0

I am trying to create a state machine. I have created a class called BaseState that all states inherits from. The problem I'm having is that when the sub classes change a BaseState member variable, it does not change the variable for all of the inherited classes. From what I know of programming, this is when I use static. But in my case I get a linker error (LNK2001).

So when I call ChangeState(State::MenuState); inside SplashState, it switches, but switches back since the value in BaseState has not changed.

class StateMachine
{
private:
    State                   _currentState;
    std::vector<BaseState*> _baseStates;
    void ProcessStateRequest();

public:
    StateMachine(InitVar initVar);
    ~StateMachine();

    void Update(float deltaTime);
};

That adds the states like this:

StateMachine::StateMachine(InitVar initVar)
{
    _currentState = State::SPLASHSTATE;

    for (int i = 0; i < State::EXITSTATE; i++)
    {
        switch (i)
        {
        case SPLASHSTATE:
        {
            _baseStates.push_back(new SplashState(initVar));
            break;
        }
        case MENUSTATE:
        {
            _baseStates.push_back(new MenuState(initVar));
            break;
        }
        case PLAYSTATE:
        {
            _baseStates.push_back(new PlayState(initVar));
            break;
        }
        case OPTIONSSTATE:
        {
            _baseStates.push_back(new OptionsState(initVar));
            break;
        }
        }
    }
}

With changing states like this:

void StateMachine::ProcessStateRequest()
{
    //if currentState does not match with the new requested state.
    if (_currentState != _baseStates[_currentState]->GetNewStateRequest())
    {
        _baseStates[_currentState]->OnStateExit();
        _currentState = _baseStates[_currentState]->GetNewStateRequest();
        _baseStates[_currentState]->OnStateEnter();
    }
}

Inside basestate.h:

enum State
{
    SPLASHSTATE,
    MENUSTATE,
    PLAYSTATE,
    OPTIONSSTATE,
    EXITSTATE,
};

class BaseState
{
private:
    State               _newStateRequest; //Cannot edit this from subclasses. Adding static causes linker error.
protected:
    ObjectHandler*      _objectHandler;
    UIHandler*          _uiHandler;

    void ChangeState(State newState);
public:
    BaseState(InitVar initVar);
    ~BaseState();

    virtual void Update(float deltaTime) = 0;
    virtual void OnStateEnter() = 0;
    virtual void OnStateExit() = 0;

    State GetNewStateRequest()const;
};

The last part of basestate.cpp:

BaseState::BaseState(InitVar initVar)
{
    _objectHandler      = initVar.objectHandler;
    _uiHandler          = initVar.uiHandler;
    _newStateRequest    = SPLASHSTATE;
}

BaseState::~BaseState()
{}

void BaseState::ChangeState(State newState)
{
    _newStateRequest = newState;
}

State BaseState::GetNewStateRequest() const
{
    return _newStateRequest;
}
Alex
  • 365
  • 4
  • 17
  • 2
    Are you sure you defined your static variable in `basestate.cpp` like `State BaseState::_newStateRequest;`? – MikeCAT Dec 07 '15 at 14:25
  • Are you asking about how to define the static variable work, or about the `ChangeState` problem? One question per question please. Oh, and if it's about the first (which your title is about) then [it's a duplicate of this](http://stackoverflow.com/questions/272900/vectorpush-back-odr-uses-the-value-causing-undefined-reference-to-static-clas). – Some programmer dude Dec 07 '15 at 14:29
  • MikeCat, that resolved the issue. I had no idea that I had to do that. – Alex Dec 07 '15 at 14:32
  • 2
    Avoid static variables. Why do you think you need one? Are you absolutely positively sure you only need one thread-unsafe state machine in your entire program? If you need one new state request per stae machine, make `_newStateRequest` a member of `StateMachine`, not of `BaseState`. A static variable is not a solution, it's a cop out. – n. m. could be an AI Dec 07 '15 at 14:35

1 Answers1

0

MikeCAT in comments gave this answer. Problem solved by doing this;

class BaseState
{
private:
    static State BaseState::_newStateRequest;
    //State             _newStateRequest;

and

#include "BaseState.h"

State BaseState::_newStateRequest;

BaseState::BaseState(InitVar initVar)
Alex
  • 365
  • 4
  • 17