Putting the 'role' back in role-playing games since 2002.
Donate to Codex
Good Old Games
  • Welcome to rpgcodex.net, a site dedicated to discussing computer based role-playing games in a free and open fashion. We're less strict than other forums, but please refer to the rules.

    "This message is awaiting moderator approval": All new users must pass through our moderation queue before they will be able to post normally. Until your account has "passed" your posts will only be visible to yourself (and moderators) until they are approved. Give us a week to get around to approving / deleting / ignoring your mundane opinion on crap before hassling us about it. Once you have passed the moderation period (think of it as a test), you will be able to post normally, just like all the other retards.

How to get out of #include "stuff.h" hell?

desocupado

Magister
Joined
Nov 17, 2008
Messages
1,802
It's actually surprising I didn't run into it until now.

I have circular includes. -> means "includes"

Map -> Grunt -> Entity -> Sludge_Cannon -> Map

Sludge_Cannon -> Oil -> (is derived from) Map_Object -> Entity -> Sludge_Cannon

Haha. :D

Sludge_Cannon is what sparked the issue. It's derived from Module (which is abstract and will probably end an interface), which is like an accessory that can give passive boosts or a spell-like ability that may affect an Entity or the map. The problem is it needs to be able to modify the Map and/or Entities, but it's contained in a vector inside entity (and right now, initialized inside the constructor of one of Entity derived classes, although that's only temporary)

Anyway, I tried forward declaration (which I might not have done properly), but it seems I can't do that if I end up using the pointers contained the classes.

So... Any takers?
 
Last edited:

DraQ

Arcane
Joined
Oct 24, 2007
Messages
32,828
Location
Chrząszczyżewoszyce, powiat Łękołody
It's actually surprising I didn't run into it until now.

I have circular includes. -> means "includes"

Map -> Grunt -> Entity -> Sludge_Cannon -> Map

Sludge_Cannon -> Oil -> (is derived from) Map_Object -> Entity -> Sludge_Cannon

Haha. :D

Sludge_Cannon is what sparked the issue. It's derived from Module (which is abstract and will probably end an interface), which is like an accessory that can give passive boosts or a spell-like ability that may affect an Entity or the map. The problem is it needs to be able to modify the Map and/or Entities, but it's contained in a vector inside entity (and right now, initialized inside the constructor of one of Entity derived classes, although that's only temporary)

Anyway, I tried forward declaration (which I might not have done properly), but it seems I can't do that if I end up using the pointers contained the classes.

So... Any takers?
Wait, I'm not sure I understood you correctly, but why would map or entity need to be aware of your sludge_cannon anyway?
 

Declinator

Arbiter
Joined
Apr 1, 2013
Messages
542
Anyway, I tried forward declaration (which I might not have done properly), but it seems I can't do that if I end up using the pointers contained the classes.

You have the forward declaration in the .h file like so:
class Stuff;
and then you #include stuff.h in the cpp file instead of the .h file which makes it possible to actually use the pointers.
 

desocupado

Magister
Joined
Nov 17, 2008
Messages
1,802
It's actually surprising I didn't run into it until now.

I have circular includes. -> means "includes"

Map -> Grunt -> Entity -> Sludge_Cannon -> Map

Sludge_Cannon -> Oil -> (is derived from) Map_Object -> Entity -> Sludge_Cannon

Haha. :D

Sludge_Cannon is what sparked the issue. It's derived from Module (which is abstract and will probably end an interface), which is like an accessory that can give passive boosts or a spell-like ability that may affect an Entity or the map. The problem is it needs to be able to modify the Map and/or Entities, but it's contained in a vector inside entity (and right now, initialized inside the constructor of one of Entity derived classes, although that's only temporary)

Anyway, I tried forward declaration (which I might not have done properly), but it seems I can't do that if I end up using the pointers contained the classes.

So... Any takers?
Wait, I'm not sure I understood you correctly, but why would map or entity need to be aware of your sludge_cannon anyway?

Map needs to know Grunt, because Grunt is an enemy, and they're contained in the map file, which is like a level scenario. So when map generates the map based on the .txt file, it also generates the enemies on the proper positions.

Grunt needs Entity because it derives from it.

Entity needs Sludge_Cannon because Entity contains a vector with all modules, and Sludge_Cannon derives from Module, also on the constructor of Robot (derived from Entity), I call "new Sludge_Cannon".

And Sludge_Cannon needs to know map, because the function "affects(Map* map)" uses map to put some sludge on some tiles.

I also have the same problem more directly with

Entity -> Weapon -> Entity

Module -> Entity -> Module

Entities needs to have weapons, and weapons affect entity.

Modules modify entity which needs to contain modules.

Right now, weapon creates a damage object which is then passed along to Entity, thus the circular including is not necessary, however, some weapons have some other effects other than damage, and having an Weapon::affect(Entity* ent) is a much more elegant solution than go around creating (possibly null objects, in case of no effect) to pass along.
 
Last edited:

desocupado

Magister
Joined
Nov 17, 2008
Messages
1,802
Anyway, I tried forward declaration (which I might not have done properly), but it seems I can't do that if I end up using the pointers contained the classes.

You have the forward declaration in the .h file like so:
class Stuff;
and then you #include stuff.h in the cpp file instead of the .h file which makes it possible to actually use the pointers.

How about some more details on that (or a link) ? Which .h goes in which .cpp?
 
Last edited:
Joined
Dec 1, 2013
Messages
452
Ok, I think can I see what your problem is: Forward declarations allow you to use pointers (or references) to a type, but will lead to errors in any expression that requires the size of the type to be known. Of course they also won't allow you to access members or methods of the forward declared type. In short, they are only useful in other declarations.

Example: Your cannon class needs to know about maps. So, in cannon.h you write:

// Tell the compiler there is a type called "Map". That's all this line says
class Map;

// Declaration of your cannon class
class Cannon
{
// The signature only uses a pointer to Map, which is ok
void Foo(Map *map);
}

For the implementation, though, the compiler needs the actual declaration. cannon.cpp will look somewhat like this:

// If you want to create/access Map objects, you'll need their full declaration
#include <map.h>

void Cannon::Foo(Map *map)
{
// Now you can call methods on Map objects
map->Bar(42);
}

HTH.
 
Joined
Jan 4, 2014
Messages
795
I was making a GUI and encountered many instances of things like this OP, if it's any consolation to you. And I've programmed now and then for 20 years. I also used forward declerations and countless "tricks" unremembered.

What's aggravating is I moved some code from MIcrosoft Visual C++ 2010 Express to Code::Blocks using Ubuntu-Kubuntu and the s*** wouldn't compile. And that's long after I trade to make it fit the c++ standard and not use ANY windows specific references. So I've left it on hte back burner since it's a headache. But let me tell you, this s*** will drive you mad.

Most of it's just some simple googling. Still a pain in hte ass and hard to remember everyting. Good luck.

EDIT: I found something online recently "YOU AIN"T GONNA NEED IT NOW". It's a catchphrase for "Don't program something unless you need it now." or "Don't bloat your projects with unnecessary things." It's also known as "YOU AIN'T GONNA NEED IT." But I find the first one more appropriate in my case, since "NOW" communicates better when I'm actually coding.

I find myself thinking about it when I code. Maybe you'll think about it too.

A description of it:
http://www.extremeprogramming.org/rules/early.html

More in-depth:
http://www.infoq.com/news/2015/06/yagni

A video explanation (watch the whole thing!):
 
Last edited:

gaussgunner

Arcane
Joined
Jul 22, 2015
Messages
6,151
Location
ХУДШИЕ США
I have circular includes. -> means "includes"

Map -> Grunt -> Entity -> Sludge_Cannon -> Map

Sludge_Cannon -> Oil -> (is derived from) Map_Object -> Entity -> Sludge_Cannon

You can prevent circular/multiple includes put putting #pragma once at the top of each .h file, or the old way, by wrapping it in #define FILENAME_H #ifndef FILENAME_H .... #endif.

But it sounds like you're gonna end up mapping out your data structures on paper and rebuilding half of your engine. I've been there, lol.

It's not you. C++ is shit and the way they teach it (*and Java) in universities is retarded.
I've learned some workarounds:
- Avoid inheritance, templates, exceptions, operator overloading, constructors and destructors (mostly...)
- Avoid STL strings streams maps vectors lists etc when you care about performance
- Use fixed size arrays whenever you can put an upper bound on the number of items
- Use compositional OO (pointer to "superclass" object instead of inheriting it)
- Define init(...) methods to use instead of constructors
- Don't even use OO when you don't have to
 

28.8bps Modem

Prophet
Joined
Jan 15, 2014
Messages
302
Location
The Internet, Circa 1993
Forward declarations are the right way to go. Since it hasn't been said before, use forward declarations in preference to inclusion in headers where ever the compiler doesn't the need the full definition to calculate the size of the thing.

So, if you have:

Code:
class Foo
    {
private:
    Bar* mBar;
     };

Since you don't need the full definition of the class Bar to calculate the size of Foo, just forward declare it in the header and include the actual definition only in the implementation. I tend to use this as a hard and fast rule, even when the forward declared thing is publicly accessible, so the user of the class would have to include both foo.h and bar.h to use it, but it's debatable as to whether this is good style or not.

Also...

It's not you. C++ is shit and the way they teach it (*and Java) in universities is retarded.
I've learned some workarounds:
- Avoid inheritance, templates, exceptions, operator overloading, constructors and destructors (mostly...)
- Avoid STL strings streams maps vectors lists etc when you care about performance
- Use fixed size arrays whenever you can put an upper bound on the number of items
- Use compositional OO (pointer to "superclass" object instead of inheriting it)
- Define init(...) methods to use instead of constructors
- Don't even use OO when you don't have to

This advice hurts my soul. Do not listen.
 

gaussgunner

Arcane
Joined
Jul 22, 2015
Messages
6,151
Location
ХУДШИЕ США
Forward declarations are the right way to go.

Yeah. Won't solve all his probs but still good advice.

This advice hurts my soul. Do not listen.
So the best workaround of C++ is to not use what C++ was made for: OOP?

Not quite... just ignore the dogma. OO is basically glorified C structs. It's about keeping your program state manageable. All that other shit is bells and whistles and failed experiments. Some of it works in other langs but it falls apart when you bolt it onto C.

C++ is pretty bad for gamedev. Check out Mike Acton's "Data Oriented Design" talk, and Jon Blow's videos about his new language if you can stand 'em.
 

DraQ

Arcane
Joined
Oct 24, 2007
Messages
32,828
Location
Chrząszczyżewoszyce, powiat Łękołody
desocupado
Could you include (heh) a dependency diagram or stripped down class definitions (with prototypes of relevant methods)?
I'm not quite getting WHY you're ending with a circular reference in the first place.


Edit:

NVM, you seem to have answered that question already, will respond tomorrow.
 
Last edited:

DraQ

Arcane
Joined
Oct 24, 2007
Messages
32,828
Location
Chrząszczyżewoszyce, powiat Łękołody
Map needs to know Grunt, because Grunt is an enemy, and they're contained in the map file, which is like a level scenario. So when map generates the map based on the .txt file, it also generates the enemies on the proper positions.

Grunt needs Entity because it derives from it.

Entity needs Sludge_Cannon because Entity contains a vector with all modules, and Sludge_Cannon derives from Module, also on the constructor of Robot (derived from Entity), I call "new Sludge_Cannon".

And Sludge_Cannon needs to know map, because the function "affects(Map* map)" uses map to put some sludge on some tiles.

I also have the same problem more directly with

Entity -> Weapon -> Entity

Module -> Entity -> Module

Entities needs to have weapons, and weapons affect entity.

Modules modify entity which needs to contain modules.
The problem is not that you're using OOP but precisely that you don't use it (also, disregard ignorant rabble).
You need to make use of some polymorphism.
Map doesn't need to know any specific classes for enemies or whatever. Neither does Entity.
What you do need is a base class with defined interface (and virtual methods including destructor) that is known by your Entity, then having derived classes for specific things, each complete with factory class (also inheriting from base abstract factory) that can construct it and return the pointer to base. You can hold a single instance of factory as static member of derived and even have it register itself on construction into some sort of global container object (make it singleton to avoid static initialization fiasco) to make it known to map or whatever you need to at runtime but not at compile time, meaning you can now add new classes without having to modify code using them (like map).


Right now, weapon creates a damage object which is then passed along to Entity, thus the circular including is not necessary, however, some weapons have some other effects other than damage, and having an Weapon::affect(Entity* ent) is a much more elegant solution than go around creating (possibly null objects, in case of no effect) to pass along.
That's actually THE way to go.
You don't want a weapon to be messing around with internals of another object (no matter how true to life it might be) it's affected class' responsibility to know to how it should react to being hit by particular attack so it's best to pass a damage object to it and let it react in appropriate manner. This way each and every of your weapons doesn't have to be aware of each and every of your potential targets.

You can decouple a lot of things in similar manners, for example by having both Map and your Sludge_Cannon depend on Tile, or having your Sludge_Cannon pass along some sort of tile effect object (that tile could react to appropriately, even if it is the kind of tile your Sludge_Cannon doesn't know about).

It's also worth considering whether you want things that are affected by weapons and things that can wield weapons at the exact same point in the class hierarchy - maybe it would be better for all kinds of generic object to allow passing damage to them (even including other weapons) and only combatants to actually use weapons?

Multiple inheritance can be used to give particular classes more interfaces should you need it.
 

Castanova

Prophet
Joined
Jan 11, 2006
Messages
2,949
Location
The White Visitation
Map needs to know Grunt, because Grunt is an enemy, and they're contained in the map file, which is like a level scenario. So when map generates the map based on the .txt file, it also generates the enemies on the proper positions.

Grunt needs Entity because it derives from it.

Entity needs Sludge_Cannon because Entity contains a vector with all modules, and Sludge_Cannon derives from Module, also on the constructor of Robot (derived from Entity), I call "new Sludge_Cannon".

And Sludge_Cannon needs to know map, because the function "affects(Map* map)" uses map to put some sludge on some tiles.

I also have the same problem more directly with

Entity -> Weapon -> Entity

Module -> Entity -> Module

Entities needs to have weapons, and weapons affect entity.

Modules modify entity which needs to contain modules.

Right now, weapon creates a damage object which is then passed along to Entity, thus the circular including is not necessary, however, some weapons have some other effects other than damage, and having an Weapon::affect(Entity* ent) is a much more elegant solution than go around creating (possibly null objects, in case of no effect) to pass along.

In my experience, you're going down a very deep and disturbing rabbit hole with this sort of code design. Except in very simple games, it's not a good idea to have the actual "entities" (such as Sludge Cannon) responsible for behavior or processing.

What if you want Sludge Cannon to behave differently based on the skills of who is using it? What if it behaves differently depending on what turn the combat is on? If it depends on how far into the game you are? If it depends on the type of target it is shooting? You can very quickly create an interlocking web where everything depends on everything else and any simple change to your game design creates a cascading effect of breakages and forced code rewrites.

Honestly if you're not that far into it, I would scrap your current design and start over... I can't tell you how many projects I've started and abandoned for this reason. The current project I'm working on I'm WAY further into it then I've ever gotten and I'm using a flatter more data-oriented code design.
 

desocupado

Magister
Joined
Nov 17, 2008
Messages
1,802
Map needs to know Grunt, because Grunt is an enemy, and they're contained in the map file, which is like a level scenario. So when map generates the map based on the .txt file, it also generates the enemies on the proper positions.

Grunt needs Entity because it derives from it.

Entity needs Sludge_Cannon because Entity contains a vector with all modules, and Sludge_Cannon derives from Module, also on the constructor of Robot (derived from Entity), I call "new Sludge_Cannon".

And Sludge_Cannon needs to know map, because the function "affects(Map* map)" uses map to put some sludge on some tiles.

I also have the same problem more directly with

Entity -> Weapon -> Entity

Module -> Entity -> Module

Entities needs to have weapons, and weapons affect entity.

Modules modify entity which needs to contain modules.

Right now, weapon creates a damage object which is then passed along to Entity, thus the circular including is not necessary, however, some weapons have some other effects other than damage, and having an Weapon::affect(Entity* ent) is a much more elegant solution than go around creating (possibly null objects, in case of no effect) to pass along.

In my experience, you're going down a very deep and disturbing rabbit hole with this sort of code design. Except in very simple games, it's not a good idea to have the actual "entities" (such as Sludge Cannon) responsible for behavior or processing.

What if you want Sludge Cannon to behave differently based on the skills of who is using it? What if it behaves differently depending on what turn the combat is on? If it depends on how far into the game you are? If it depends on the type of target it is shooting? You can very quickly create an interlocking web where everything depends on everything else and any simple change to your game design creates a cascading effect of breakages and forced code rewrites.

Honestly if you're not that far into it, I would scrap your current design and start over... I can't tell you how many projects I've started and abandoned for this reason. The current project I'm working on I'm WAY further into it then I've ever gotten and I'm using a flatter more data-oriented code design.

I see the issue, and in fact, I've ran into this issue with buffs (weapons are more accurate if the user has a +acc buff for example), but I don't quite know how else to proceed. So far everything is working ok (few hacks here and there) and I hope they'll stay this way, but how would you manage this? Let's say you do have a piece of equipment that has all these things. Depends on the turn, how far into the game, the target and the terrain. How would you implement that?
 

Castanova

Prophet
Joined
Jan 11, 2006
Messages
2,949
Location
The White Visitation
I see the issue, and in fact, I've ran into this issue with buffs (weapons are more accurate if the user has a +acc buff for example), but I don't quite know how else to proceed. So far everything is working ok (few hacks here and there) and I hope they'll stay this way, but how would you manage this? Let's say you do have a piece of equipment that has all these things. Depends on the turn, how far into the game, the target and the terrain. How would you implement that?

Here's what I've been doing...

You may have a data structure for weapons or items in general:

struct Item
{
int itemType;
int subType;
int damage;
... // other data
};

In this case, itemType = ITEM_WEAPON and subType = ITEM_SLUDGE_CANNON.

Then, instead of Item having a method called "Shoot()" or something like that, you can have "System" classes or functions which handle all the actual logic. Like, you may implement a class like this:

class CombatRuleset
{
void shoot(Unit *shooter, unit *target, item *weapon);
};

The ruleset generally has no state. It just operates on inputs that you give it. So, only CombatRuleset has to deal with dependencies and you'll never have circular references or anything because nothing else really depends on CombatRuleset.

To answer my random example, it could be like:

void shoot(Unit *shooter, unit *target, item *weapon, int gameTime, int turnCount, int terrainType);

The other benefit of this is you can then store all your game data in external data files or maybe a database and you can create a "Generator" class that reads the data from the database and instantiates, say, a Sludge Cannon. Then you can change game balance without having to recompile the code. Also, since all your game logic is contained in these "System" classes, you can even take that out of your C++ or whatever you're using and put it into, say, Lua... then you can even change your game logic without recompiling. And your game would be moddable.
 

Leshy

Educated
Joined
Mar 9, 2014
Messages
33
Location
Cydonia, Mars
It's not you. C++ is shit and the way they teach it (*and Java) in universities is retarded.
I've learned some workarounds:
- Avoid inheritance, templates, exceptions, operator overloading, constructors and destructors (mostly...)
- Avoid STL strings streams maps vectors lists etc when you care about performance
- Use fixed size arrays whenever you can put an upper bound on the number of items
- Use compositional OO (pointer to "superclass" object instead of inheriting it)
- Define init(...) methods to use instead of constructors
- Don't even use OO when you don't have to

What? If that is your way of programming stick to C, Fortran or COBOL or whatever other ancient technology you like. But if you use C++, please do use OO and all what comes with it, just don't go full retard (virtual inheritance - just say no).

And for OP. Use #pragma once or just switch to Java or (yuck...) C#.
 
Joined
Dec 1, 2013
Messages
452
#pragma once is non-standard and has subtly different behavior than include guards. That's exactly the kind of stuff that's bound to blow up in your face when you expect it the least.

Oh, and some of gaussgunners tips are in fact quite reasonable. The C++ FQA is mandatory reading for everyone stuck with this god-awful language.
 

DraQ

Arcane
Joined
Oct 24, 2007
Messages
32,828
Location
Chrząszczyżewoszyce, powiat Łękołody
#pragma once is non-standard and has subtly different behavior than include guards. That's exactly the kind of stuff that's bound to blow up in your face when you expect it the least.
:bro:


The C++ FQA is mandatory reading for everyone stuck with this god-awful language.
Personally I consider C++ awesome and fun* :M , but I'd still recommend FQA (*after* FAQ it references) for a distanced, and somewhat amusing second look. It's not good getting saddled with tunnel vision, no matter the exact direction you're looking in.

Of course, debugging and maintaining badly written C++ code *will* drive you certifiably insane and it's sadly remarkably easy to make awful, deranged shit in C++.
 
Last edited:

As an Amazon Associate, rpgcodex.net earns from qualifying purchases.
Back
Top Bottom