William Barnes William Barnes - 3 months ago 39
C++ Question

state pattern C++

I'm trying to instigate a simple State pattern, after following some of the excellent tutorials here: http://gameprogrammingpatterns.com/state.html

I am half way through this current tutorial, and I am trying to replicate the static instances of each state, by containing them within the base class. However, when it comes to switching states, g++ is throwing this error.

state_test.cpp: In member function ‘virtual void Introduction::handleinput(Game&, int)’:
state_test.cpp:55:16: error: cannot convert ‘Playing*’ to ‘GameState*’ in assignment
game.state_ = &GameState::play;
^


Now, I understand the error involves the conversion of the pointer, but I am really struggling to see how to fix it. As I was following this guys code, I kind of expected it to work, but because he is changing it as he goes along and trying to reinforce best practice, I don't have his complete source code to follow. However, I feel it is important for me to understand the code at this stage, before I move through the rest of the tutorial.

Following is the code I created, attempting to replicate his state system:

#include <iostream>

class Game;
class Introduction;
class Playing;

class GameState
{
public:

static Introduction intro;
static Playing play;

virtual ~GameState() {std::cout << "an undefined GameState has been destroyed" << std::endl;}
virtual void handleinput(Game& game, int arbitary) {}
virtual void update(Game& game) {}

};

class Game
{
public:

Game()
{}
~Game()
{}

virtual void handleinput(int arbitary)
{
state_->handleinput(*this, arbitary);
}

virtual void update()
{
state_->update(*this);
}

//private:
GameState* state_;
};

class Introduction : public GameState
{
public:

Introduction()
{
std::cout << "constructed Introduction state" << std::endl;
}

virtual void handleinput(Game& game, int arbitary)
{
if (arbitary == 1)
game.state_ = &GameState::play;
}

virtual void update(Game& game) {}
};

class Playing : public GameState
{
public:
Playing() {std::cout << "constructed Playing state" << std::endl;}

virtual void handleinput(Game& game, int arbitary)
{
if (arbitary == 0)
game.state_ = &GameState::intro;
}

virtual void update(Game& game) {}
};

int main(int argc, char const *argv[])
{
Game thisgame;

return 0;
}


Any ideas why my implementation isn't compiling?

Answer

The problem is that the compiler reads the file from top to bottom. At the line that contains

game.state_ = &GameState::play;

he still doesn't know that Playing inherits from GameState. It only knows that Playing is a class that will be declared later.

You should split the class declarations from method implementations. Have all class declarations first and method implementations later. In bigger project you would split them all to individual *.h and *.cpp files and this ordering would happen naturally.

Shortened example:

class Playing : public GameState
{
public:
    Playing();

    virtual void handleinput(Game& game, int arbitary);

    virtual void update(Game& game);
};

// Declarations of other classes...


Playing::Playing() {
    std::cout << "constructed Playing state" << std::endl;
}

void Playing::handleinput(Game& game, int arbitrary) {
    if (arbitary == 0)
        game.state_ = &GameState::intro;
    }
}

void Playing::update(Game& game) {
}

You can leave some of the method inside the class declaration. Usually it's done if the method is small, would benefit from inlining and doesn't have this kind of circular dependency problem.