0

Context: I want to utilise state objects within my program to determine how the program functions during a state. I have an abstract class State that each state derives from (to keep things simple lets say we have MenuState and AboutState), The current state is stored as type State.

I want to be able to create a new instance of AboutState from within MenuState and vice versa so that I can control which program state I am currently in and change state easily (This would return a State object since that is what my current states type is)

The problem I am getting is obviously that if I first create AboutState, MenuState does not exist yet (to the compiler) and crashes on compile. I thought to fix this by forward declaring MenuState but I cannot cast MenuState in the function because I have only forward declared it rather than creating a full class.

Essentially How do I forward declare / fix this circular reference issue, so that I can create each of the objects from the other?

I primarily use Java so excuse the obvious errors below but you get the point, I can't cast temp -> IWorldState even if I forward declare. (I think)

class AboutState : public IWorldState
{
public:
    AboutState() {};
    virtual IWorldState* handleInput(std::string input) {
        MainMenuState temp;
                *IWorldState state = (IWorldState)temp;
        return state;
        }
};

class MainMenuState : public IWorldState
{
public:
    MainMenuState() {};
    virtual IWorldState* handleInput(std::string input) {
                 AboutState temp;
                *IWorldState state = (IWorldState)temp;
        return state;
        }
};

Also don't know know if It's ok to ask in the same question, but is there a more appropriate way to do this kinda functionality with objects or is there a different type of approach to moving between the different states? I considered the idea of creating all states at the start and passing the next state as a parameter to the constructor but i feel It's unnecessary if I can get this working.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • As pe your second question: are you looking for a [state machine](https://sourcemaking.com/design_patterns/state/cpp/1)? –  Oct 02 '19 at 14:24
  • 2
    As a first note, `*IWorldState state = (IWorldState)temp;` is not valid and won't compile since the syntax is not correct. If I understood correctly, it should instead be `IWorldState * state = (IWorldState*)&temp;`. However, this code returns a pointer to a local object that is destroyed right after return, which is really bad. You need to `return new MainMenuState` – Gilles-Philippe Paillé Oct 02 '19 at 14:25
  • To answer your question, separate the definition from the declaration. Declare both classes, then define the methods. – Gilles-Philippe Paillé Oct 02 '19 at 14:26
  • @Chipster, a state machine is exactly what I want, thankyou for the link, I think it will come in helpful for reference – Alfredo Awesome Monazite Oct 02 '19 at 15:35
  • @Gilles-PhilippePaillé thankyou, didn't occur that the object would be destroyed on leaving the function, separating the declaration from the definition got me a lot further – Alfredo Awesome Monazite Oct 02 '19 at 15:38

1 Answers1

1

You have to split (forward) declaration from definition:

class IWorldState
{
public:
    virtual ~IWorldState() = default;
    virtual std::unique_ptr<IWorldState> handleInput(std::string input) = 0;
};

class AboutState : public IWorldState
{
public:
    AboutState() = default;
    std::unique_ptr<IWorldState> handleInput(std::string input) override;
};

class MainMenuState : public IWorldState
{
public:
    MainMenuState() = default
    std::unique_ptr<IWorldState> handleInput(std::string input) override
};

// in cpp, else add inline

std::unique_ptr<IWorldState> AboutState::handleInput(std::string input) {
    return std::make_unique<MainMenuState>();
}
std::unique_ptr<IWorldState> MainMenuState::handleInput(std::string input) {
    return std::make_unique<AboutState>();
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Thankyou so much, I hadn't heard of std::make_unique or std::unique_ptr before. You are a life saver tho, this response answered the question and answered like 5 follow up questions at the same time! – Alfredo Awesome Monazite Oct 02 '19 at 15:41