0

While working on a little game of mine, I ran into a circular dependency related issue.

Say I'm using 2 classes and a helper namespace(all include guarded), where Base is the main game class, Player the player object and a child of Entity, and helper a functional namespace responsible for handling tile collision:

When I try to compile the code, Player is not recognized as a type-specifier in base.h and I also get an unknown override specifier. When I forward declare Player it is undefined, although I am including player.h. I've been questing on the internet for a solution, but none of the typical solutions to circular inclusion seemed applicable. As aforementioned I have tried all sorts of combinations of forward-declarations but it only changed the type of error.

I was wondering whether anyone could notice any flaw in the code below.

(Please note that I've put all of the function implementations in the headers for demonstration purposes only, they've got their own little cpp files)

base.h

#include "player.h"
#include "level.h"
class Base{
   static Base& instance() 
   {
        static Base base;
        return base;
   }
   Player player;
   Level level;
}

entity.h

class Entity{
    vec2 velocity; //Assume we are using the glm library
    vec2 position;
    virtual void update()
    {
    }
}

player.h

#include "helper.h"
#include "entity.h"
class Player:public Entity{
    void update()
    {
        velocity=helper::tileCollision(velocity);
        //Update position and stuff
    }
}

helper.h

#include "level.h"
#include "base.h"
namespace helper{
    vec2 tileCollision(vec2 velocity)
    {   
         Level& level = Game::instance().level;
         //Pop some fancy tile collision math in here
         return vec2(0);
    }
}
tbvanderwoude
  • 587
  • 6
  • 17
  • You show only bits and pieces of code, accompanied by a description that doesn't fit (where are the forward declarations?) and leave too much to our fantasy. Create an MCVE instead. – Christian Hackl Mar 26 '17 at 11:42

1 Answers1

0

The first of all, please don't write implementations of functions in headers unless it is not inline or template.

Try the following:

base.h

#include <memory>

class Player;
class Level;

class Base {
   public:
        static Base& instance();

   private:
       Base();
       unique_ptr<Player> player;
       unique_ptr<Level> level;
}

base.cpp

#include "base.h"
#include "player.h"
#include "level.h"


Base::Base() : Player(make_unique<Player>()), Level(make_unique<Level>())
{
}


static Base& Base::instance() 
{
    static Base base;
    return base;
}

And you should watch the following : https://www.youtube.com/watch?v=QjFpKJ8Xx78

Alex
  • 9,891
  • 11
  • 53
  • 87
  • 2
    *"don't write your code in headers"* - Perhaps a better way to put it would be *"don't write implementations of functions in headers"* :) – Christian Hackl Mar 26 '17 at 11:58
  • @Alex I felt like adding cpp files to this example was unnecessary and that this was complete on it's own. But although this a valid solution, I don't understand why there is no proper way of having a regular value member of a singleton (Base::instance().player of Player type) use a helper namespace (helper) using another member of the same singleton (Base::instance().level). Would you care to explain? – tbvanderwoude Mar 27 '17 at 16:21