I often find myself in a situation where I am facing multiple compilation/linker errors in a C++ project due to some bad design decisions (made by someone else :) ) which lead to circular dependencies between C++ classes in different header files (can happen also in the same file). But fortunately(?) this doesn't happen often enough for me to remember the solution to this problem for the next time it happens again.
So for the purposes of easy recall in the future I am going to post a representative problem and a solution along with it. Better solutions are of-course welcome.
A.h
class B; class A { int _val; B *_b; public: A(int val) :_val(val) { } void SetB(B *b) { _b = b; _b->Print(); // COMPILER ERROR: C2027: use of undefined type 'B' } void Print() { cout<<"Type:A val="<<_val<<endl; } };
B.h
#include "A.h" class B { double _val; A* _a; public: B(double val) :_val(val) { } void SetA(A *a) { _a = a; _a->Print(); } void Print() { cout<<"Type:B val="<<_val<<endl; } };
main.cpp
#include "B.h" #include <iostream> int main(int argc, char* argv[]) { A a(10); B b(3.14); a.Print(); a.SetB(&b); b.Print(); b.SetA(&a); return 0; }
I once solved this kind of problem by moving all inlines after the class definition and putting the
#include
for the other classes just before the inlines in the header file. This way one make sure all definitions+inlines are set prior the inlines are parsed.Doing like this makes it possible to still have a bunch of inlines in both(or multiple) header files. But it's necessary to have include guards.
Like this
...and doing the same in
B.h
I'm late answering this, but there's not one reasonable answer to date, despite being a popular question with highly upvoted answers....
Best practice: forward declaration headers
As illustrated by the Standard library's
<iosfwd>
header, the proper way to provide forward declarations for others is to have a forward declaration header. For example:a.fwd.h:
a.h:
b.fwd.h:
b.h:
The maintainers of the
A
andB
libraries should each be responsible for keeping their forward declaration headers in sync with their headers and implementation files, so - for example - if the maintainer of "B" comes along and rewrites the code to be...b.fwd.h:
b.h:
...then recompilation of the code for "A" will be triggered by the changes to the included
b.fwd.h
and should complete cleanly.Poor but common practice: forward declare stuff in other libs
Say - instead of using a forward declaration header as explained above - code in
a.h
ora.cc
instead forward-declaresclass B;
itself:a.h
ora.cc
did includeb.h
later:B
(i.e. the above change to B broke A and any other clients abusing forward declarations, instead of working transparently).b.h
- possible if A just stores/passes around Bs by pointer and/or reference)#include
analysis and changed file timestamps won't rebuildA
(and its further-dependent code) after the change to B, causing errors at link time or run time. If B is distributed as a runtime loaded DLL, code in "A" may fail to find the differently-mangled symbols at runtime, which may or may not be handled well enough to trigger orderly shutdown or acceptably reduced functionality.If A's code has template specialisations / "traits" for the old
B
, they won't take effect.Unfortunately, all the previous answers are missing some details. The correct solution is a little bit cumbersome, but this is the only way to do it properly. And it scales easily, handles more complex dependencies as well.
Here's how you can do this, exactly retaining all the details, and usability:
A
andB
can include A.h and B.h in any orderCreate two files, A_def.h, B_def.h. These will contain only
A
's andB
's definition:And then, A.h and B.h will contain this:
Note that A_def.h and B_def.h are "private" headers, users of
A
andB
should not use them. The public header is A.h and B.h.