2016-08-29 6 views
7

Я пытаюсь спровоцировать простой шаблон State, после выполнения некоторых из прекрасных учебников здесь: http://gameprogrammingpatterns.com/state.htmlсостояния шаблон C++

Я на полпути через этот текущий учебник, и я пытаюсь повторить статические экземпляры каждое состояние, содержащее их в базовом классе. Однако, когда дело доходит до состояний переключения, g ++ выбрасывает эту ошибку.

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; 
       ^

Теперь я понимаю, что ошибка включает преобразование указателя, но я действительно изо всех сил, чтобы увидеть, как это исправить. Поскольку я следовал этому парному коду, я как бы ожидал, что он сработает, но поскольку он меняет его, когда он продвигается вперед и пытается укрепить лучшую практику, у меня нет его полного исходного кода. Тем не менее, я считаю, что для меня важно понять код на этом этапе, прежде чем я перехожу к остальной части учебника.

Ниже приведен код, который я создал, пытаясь повторить свою государственную систему:

#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; 
} 

Любые идеи, почему моя реализация не компиляцией?

EDIT:

Таким образом, в ответ на ранее обучающимся, за что я был очень благодарен, я пересмотрел код. Начну с того, что все это было в отдельных файлах, но это было больше проблем, чем для такого небольшого количества тестового кода. Я просто переписал один заголовочный файл, который объявил классы, а затем определил их в файле .cpp.

Вот .h файл:

class Introduction; 
class Playing; 
class Game; 
class GameState; 

class GameState 
{ 
    public: 

    static Introduction intro; 
    static Playing play; 

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

}; 


class Introduction : public GameState 
{ 
public: 

    Introduction(); 

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

    virtual void update(Game& game); 

}; 

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

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

    virtual void update(Game& game);  
}; 


class Game 
{ 
public: 

    Game(); 

    ~Game(); 

    virtual void handleinput(int arbitary); 

    virtual void update(); 

    GameState* state_; 

}; 

А вот файл .cpp:

#include <iostream> 
#include "state.h" 


GameState::~GameState() 
    {std::cout << "Exiting Game State Instance" << std::endl;} 
void GameState::handleinput(Game& game, int arbitary) 
    {} 
void GameState::update(Game& game) 
    {} 



Game::Game() 
    {} 
Game::~Game() 
    {} 
void Game::handleinput(int arbitary) 
     { 
      state_->handleinput(*this, arbitary); 
     } 

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


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

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

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


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

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

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



int main(int argc, char const *argv[]) 
{ 
    Game mygame; 
    return 0; 
} 

И я до сих пор не могу заставить его работать. Предыдущая ошибка исчезла, но я изо всех сил пытаюсь получить доступ к статическим экземплярам «введения» и играть внутри базового класса. Произошла ошибка:

/tmp/ccH87ioX.o: In function `Introduction::handleinput(Game&, int)': 
state_test.cpp:(.text+0x1a9): undefined reference to `GameState::play' 
/tmp/ccH87ioX.o: In function `Playing::handleinput(Game&, int)': 
state_test.cpp:(.text+0x23f): undefined reference to `GameState::intro' 
collect2: error: ld returned 1 exit status 

Я думал, что у меня это было! Так расстроено!

Я должен добавить, что ответ, предоставленный RustyX, компилируется, однако мне нужно переместить экземпляры «воспроизведения» и «введения» вне определения класса, и тогда я не могу ставить их статически, I что это важно, потому что мне нужен только один экземпляр каждого, и я хотел бы, чтобы они были инициализированы как можно раньше.

+0

Возможно, вас заинтересует структура [STTCL] (https://github.com/makulik/sttcl). –

ответ

6

Проблема в том, что компилятор читает файл сверху вниз. В строке, которая содержит

game.state_ = &GameState::play; 

он еще не знает, что Playing наследует от GameState. Он знает только, что Playing - это класс, который будет объявлен позже.

Вы должны разделить объявления классов от реализации метода. Сначала укажите все объявления классов и методы реализации. В более крупном проекте вы разделили бы их на отдельные файлы * .h и * .cpp, и это упорядочение произойдет естественным образом.

Укороченный пример:

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) { 
} 

Вы можете оставить некоторые из метода внутри объявления класса. Обычно это делается, если метод мал, он бы выиграл от вложения и не имеет такой проблемы с круговой зависимостью.

+0

Хорошо, это похоже на мой вопрос уверенно! Благодаря! –

3

Переместить реализации функций вне линии на после определения всех классов.

Компилятор должен видеть унаследованные классы Playing и Introduction полностью, прежде чем он узнает, что они наследуют от GameState.

#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); 

    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); 

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

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

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

Introduction GameState::intro; 
Playing GameState::play; 


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

    return 0; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^