Always running into a circular dependency

Started by
18 comments, last by Paradigm Shifter 10 years, 4 months ago

Hi guys.

So whenever I try to make a game I run into a problem where a circular dependency occurs between the scene or level holding my game objects and the game objects that need access to the level. I am sure this can be easily solved because my architecture is structured wrong but I just can't seem to think of an efficient solution. I'll roughly show what I have (just the parts that are causing the dependency).

Scene.h


#include "ObjectList.h"
 
class Scene : public EventListener
{
public:
ObjectList objectList; // This holds all the entities that are currently active in a particular scene/level.
};

ObjectList.h


#include "Entity"
 
class ObjectList
{
private:
std::vector<Entity*> objectList;
};

Entity.h


#include "Scene.h"
 
class Entity : public sf::Sprite, public EventListener
{
protected:
Scene *gameWorld;
};
Advertisement
Since Entity only has a pointer reference to Scene, you can forward declare Scene. That way you won't have to include scene.h and you'll avoid the circular dependency problem. A forward declaration looks like this:

class Scene;

This lets the compiler know that the type Scene exists, but doesn't tell it anything else. Scene can be declared elsewhere without issue.

Forward declaration is fairly common. Sometimes you just need two types to know about each other!

Why does an Entity has to know about the Scene?

Look up guard statements.

At the start of your header:

#ifndef ENTITY_H
#define ENTITY_H

And at the end of the header:

#endif

Why does the entity need to know about the scene?

Also, you shouldn't be inheriting from sf::Sprite. Make it a member and, if you want to use your class like the sprite, inherit from sf::Drawable and sf::Transformable. You'll need to override the draw method, and there are a few things that the Sprite has that aren't in either of those (color, bounds, and texture/texture rects).

Look up guard statements.

At the start of your header:


#ifndef ENTITY_H
#define ENTITY_H

And at the end of the header:


#endif

I use #pragma once.

I didn't include it with my examples because it has nothing to do with the problem at hand. Those classes are actually filled with members and methods but I thought I would leave out any code that has nothing to do with the circular dependency, to make the problem easier for others to understand.

Why does an Entity has to know about the Scene?

Because the Scene is going to hold the list of entities found in a particular level. I was thinking I might need it later to implement some logic, for example:


// Inside explosion_object, this is purely psuedo
Explode()
{
    scene.ObjectList.findObjectsInSphere(DamageRadius,variableToStoreObjects)
}


Also, you shouldn't be inheriting from sf::Sprite

Why is that, please elaborate?

Thanks for the tip on forward declarations. I have read about them but I always thought it was bad practice to do it, but if you say it's fairly common I guess it's a solution smile.png


That's why I use
#pragma once

One small thing about #pragma once is that it's technically not part of the standard, and though it's widely supported (I don't think I've ever seen a compiler that doesn't support it) people will often use include guards after the #pragma once, just in case #pragma once isn't supported.


I use #pragma once.

I didn't include it with my examples because it has nothing to do with the problem at hand. Those classes are actually filled with members and methods but I thought I would leave out any code that has nothing to do with the circular dependency, to make the problem easier for others to understand.

Since the topic appeared to be circular dependency, making a note about using guards or #pragma once would have contributed to the understanding, as that tends to be one portion of usual circular dependency issues.


That's why I use
#pragma once

One small thing about #pragma once is that it's technically not part of the standard, and though it's widely supported (I don't think I've ever seen a compiler that doesn't support it) people will often use include guards after the #pragma once, just in case #pragma once isn't supported.

Yes, I know it's only a directive for compilers. Since I am a mere novice, working alone, on a project that no one else will see... I figured that if my compiler supports it, it reduces the chance of bugs, and does not involve as much typing :p


I use #pragma once.

I didn't include it with my examples because it has nothing to do with the problem at hand. Those classes are actually filled with members and methods but I thought I would leave out any code that has nothing to do with the circular dependency, to make the problem easier for others to understand.

Since the topic appeared to be circular dependency, making a note about using guards or #pragma once would have contributed to the understanding, as that tends to be one portion of usual circular dependency issues.

Ah I see, forgive my lack of experience. I didn't realize that it could cause dependency issues. Thank you :)


Dragonsoulj, on 29 Nov 2013 - 2:15 PM, said:



PragmaOnce, on 29 Nov 2013 - 2:00 PM, said:


I use #pragma once.

I didn't include it with my examples because it has nothing to do with the problem at hand. Those classes are actually filled with members and methods but I thought I would leave out any code that has nothing to do with the circular dependency, to make the problem easier for others to understand.



Since the topic appeared to be circular dependency, making a note about using guards or #pragma once would have contributed to the understanding, as that tends to be one portion of usual circular dependency issues.





Ah I see, forgive my lack of experience. I didn't realize that it could cause dependency issues. Thank you smile.png

Not always the case, but one potential issue. I ran into this a few times myself.

Just a potential thought to this issue, why not just pass the Scene to your Explode function and see if that removes the issue?

This topic is closed to new replies.

Advertisement