Невозможно скомпилировать пример кода FSM

Есть хороший учебник по конечным автоматам под названием UML Tutorial: Finite State Machines от Robert C. Martin. Но я не могу скомпилировать пример кода, который он предоставляет. Я получил *FsmTest.cpp(46): ошибка C2664: "SetState": невозможно преобразовать параметр 1 из "класса UnlockedState *" в "класс TurnstileState "

Пожалуйста помоги. Благодарю.

class Turnstile
{
public:
    virtual void Lock();
    virtual void Unlock();
    virtual void Thankyou();
    virtual void Alarm();
};

class TurnstileFSM;
class LockedState;
class UnlockedState;

class TurnstileState
{
public:
    virtual void Coin(TurnstileFSM*) = 0;
    virtual void Pass(TurnstileFSM*) = 0;
protected:
    static LockedState lockedState;
    static UnlockedState unlockedState;
};

class TurnstileFSM : public Turnstile
{
public:
    void SetState(TurnstileState* s) {itsState = s;}
    void Coin() {itsState->Coin(this);}
    void Pass() {itsState->Pass(this);}


private:
    TurnstileState *itsState;
};

class LockedState : public TurnstileState
{
public:
    virtual void Coin(TurnstileFSM* t)
    {
        t->SetState(&unlockedState);
        t->Unlock();
    }
    virtual void Pass(TurnstileFSM* t)
    {
        t->Alarm();
    }
};

class UnlockedState : public TurnstileState
{
public:
    virtual void Coin(TurnstileFSM* t)
    {
        t->Thankyou();
    }
    virtual void Pass(TurnstileFSM* t)
    {
        t->SetState(&lockedState);
        t->Lock();
    }
};

LockedState TurnstileState::lockedState;
UnlockedState TurnstileState::unlockedState;

3 ответа

Проблема в том, что при попытке позвонить SetState() Внутри LockedState::Coin(), класс UnlockedState является неполным типом: он был объявлен, но не определен. Чтобы это исправить, вам нужно переместить определение Coin() после этого из UnlockedState:

class LockedState : public TurnstileState
{
public:
    virtual void Coin(TurnstileFSM* t);
    ...
};

class UnlockedState : public TurnstileState
{
    ...
};

void LockedState::Coin(TurnstileFSM* t)
{
    ...
}

Скорее всего, это потому, что он еще не знает, что UnlockedState является подклассом TurnstileState. Удалите функцию изнутри класса до конца файла:

class TurnstileFSM {
    void SetState(TurnstileState* s);
};

void TurnstileFSM::SetState(TurnstileState* s) {itsState = s;}

В этом примере сгенерированный код должен включать tscontext.h, а класс TurnStyle является производным от контекста, который должен быть объявлен в *tscontext.h"как класс TurnStyleContext.

В моем случае сгенерированный код выглядит так:

    #include "tscontext.h"   // the header file name for the context class"

    // Forward Declarations

    class TurnStyle;

    //----------------------------------------------
    // TurnStyleState: The base state class
    //----------------------------------------------
    class TurnStyleState
    {
      public: 
        virtual const char* StateName() const = 0;
        virtual void Coin( TurnStyle& );
        virtual void Pass( TurnStyle& );
    };

    //----------------------------------------------
    // State: Unlocked
    //----------------------------------------------
    class TurnStyleUnlockedState : public TurnStyleState
    {
      public: 
        virtual const char* StateName() const
            { return "Unlocked"; }
        virtual void Pass( TurnStyle& );
        virtual void Coin( TurnStyle& );
    };
    //----------------------------------------------
    // State: Locked
    //----------------------------------------------
    class TurnStyleLockedState : public TurnStyleState
    {
      public: 
        virtual const char* StateName() const
            { return "Locked"; }
        virtual void Coin( TurnStyle& );
        virtual void Pass( TurnStyle& );
    };
    //----------------------------------------------
    // TurnStyle: The Finite State Machine class
    //----------------------------------------------
    class TurnStyle: public TurnStyleContext
    {
      public: 
        // Static State variables
        static TurnStyleUnlockedState Unlocked;
        static TurnStyleLockedState Locked;

        TurnStyle(); // default Constructor

        // Event functions
        virtual void Coin() { itsState->Coin( *this ); }
        virtual void Pass() { itsState->Pass( *this ); }

        // State Accessor functions
        void SetState( TurnStyleState& theState ) { itsState = &theState; }
        TurnStyleState& GetState() const { return *itsState; }

        const char* GetCurrentStateName() const { return itsState->StateName(); }
        const char* GetVersion() const;

      private: 
        TurnStyleState* itsState;
    };

с конечным автоматом, определенным следующим образом:

Context TurnStyleContext     // the name of the context class
FSMName TurnStyle            // the name of the FSM to create
Initial Locked               // the name of the initial state
                             // for C++ output
pragma Header  tscontext.h"   // the header file name for the context class, note the necessary "
{
    Locked
    {
        Coin     Unlocked    Unlock
        Pass     Locked      Alarm
    }
    Unlocked <BeforeUnlocked >AfterUnlocked
    {
        Coin    Unlocked    Thankyou
        Pass    Locked      Lock
    }
}

Контекст реализует FSMError, Thankyou, Lock, Alarm, Unlock, BeforeUnlocked, AfterUnlocked

Другие вопросы по тегам