Sign in to follow this  
PragmaOnce

Always running into a circular dependency

Recommended Posts

PragmaOnce    755

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;
};
Edited by PragmaOnce

Share this post


Link to post
Share on other sites
Dante12129    2038

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).

Share this post


Link to post
Share on other sites
PragmaOnce    755

 

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

Edited by PragmaOnce

Share this post


Link to post
Share on other sites
Samith    2460

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.

Edited by Samith

Share this post


Link to post
Share on other sites
Dragonsoulj    3212


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.

Share this post


Link to post
Share on other sites
PragmaOnce    755

 


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 :)

Share this post


Link to post
Share on other sites
Dragonsoulj    3212


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?

Share this post


Link to post
Share on other sites
PragmaOnce    755

Because currently the Explode function does not exist :/ I have a tendency to go into a "What if.. " mindset when programming. I could even make an EXPLOSION_EVENT with those parameters and make the scene register to it. That way the scene will handle the explosion and my entities are oblivious to the world they are in.

 

Basically, i'm just scared that at some or other point my Entities are going to need something and my scene class is "global" enough to be able to respond to anything the Entities might want. But... now that I really think about it, events will be able to keep things together. If not, then I guess i'll have to do some refactoring.

 

It's really hard for me to plan things out because I am afraid of having to refactor. I know code is not supposed to be completely set in stone but I can't stop myself from being over cautious to eliminate the chances of redoing something. 

Share this post


Link to post
Share on other sites
Waterlimon    4398

In this particular case, the objects storing a pointer to the scene is redundant and a waste of memory. The scene is implicit in the objects being within the scene. Thus you should pass the scene to the methods of the objects that require the scene.

 

A potential downside with explicitly passing the scene to the methods is, well, that its explicit. When you store it in the object, the object "implicitly" knows which scene you are talking about, since you set it when creating the object. When you pass the scene as a parameter, the scene is still implicit, except that C++ does not have the capability to implicitly pass the scene, and thus it must be done manually for each and every method call. This might be enough to just keep it as a member variable, since your game code will be less cluttered with fairly redundant information.

Share this post


Link to post
Share on other sites
Satharis    2444

General rules of thumb I use are:

  • If it's a pointer or a reference, forward declare it.
  • If its something complex like a bunch of typedefs(as Microsoft is famous for) just give up and include the file.
  • If the class/struct is a member, include the file.

That fixes most issues.

 

In your case I would question why both the scene and the object list need to know about entities as well as the former including the later of the two. Of course if your object can exist without a scene then you probably should have the scene as a pointer, which you do. So declare class Scene;

 

Treat header files as vague, treat cpp files as where you include the meat of how to work with objects.

Edited by Satharis

Share this post


Link to post
Share on other sites
boogyman19946    1487

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

 

 

 

You shouldn't be inheriting from any classes that don't include a virtual destructor. If you cast the derived object into its base class and call the object's destructor, chances are good that the derived destructor will not be called. That is at least what I learned from Effective C++ :D

Share this post


Link to post
Share on other sites
RobTheBloke    2553

 

Look up guard statements.

 

 

His user name is pragma once - I reckon he's aware of how to use them ;)  #defined sentry nonsense is only useful if you're targeting an ancient compiler, or because you are doing something a bit freaky with redefined macros (which would probably be better served in template form)

 

It's really hard for me to plan things out because I am afraid of having to refactor. I know code is not supposed to be completely set in stone but I can't stop myself from being over cautious to eliminate the chances of redoing something.

 

The spend less time thinking about the code, and make it easy enough to throw away! :)

You will inevitably be refactoring at some point - it's the nature of the game really. Being aware of potential problems in the future is a good thing (makes you aware of areas to not invest too heavily in, since you'll probably need to rework at a later date), but coding for every possible eventually is not (a.k.a. second system syndrome). 

Share this post


Link to post
Share on other sites
SeanMiddleditch    17565

 

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

 

It's quite the opposite.  You should use them everywhere you possibly can instead of including headers in headers.  This will greatly assist your compilation/iteration times with normal build systems, especially if you also avoid the STL as much as possible.  If you habitually use forward declarations and avoid header includes in other headers unless you are forced to you'll find you tend to design better classes, too.

Share this post


Link to post
Share on other sites
DejaimeNeto    4221

If you want to avoid this circular dependency, you can declare that "scene *gameworld" as "void *miscdata". It'd add up reusability and free you from this circular dependency, under the cost of increased complexity. But you really should rethink your architecture; as a teacher once told me, if programmers can't understand your architecture, it's a bad one. Given that more people asked the same question i would, I am not the only one!

Share this post


Link to post
Share on other sites

Don't do that! If you delete it through a void* without a cast no destructor will be called! EDIT: plus you need to cast it everywhere you use it unless you are just taking the address sad.png EDIT2: And you could cast it to anything you want really with a C-style cast and the compiler will assume you know what you are doing!

 

Forward declare scene instead.

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this