A very common situation in c++ is that we write a header that requires access to a class that is declared and defined in a different header. In this case, there are two approaches: Forward Declaration and Header Includes. For the rest of this post, let us assume that we have two classes: A and B.
Forward Declaration
If you make a forward declaration, this effectively declares the existence of a class, but it does not define it. If a header file only knows about the declaration of a class, it is impossible to use the class in anyway. Thus using forward declarations has limitations.
For example if you are defining class A in a header file “ClassA.h”, then the definition of class A cannot have a member variable B m_B. This is because in order to figure out the size of class A, you would need to know the size of class B, which is impossible if you do not have the definition of class B. This is a problem because when the compiler looks at the definition of a class, it must be able to figure out the size of the class in order to compile. Due to this, the definition for class A can only have either a pointer or reference to class B as one of its member variables. This is valid since the size of a pointer (and a reference since they use pointers under the hood) is always the same regardless of what class it is a pointer to, and thus the compiler can properly figure out the size of class A from the definition of class A. In the same vain you cannot call any of the functions of class B inside the header. That is, you cannot dereference B* in anyway, because to dereference a pointer would be to access class B itself, which we do not have the definition for.
Finally, keep in mind that if you do use forward declaration, then you must include the class header inside the source file. That is, if the “ClassA.h” forward declares class B so that the definition of A may store a pointer to B, then the source file that has the implementation of class A’s methods must include “ClassB.h” in order to access the definition of class B. If the source file which holds the implementation for class A does not include the header which has the definition of class B, then we have the same problem as previously described.
Using Includes
On the other hand, including “ClassB.h” in “ClassA.h” would give us access to both the declaration and the definition, and so there is no need to forward declare. This seems simpler right? Anything you might need, you may as well just include the header for in the header that you are currently writing, no problem! Well…. there are can potentially be consequences. One issue that might arise is compile times.
Consider that we are now writing a header that holds the definition of class C, called “ClassC.h”. The definition for class C has a member variable; B* m_B. Let say we wont bother to do a forward declaration and include “ClassB.h” in the source file, but instead we will include “ClassB.h” in “ClassC.h”. Now remember that class B’s definition also uses class A. Lets also assume that “ClassB.h” includes “ClassA.h”. Well, now realize that if you include “ClassB.h” you are also indirectly including “ClassA.h”. Suddenly class C depends on “ClassA.h” and any change made to “ClassA.h” will force a recompilation of class C. This is rather wasteful, because nowhere in the definition or implementation of class C, do we need class A, and yet we depend on it nonetheless. This issue is rather harmless for small projects, but it is possible that in larger projects such negligence can lead to very large compilation times. Following this pattern, its possible we might end up having hundreds of classes which depend on hundreds of headers, and suddenly changing a single header will cause half the project to recompile.
The other issue, which even people working on smaller projects run into, is circular dependencies and circular includes. This topic is a longer one so we will dedicate a whole section to it.
Circular Dependency and Circular Includes
While designing our project, we might however find ourselves in an situation where we have a circular dependency (This is very likely to occur in large projects, and in the process of building my DX12 abstraction layer, I found myself running into this). Say class A has a member variable B m_B, and class B has a member variable A m_A. It should be immediately clear that we have a problem here, the definition for class A depends on the definition of class B, and the definition of class B depends on the definition of class A. This is impossible to compile. Think about it from the compilers perspective, the compiler will look at one of these and when attempting to compile it, it will say:
“Well, the size of the first class depends on the size of the second class, so whats the size of the second class?”
“Well, the size of the second class depends on the size of the first class, so whats the size of the first class?”
This clearly looks like a loop that cannot be resolved and as such, compilation is out of the question. Based on what we discussed above however, we can reason that if instead, one of either class A or B used a pointer or reference to the other class instead, then that would be enough to break up this circular problem. So instead let us alter the definition of class B to instead have the member variable A* m_A. Now we are on the right track, and there is at least some hope of compilation.
We will start by looking at what someone unaware of circular dependencies in detail would do. They might have googled the circular dependency problem, and understood that they need to fix the above problem by using a pointer in one of the classes. After some research, they will likely write code that looks like the following:


Satisfied with their work, they will go ahead and press the compile button….. and I can hear it already, the sigh of frustration as they murmur “god damn compilers” when the following cryptic error presents itself:

Let us assume that with some further googling of the error codes, or by sheer luck through trial and error, the programmer in question decides to add a forward declaration of class A in “ClassB.h” such that they have the following:

They compile and huzzah! Victory! They believe they have found the secret; “you just need a forward declaration when the compiler complains”. As is normal during a project, they have other work to do, so understanding why this works is not of the utmost urgency to them and they move on. They reason loosely that probably the compiler for some reason didnt understand the type of the pointer, and so error C2143 was talking about a pointer, and that in turn led to the other errors and now everything is resolved because the forward declaration fixes the type of the pointer.
Some time passes and everything is fine. Then one day, the programmer must once again include “ClassA.h” and “ClassB.h”. This time around, they write the following:

They go ahead and press compile….. and I can hear it already, the classic sigh of frustration following by a murmur of “who even designs these stupid compilers” as they are greeted with the following error:

They are confused. This was working just fine in the past and on top of that, how can the definition of class A not know what the type B is, “ClassA.h” literally includes “ClassB.h”, surely it knows what class B is.
Let us look at what is happening here. Our source file which is being compiled starts by including “ClassB.h”, so the preprocessor will directly take the contents of “ClassB.h” and insert it into the source file. “ClassB.h” then has the directive to include “ClassA.h”, and so the preprocessor does this. “ClassA.h” then has the directive to include “ClassB.h” but the preprocessor stops there, because there is a #pragma once directive, and “ClassB.h” has already been included. So the compiler moves on with whatever has been inserted into our source file so far, and at the top of all this, is the contents of the header for class A (because “ClassB.h” was the first include in the source file, which in turn includes “ClassA.h” first and there are no further includes). The issue is now clear, the very first definition that the compiler is trying to compile is the definition for class A, but the definition for class A depends on the definition of class B, which does not yet exist. Even if “ClassA.h” includes “ClassB.h”, the #pragma once directive that served to break up the infinite loop means that the include for class B was ignored, and now the definition for class A does not in fact have access to the definition for class B.
The reason this worked the other way around (when the source file included “ClassA.h” first, and then “ClassB.h”), was because if “ClassA.h” is included first, we actually end up defining class B first due to the order of includes, and defining class B is perfectly valid as long as we just have a forward declaration of class A, since class B’s member variable is a pointer to an instance of A, and not an instance of A itself.
We can see that this whole configuration leads us to a very peculiar error that fundamentally depends on the order of includes. If your project is using just two header files like in this example, this isnt too much of an issue, you could try to remember that you must always include A before you include B. However if the project is even slightly larger, this can start to get complicated, and for very large projects, it could cause outright chaos. Having a project whose successful compilation depends on the correct order of header inclusion is a very bad situation to be in.
What is the solution to prevent this include order dependency? Well, we should only actually include headers for classes whose definition we need. Class B only uses a pointer to class A in its definition, and so a forward declaration is sufficient and we can remove the #include “ClassA.h” directive.
In this case if we include “ClassB.h” first then there is no directive in “ClassB.h” to include “ClassA.h” and so class B gets defined first (whereas before, class A was being defined first due to the include directive). If class B is defined first then there are no compilation issues, and that is the key. In general, we always want to define first the class which does not need the definition of the other class, and then we will not have any issues with our circular dependencies.
To conclude, as a general rule, for both compilation times and circular dependency reasons, you ideally want to forward declare in situations where a class does not need the definition of another class, and then include the header with the definition in the source file. And then make an effort to only have definitions of a class depend on definitions of another class in cases where it is really needed, otherwise consider just using a pointer or reference. Hopefully this post helps somebody who was as lost as I once was!