Header files often #include lots of other headers because other classes are being referenced. These chained includes force the compiler to repeatedly load and precompile long lists of headers over and over again.
Thanks to #pragma directives or #ifdef guards this is a rather cheap operation, but it would be a lot cheaper if the compiler didn't even have to check in the first place: because whenever a header changes, every file that inlcudes that header, or a header that includes that header, or a header that includes a header that... (you get the picture) - the compiler will then be forced to recompile that file - even though there may be not a single actual change regarding that file!
For that reason, use forward declarations in headers instead of #includes, whenever you can!
Here is an example:
File A.h:
#pragma once
class A {
private:
int m_var1;
double m_var2;
public:
void do_something();
}
File Bad.h:
#pragma once
#include "A.h"
class B {
private:
A* m_var1;
public:
void work();
}
File Bad.cpp:
#include "Bad.h"
void B::work()
{
m_var1->do_something();
}
When you look at this example, what will happen when the designer for class A decides he needs another method
void do_sth_else()
for whatever purpose, which class B isn't even interested in? When you compile your project, the compiler will recognize the dependcy of Bad.cpp to Bad.h, which didn't change, but also the dependency of Bad.h to A.h, which did! So it recompiles Bad.cpp, even though nothing has changed with respect to class B!
What's even worse, consider class C:
File C.h:
#pragma once
#include "Bad.h"
class C
{
private:
B* m_var1;
public:
void foo();
}
File C.cpp:
#include "C.h"
void C::foo()
{
m_var1->work();
}
File C.cpp is indirectly dependent on A.h as well, so needs to be recompiled, even though it cannot even directly access B's data member that uses the type!
Now change the declaration and definition of class B like that:
File Good.h:
#pragma once
class A;
class B {
private:
A* m_var1;
public:
void work();
}
File Good.cpp:
#include "Good.h"
#include "A.h"
void B::work()
{
m_var1->do_something();
}
If the designer of class A now decides to change the interface of class A, Good.cpp will still need to be recompiled (because it now directly includes A.h - but that cannot be avoided). But file C.cpp remains untouched: it no longer has any direct or indirect dependency to class A and thus does no longer require to be recompiled!