Why don't include guards make a circular #include work?
c++, circular-dependency, header, include, include-guards
Solution
The preprocessor is a program that takes your program, makes some changes (for example include files (#include), macro expansion (#define), and basically everything that starts with `#`) and gives the "clean" result to the compiler.
The preprocessor works like this when it sees `#include`:
When you write:
#include "some_file"
The contents of `some_file` almost literally get copy pasted into the file including it. Now if you have:
a.h:
class A { int a; };
And:
b.h:
#include "a.h"
class B { int b; };
And:
main.cpp:
#include "a.h"
#include "b.h"
You get:
main.cpp:
class A { int a; }; // From #include "a.h"
class A { int a; }; // From #include "b.h"
class B { int b; }; // From #include "b.h"
Now you can see how `A` is redefined.
When you write guards, they become like this:
a.h:
#ifndef A_H
#define A_H
class A { int a; };
#endif
b.h:
#ifndef B_H
#define B_H
#include "a.h"
class B { int b; };
#endif
So now let's look at how `#include`s in main would be expanded (this is exactly, like the previous case: copy-paste)
main.cpp:
// From #include "a.h"
#ifndef A_H
#define A_H
class A { int a; };
#endif
// From #include "b.h"
#ifndef B_H
#define B_H
#ifndef A_H // From
#define A_H // #include "a.h"
class A { int a; }; // inside
#endif // "b.h"
class B { int b; };
#endif
Now let's follow the preprocessor and see what "real" code comes out of this. I will go line by line:
// From #include "a.h"
Comment. Ignore! Continue:
#ifndef A_H
Is `A_H` defined? No! Then continue:
#define A_H
Ok now `A_H` is defined. Continue:
class A { int a; };
This is not something for preprocessor, so just leave it be. Continue:
#endif
The previous `if` finished here. Continue:
// From #include "b.h"
Comment. Ignore! Continue:
#ifndef B_H
Is `B_H` defined? No! Then continue:
#define B_H
Ok now `B_H` is defined. Continue:
#ifndef A_H // From
Is `A_H` defined? YES! Then ignore until corresponding `#endif`:
#define A_H // #include "a.h"
Ignore
class A { int a; }; // inside
Ignore
#endif // "b.h"
The previous `if` finished here. Continue:
class B { int b; };
This is not something for preprocessor, so just leave it be. Continue:
#endif
The previous `if` finished here.
That is, after the preprocessor is done with the file, this is what the compiler sees:
main.cpp
class A { int a; };
class B { int b; };
So as you can see, anything that can get `#include`d in the same file twice, whether directly or indirectly needs to be guarded. Since `.h` files are always very likely to be included twice, it is good if you guard ALL your .h files.
P.S. Note that you also have circular `#include`s. Imagine the preprocessor copy-pasting the code of Physics.h into GameObject.h which sees there is an `#include "GameObject.h"` which means copy `GameObject.h` into itself. When you copy, you again get `#include "Pysics.h"` and you are stuck in a loop forever. Compilers prevent that, but that means your `#include`s are half-done.
Before saying how to fix this, you should know another thing.
If you have:
#include "b.h"
class A
{
B b;
};
Then the compiler needs to know everything about `b`, most importantly, what variables it has etc so that it would know how many bytes it should put in place of `b` in `A`.
However, if you have:
class A
{
B *b;
};
Then the compiler doesn't really need to know anything about `B` (since pointers, regardless of the type have the same size). The only thing it needs to know about `B` is that it exists!
So you do something called "forward declaration":
class B; // This line just says B exists
class A
{
B *b;
};
This is very similar to many other things you do in header files such as:
int function(int x); // This is forward declaration
class A
{
public:
void do_something(); // This is forward declaration
}
Problem
I have three classes: `GameEvents`, `Physics` and `GameObject`. I have headers for each of them. - `GameEvents` has one `Physics` and a list of `GameObjects`. - `Physics` has a list of `GameObjects`. Note the circular dependency. I'm trying to achieve that `GameObject` is able to access or own a `Physics` object. If I simply `#include "Physics.h"` in `GameObject`, I get `error C2111: 'ClassXXX' : 'class' type redifinition` which I understand. This is where I thought include guards would help so I added an include guard to my `Physics.h` since that's the header I want to include twice. This is how it looks ``` #ifndef PHYSICS_H #define PHYSICS_H #include "GameObject.h" #include <list> class Physics { private: double gravity; list<GameObject*> objects; list<GameObject*>::iterator i; public: Physics(void); void ApplyPhysics(GameObject*); void UpdatePhysics(int); bool RectangleIntersect(SDL_Rect, SDL_Rect); Vector2X CheckCollisions(Vector2X, GameObject*); }; #endif // PHYSICS_H ``` But if I `#include "Physics.h"` in my `GameObject.h` now like this: ``` #include "Texture2D.h" #include "Vector2X.h" #include <SDL.h> #include "Physics.h" class GameObject { private: SDL_Rect collisionBox; public: Texture2D texture; Vector2X position; double gravityForce; int weight; bool isOnGround; GameObject(void); GameObject(Texture2D, Vector2X, int); void UpdateObject(int); void Draw(SDL_Surface*); void SetPosition(Vector2X); SDL_Rect GetCollisionBox(); }; ``` I get multiple issues that don't understand why they're showing up. If I don't `#include "Physics.h"` my code runs just fine.