So I have a problem when using a singleton Game class and the Story class.
Game.hpp
#ifndef GAME_HPP
#define GAME_HPP
#include <memory>
class Phase; // Forward declaration
class Game
{
private:
static inline Game* instance_reference_{nullptr};
std::unique_ptr<Phase> current_phase_;
bool is_running_{true};
explicit Game() {};
public:
virtual ~Game();
const static Game* getInstance();
and of course the getInstance()
method is defined in a .cpp file.
Story.hpp
#ifndef PHASE_HPP
#define PHASE_HPP
class Game; // Forward declaration
class Phase
{
protected:
const Game* game_;
public:
explicit Phase() : game_{ Game::getInstance() } {};
virtual ~Phase() = default;
virtual void handlePhase() = 0;
};
#endif
And some other classes inherit from the Phase class. Also, currently there is no Phase.cpp
file.
Right now I cannot compile because the Game::getInstance()
is nowhere declared.
but when I swap to #include "Game.hpp"
instead of the forward declaration, when I compile I get this error:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../include/c++/13.2.1/bits/unique_ptr.h:97:16: error: invalid application of 'sizeof' to an incomplete type 'Phase'
97 | static_assert(sizeof(_Tp)>0,
| ^~~~~~~~~~~
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/13.2.1/../../../../include/c++/13.2.1/bits/unique_ptr.h:404:4: note: in instantiation of member function 'std::default_delete<Phase>::operator()' requested here
404 | get_deleter()(std::move(__ptr));
| ^
./Game.hpp:36:14: note: in instantiation of member function 'std::unique_ptr<Phase>::~unique_ptr' requested here
36 | explicit Game() {};
| ^
./Game.hpp:13:7: note: forward declaration of 'Phase'
13 | class Phase; // Forward declaration
| ^
So all in all, when I implement it how it is usually done, I have problems calling Game::getInstance()
in the Phase
constructor, but when I try to resolve this, it still won't compile.
If you forward declare a class:
class Game; // Forward declaration
You can only use it in ways that don't require you to know anything about it. So in header files this basically means you can only declare pointers to it.
That means this is not going to work:
class Phase
{
protected:
const Game* game_;
public:
/// This will fail
/// You don't know that Game has any members.
/// So you can't call functions at this point.
explicit Phase() : game_{ Game::getInstance() } {};
virtual ~Phase() = default;
virtual void handlePhase() = 0;
};
The solution is to change the header to
class Phase
{
protected:
const Game* game_;
public:
explicit Phase();
virtual ~Phase() = default;
virtual void handlePhase() = 0;
};
Then in the Phase.cpp file add:
#include "Phase.h"
#include "Game.h"
Phase::Phase() : game_{ Game::getInstance() } {};