0

I have three classes, 2 of which rely on the functionality of each other, and one which contains pointers to and is included in both:

Player:

 #pragma once
#include <SFML\Graphics.hpp>
#include "RenderableObject.h"
//#include "Renderer.h"

class Renderer;
class Player : public RenderableObject
{
public:
    Player(int size, Renderer* renderer);
    ~Player();

    void render();
    void setX(int x);
    void setY(int y);

    int getX();
    int getY();

    void setVelX(float x);
    void setVelY(float y);

    float getVelx();
    float getVely();

    int getSize();

    private:
    int size;
    int x;
    int y;

    float velx;
    float vely;

    Renderer* ren;

};

GameManager:

#pragma once
#include "Player.h"


class Renderer;
class GameManager
{
public:
    GameManager(Renderer* r);
    ~GameManager();

    Player* getBall();

private:
    Player* ball;

};

Renderer:

#pragma once
#include <SFML\Graphics.hpp>
#include "GameManager.h"
#include "Player.h"

class Renderer
{
public:
    Renderer(GameManager* game);
    ~Renderer();
    sf::RenderWindow* getWindow();
    void draw();
    void renderCircle(int size, int x, int y);
    void renderSquare(int size, int x, int y);

private:
    sf::RenderWindow* win;
    GameManager* game;
    Player* ball;
};

I suspect there is some sort of circular dependency going on here. I managed to reduce the 60 odd errors down to 3, by adding "class Renderer;" to the Player header file. However, I'm now receiving "Use of undefined type" errors.

It might help to give a higher level view of what I want to achieve:

The GameManager object should hold an instance (maybe more) of player. This GameManager object is shared between subsystems such as Renderer so they all have access to the same resources.

The Renderer object should be able to call the Player object's (retrieved from the GameManager object) render() function, which in turn should call back to the Renderer object's renderCircle() object.

I'm hoping this is a simple case of re-arranging the includes, without having to re-design what I've already done.

19172281
  • 237
  • 2
  • 10
  • In the source files you do include all the header files? – Some programmer dude Apr 23 '18 at 19:35
  • 1
    Lot of pointers here. Odds are good you can replace many of the headers with forward declarations similar to what you did with `class Render`. Handy reading: [Resolve build errors due to circular dependency amongst classes](https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes) – user4581301 Apr 23 '18 at 19:37
  • @Someprogrammerdude, I only include the respective header file - not header files to the other classes. – 19172281 Apr 23 '18 at 19:41
  • 1
    You need to include all header files of all classes you use in the source files. Otherwise the compiler doesn't know anything more than the class might exists *somewhere*, and that's not enough if you want to create object of that class or call member function in it. – Some programmer dude Apr 23 '18 at 19:45
  • @user4581301, but wouldn't we still end up with the "Use of undefined type" errors? – 19172281 Apr 23 '18 at 19:47
  • @Someprogrammerdude, do I also need to include them in the respective header files? – 19172281 Apr 23 '18 at 19:48
  • Unless you actually *use* objects of the class (like calling member functions etc., which you don't) then forward declarations are okay. – Some programmer dude Apr 23 '18 at 19:52
  • Not if you include all of the header files you need in the cpp files that implement those classes. – user4581301 Apr 23 '18 at 19:52
  • @Someprogrammerdude, I tried including the header files in the source files, and ended up with 133 errors... – 19172281 Apr 23 '18 at 19:53
  • @Someprogrammerdude, I call a Renderer method in the Player class. – 19172281 Apr 23 '18 at 19:54
  • Is there somewhere I can upload the full project? Might be more useful. – 19172281 Apr 23 '18 at 20:28

1 Answers1

2

In a header file, where you only declare variables that are pointers or references, all the compiler needs to know is that a class exists, nothing more. It doesn't need to know how big it it, or what members the class have. Therefore it's enough with a forward declaration.

However, in the source files where the variable is used, objects are created, and member functions are called, then the compiler need the full definition which means you have to include your whole header file.


Taking your code, simplified:

Player.h

#pragma once

class Renderer;

class Player
{
public:
    Player(Renderer*);

private:
    Renderer* ren;
};

GameManager.h

#pragma once

class Renderer;

class GameManager
{
public:
    GameManager(Renderer*);

private:
    Renderer* ren;
};

Renderer.h:

#pragma once

class Player;
class GameManager;

class Renderer
{
public:
    Renderer(GameManager*);

private:
    GameManager* game;
    Player* ball;
};

The above header files are about the same that you already have, with the exception that I used forward declarations in Renderer.h instead.

Now the Renderer.cpp source file, where the Player and GameManager objects are actually created and used, we need the full definition from the header files:

#include "Renderer.h"
#include "Player.h"
#include "GameManager.h"

Renderer::Renderer(GameManager* game)
    : game(game), ball(new Player)
{
}

// Other functions that calls member function in the `man` and `ball` objects

Of course, you need to #include "Renderer.h" in the Player.cpp and GameManager.cpp source files.

If you have other errors, they are because of other things you done, not because of the circular dependencies, as those have been solved with the forward declarations.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I've read that circular dependencies are bad. However, to me it makes sense to have the renderer call the player's overridden "render" function (inherited from a RenderObject header file). What do you think? – 19172281 Apr 23 '18 at 21:02
  • @B4039 That's unrelated to circular dependencies, and from my point of view it seems like a good idea. Having a "renderer" class which holds all "renderable" objects, and then calls those objects "render" function for the actual rendering is quite common I think. – Some programmer dude Apr 23 '18 at 21:06
  • Right, but this particular design pattern leads to a circular dependency? – 19172281 Apr 23 '18 at 21:08
  • @B4039 What I said in my previous comment is somewhat misleading, maybe even a little *wrong*... A "good" (or perhaps only adequate) design would have a manager class which holds a "renderer" and all "renderable" objects. Then in the game loop the manager calls the "renderable" objects passing the "renderer" as an argument. Then the "renderable" object doesn't really need to keep an instance of either the manager *or* the renderer, and the renderer doesn't need to know anything about the renderable objects or the game manager. No circular dependency. – Some programmer dude Apr 23 '18 at 21:14
  • @B4039 However this is turning into a discussion about good design practices which is off topic for your question, which I hopefully solved. If you want tips and tricks for good design practices or patterns, then there are quite a few books and sites you could read. – Some programmer dude Apr 23 '18 at 21:15
  • I should point out that GameManager, and the Player object are created in a Startup class, not in the Renderer. Is this going to make a difference to what you wrote in your answer? – 19172281 Apr 23 '18 at 21:38