Jump to content

  • Log In with Google      Sign In   
  • Create Account


Always running into a circular dependency


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 PragmaOnce   Members   -  Reputation: 719

Like
0Likes
Like

Posted 29 November 2013 - 07:33 AM

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, 29 November 2013 - 07:46 AM.


Sponsor:

#2 Samith   Members   -  Reputation: 2110

Like
7Likes
Like

Posted 29 November 2013 - 08:17 AM

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!

#3 rozz666   Members   -  Reputation: 609

Like
4Likes
Like

Posted 29 November 2013 - 10:35 AM

Why does an Entity has to know about the Scene?



#4 Dragonsoulj   Crossbones+   -  Reputation: 2015

Like
0Likes
Like

Posted 29 November 2013 - 11:28 AM

Look up guard statements.

 

At the start of your header:

#ifndef ENTITY_H
#define ENTITY_H

 

And at the end of the header:

#endif


#5 Dante12129   Members   -  Reputation: 1007

Like
2Likes
Like

Posted 29 November 2013 - 12:16 PM

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



#6 PragmaOnce   Members   -  Reputation: 719

Like
0Likes
Like

Posted 29 November 2013 - 01:00 PM

 

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, 29 November 2013 - 01:09 PM.


#7 Samith   Members   -  Reputation: 2110

Like
0Likes
Like

Posted 29 November 2013 - 01:09 PM


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, 29 November 2013 - 01:09 PM.


#8 Dragonsoulj   Crossbones+   -  Reputation: 2015

Like
0Likes
Like

Posted 29 November 2013 - 01:15 PM


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.



#9 PragmaOnce   Members   -  Reputation: 719

Like
0Likes
Like

Posted 29 November 2013 - 01:20 PM

 


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



#10 Dragonsoulj   Crossbones+   -  Reputation: 2015

Like
0Likes
Like

Posted 29 November 2013 - 01:25 PM


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?



#11 PragmaOnce   Members   -  Reputation: 719

Like
0Likes
Like

Posted 29 November 2013 - 01:36 PM

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. 



#12 Waterlimon   Crossbones+   -  Reputation: 2417

Like
0Likes
Like

Posted 29 November 2013 - 02:56 PM

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.


o3o


#13 Satharis   Members   -  Reputation: 949

Like
3Likes
Like

Posted 29 November 2013 - 03:23 PM

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, 29 November 2013 - 03:23 PM.


#14 boogyman19946   Members   -  Reputation: 1036

Like
0Likes
Like

Posted 29 November 2013 - 05:15 PM


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


"If highly skilled generalists are rare, though, then highly skilled innovators are priceless." - ApochPiQ

My personal links :)
- Khan Academy - For all your math needs
- Java API Documentation - For all your Java info needs :D
- C++ Standard Library Reference - For some of your C++ needs ^.^

#15 Dante12129   Members   -  Reputation: 1007

Like
1Likes
Like

Posted 29 November 2013 - 05:26 PM

Actually, Sprite does have a virtual destructor because sf::Drawable has one. Here are some link  on the SFML about inheriting from sf::Sprite.



#16 RobTheBloke   Crossbones+   -  Reputation: 2324

Like
0Likes
Like

Posted 29 November 2013 - 05:28 PM

 

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



#17 boogyman19946   Members   -  Reputation: 1036

Like
0Likes
Like

Posted 29 November 2013 - 05:35 PM

Actually, Sprite does have a virtual destructor because sf::Drawable has one. Here are some link  on the SFML about inheriting from sf::Sprite.

 

Nice catch! I checked out Sprite.hpp and didn't see it declare a destructor so I thought it didn't have one.


"If highly skilled generalists are rare, though, then highly skilled innovators are priceless." - ApochPiQ

My personal links :)
- Khan Academy - For all your math needs
- Java API Documentation - For all your Java info needs :D
- C++ Standard Library Reference - For some of your C++ needs ^.^

#18 SeanMiddleditch   Members   -  Reputation: 4658

Like
0Likes
Like

Posted 01 December 2013 - 12:04 AM

 

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.



#19 dejaime   Crossbones+   -  Reputation: 3925

Like
0Likes
Like

Posted 03 December 2013 - 12:56 PM

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!



#20 Paradigm Shifter   Crossbones+   -  Reputation: 5208

Like
1Likes
Like

Posted 03 December 2013 - 04:04 PM

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, 03 December 2013 - 04:09 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS