Whenever a class declaration uses another class only as pointers, does it make sense to use a class forward declaration instead of including the headerfile in order to pre-emptively avoid problems with circular dependencies? so, instead of having:
//file C.h
#include "A.h"
#include "B.h"
class C{
A* a;
B b;
...
};
do this instead:
//file C.h
#include "B.h"
class A;
class C{
A* a;
B b;
...
};
//file C.cpp
#include "C.h"
#include "A.h"
...
Is there any reason why not to do this wherever possible?
Fun fact, in its C++ styleguide, Google recommands using
#include
everywhere but to avoid circular dependencies.Absolutely: It breaks encapsulation by requiring the user of a class or function to know and duplicate implementation details. If those implementation details change, code that forward declares can be broken while code that relies on the header will continue to work.
Forward declaring a function:
requires knowing that it's implemented as a function and not an instance of a static functor object or (gasp!) a macro,
requires duplicating the default values for default parameters,
requires knowing its actual name and namespace, since it may just be a
using
declaration that pulls it into another namespace, perhaps under an alias, andmay lose out on inline optimization.
If the consuming code relies on the header, then all those implementation details can be changed by the function provider without breaking your code.
Forward declaring a class:
requires knowing whether it's a derived class and the base class(es) it's derived from,
requires knowing that it's a class and not just a typedef or a particular instantiation of a class template (or knowing that it is a class template and getting all the template parameters and default values correct),
requires knowing the true name and namespace of the class, since it may be a
using
declaration that pulls it into another namespace, perhaps under an alias, andrequires knowing the correct attributes (perhaps it has special alignment requirements).
Again, forward declaring breaks the encapsulation of these implementation details, making your code more fragile.
If you need to cut header dependencies to speed up compilation time, then get the provider of the class/function/library to provide a special forward declarations header. The standard library does this with
<iosfwd>
. This model preserves the encapsulation of implementation details and gives the library maintainer the ability to change those implementation details without breaking your code, all while reducing the load on the compiler.Another option is to use a pimpl idiom, which hides implementation details even better and speeds up compiles at the cost of a small run-time overhead.
One case in which you don't want to have forward declarations is when they are themselves tricky. This can happen if some of your classes are templated, like in the following example:
Forward-declarations are the same as code duplication: if the code tends to change a lot, you have to change it in 2 places or more each time, and that is no good.
The only reason I think of is to save some typing.
Without forward declarations you can include header file just once, but I don't advice to do so on any rather big projects due to disadvantages pointed by other people.
Yes, using forward declarations is always better.
Some of the advantages they provide are:
However, Forward declaring a class makes that particular class an Incomplete type and that severely, restricts what operations you can perform on the Incomplete type.
You cannot perform any operations which would need the compiler to know the layout of the class.
With Incomplete type you can:
With Incomplete type you cannot:
The forward-declaration method is almost always better. (I can't think of a situation where including a file where you can use a forward declaration is better, but I'm not gonna say it's always better just in case).
There are no downsides to forward-declaring classes, but I can think of some downsides for including headers unnecessarily:
longer compilation time, since all translation units including
C.h
will also includeA.h
, although they might not need it.possibly including other headers you don't need indirectly
polluting the translation unit with symbols you don't need
you might need to recompile source files that include that header if it changes (@PeterWood)