c++inheritancemember-variables

C++ state machine, inherited class with member values with incorrect syntax


I don't know if my question title makes sense, so apologies in advance for that. so... I'm trying to implement a state machine for a little game I'm trying to make using C++ and SFML.

I have a GameLoopObject abstract class which needs a renderwindow argument and has these virtual methods: update, draw, handleinput and reset.

Then I have a GameState abstract class which inherits from GameLoopObject, but doesnt add anything new yet so its basically the same as GameLoopObject, for now.

Last, I have a GameStateManager class which also inherits from GameLoopObject and should handle my gamestates.

Now my problem is that I want to use a GameState currentState and a nextState member variable in my GameStateManager, but I can't seem to find the correct way/syntax to declare these and use them afterwards. I'd prefer leaving them empty (if that's possible in C++), as GameState objects are being stored inside of them immediately after making a GameStateManager object.

Basically, what I'm trying to do is something along the lines of this:

GameStateManager(sf::RenderWindow & w) : 
    GameLoopObject(w), 
    currentState(new GameState(w)), 
    nextState(new GameState(w));

Which gives me a "no default constructor exists for class "GameLoopObject" "

This is the rest of my code:

/*
 * GameStateManager.hpp
 */

#ifndef GameStateManager_HPP
#define GameStateManager_HPP

#include "stdafx.h"
#include "GameLoopObject.hpp"
#include "GameState.hpp"
#include<string>
#include<map>

class GameStateManager : GameLoopObject {
private:
    GameState currentState;
    GameState nextState;
public:
    std::map<std::string, GameState> gameStates{}; // list where all known gamestates are stored.

    // methods
    GameStateManager(sf::RenderWindow & w);

    void AddGameState(std::string name, GameState * state);
    void SetNext(std::string name);
    void SwitchState();
    void HandleInput(); 
    void Update();
    void Draw();
    void Reset();
};

#endif //GameStateManager_HPP



/*
 * GameStateManager.cpp
 */
#include "stdafx.h"
#include "GameStateManager.hpp"

GameStateManager::GameStateManager(sf::RenderWindow & w)
// : GameLoopObject(w)
{
    GameState currentState(w);
    GameState nextState(w);
}

void GameStateManager::AddGameState(std::string name, GameState * state)
{
    gameStates.insert(std::make_pair(name, * state));
}

void GameStateManager::SetNext(std::string name)
{
    //check if user wants to exit (close window with X)
    if (gameStates.count(name))
    {
        nextState = gameStates[name];
    }
}

void GameStateManager::SwitchState()
{
    if (currentState != nextState)
    {
        currentState = nextState;
    }

}

void GameStateManager::HandleInput()
{
    // if(currentState != null)
    currentState.HandleInput();
}

void GameStateManager::Update()
{
    // if(currentState != null)
    currentState.Update();
}

void GameStateManager::Draw()
{
    // if(currentState != null)
    currentState.Draw();
}

void GameStateManager::Reset()
{
    // if(currentState != null)
    currentState.Reset();
}

Solution

  • I see you have two issues here, both stemming from the fact that you can't declare an instance of an abstract class. The members of the class should be GameState pointers. You also face the same issue when you call new GameState, there is no constructor available here as GameState is abstract.

    I'm not sure whether your GameStateManager is the owner of the current and next state. In the case that it is, you should change the type of your members to std::unique_ptr<GameState>, otherwise just use a GameState*.

    Your constructor doesn't need to create a new GameState object to initialise these members if they don't own the states, in this case you would pass a pointer to an existing GameState. However if they do, you must call new ConcreteGameState where ConcreteGameState is some derived class of GameState that is not abstract.

    EDIT: Looking at your member functions, you almost definitely want to a raw pointer.

    EDIT 2: Noticed you are currently privately inheriting from GameLoopObject, you should change that to public by adding the keyword:

    class GameStateManager: public GameLoopObject