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.

Original source