Related
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;
}
The way to think about this is to "think like a compiler".
Imagine you are writing a compiler. And you see code like this.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
When you are compiling the .cc file (remember that the .cc and not the .h is the unit of compilation), you need to allocate space for object A. So, well, how much space then? Enough to store B! What's the size of B then? Enough to store A! Oops.
Clearly a circular reference that you must break.
You can break it by allowing the compiler to instead reserve as much space as it knows about upfront - pointers and references, for example, will always be 32 or 64 bits (depending on the architecture) and so if you replaced (either one) by a pointer or reference, things would be great. Let's say we replace in A:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Now things are better. Somewhat. main() still says:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include, for all extents and purposes (if you take the preprocessor out) just copies the file into the .cc. So really, the .cc looks like:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
You can see why the compiler can't deal with this - it has no idea what B is - it has never even seen the symbol before.
So let's tell the compiler about B. This is known as a forward declaration, and is discussed further in this answer.
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
This works. It is not great. But at this point you should have an understanding of the circular reference problem and what we did to "fix" it, albeit the fix is bad.
The reason this fix is bad is because the next person to #include "A.h" will have to declare B before they can use it and will get a terrible #include error. So let's move the declaration into A.h itself.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
And in B.h, at this point, you can just #include "A.h" directly.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.
You can avoid compilation errors if you remove the method definitions from the header files and let the classes contain only the method declarations and variable declarations/definitions. The method definitions should be placed in a .cpp file (just like a best practice guideline says).
The down side of the following solution is (assuming that you had placed the methods in the header file to inline them) that the methods are no longer inlined by the compiler and trying to use the inline keyword produces linker errors.
//A.h
#ifndef A_H
#define A_H
class B;
class A
{
int _val;
B* _b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
//B.h
#ifndef B_H
#define B_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
//A.cpp
#include "A.h"
#include "B.h"
#include <iostream>
using namespace std;
A::A(int val)
:_val(val)
{
}
void A::SetB(B *b)
{
_b = b;
cout<<"Inside SetB()"<<endl;
_b->Print();
}
void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
//B.cpp
#include "B.h"
#include "A.h"
#include <iostream>
using namespace std;
B::B(double val)
:_val(val)
{
}
void B::SetA(A *a)
{
_a = a;
cout<<"Inside SetA()"<<endl;
_a->Print();
}
void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
//main.cpp
#include "A.h"
#include "B.h"
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'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:
#pragma once
class A;
a.h:
#pragma once
#include "a.fwd.h"
#include "b.fwd.h"
class A
{
public:
void f(B*);
};
b.fwd.h:
#pragma once
class B;
b.h:
#pragma once
#include "b.fwd.h"
#include "a.fwd.h"
class B
{
public:
void f(A*);
};
The maintainers of the A and B 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:
template <typename T> class Basic_B;
typedef Basic_B<char> B;
b.h:
template <typename T>
class Basic_B
{
...class definition...
};
typedef Basic_B<char> B;
...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 or a.cc instead forward-declares class B; itself:
if a.h or a.cc did include b.h later:
compilation of A will terminate with an error once it gets to the conflicting declaration/definition of B (i.e. the above change to B broke A and any other clients abusing forward declarations, instead of working transparently).
otherwise (if A didn't eventually include b.h - possible if A just stores/passes around Bs by pointer and/or reference)
build tools relying on #include analysis and changed file timestamps won't rebuild A (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.
Things to remember:
This won't work if class A has an object of class B as a member or vice versa.
Forward declaration is way to go.
Order of declaration matters (which is why you are moving out the definitions).
If both classes call functions of the other, you have to move the definitions out.
Read the FAQ:
How can I create two classes that both know about each other?
What special considerations are needed when forward declarations are used with member objects?
What special considerations are needed when forward declarations are used with inline functions?
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
// File: A.h
#ifndef __A_H__
#define __A_H__
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
// Including class B for inline usage here
#include "B.h"
inline A::A(int val) : _val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif /* __A_H__ */
...and doing the same in B.h
I've written a post about this once: Resolving circular dependencies in c++
The basic technique is to decouple the classes using interfaces. So in your case:
//Printer.h
class Printer {
public:
virtual Print() = 0;
}
//A.h
#include "Printer.h"
class A: public Printer
{
int _val;
Printer *_b;
public:
A(int val)
:_val(val)
{
}
void SetB(Printer *b)
{
_b = b;
_b->Print();
}
void Print()
{
cout<<"Type:A val="<<_val<<endl;
}
};
//B.h
#include "Printer.h"
class B: public Printer
{
double _val;
Printer* _a;
public:
B(double val)
:_val(val)
{
}
void SetA(Printer *a)
{
_a = a;
_a->Print();
}
void Print()
{
cout<<"Type:B val="<<_val<<endl;
}
};
//main.cpp
#include <iostream>
#include "A.h"
#include "B.h"
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;
}
Here is the solution for templates: How to handle circular dependencies with templates
The clue to solving this problem is to declare both classes before providing the definitions (implementations). It’s not possible to split the declaration and definition into separate files, but you can structure them as if they were in separate files.
The simple example presented on Wikipedia worked for me.
(you can read the complete description at http://en.wikipedia.org/wiki/Circular_dependency#Example_of_circular_dependencies_in_C.2B.2B )
File '''a.h''':
#ifndef A_H
#define A_H
class B; //forward declaration
class A {
public:
B* b;
};
#endif //A_H
File '''b.h''':
#ifndef B_H
#define B_H
class A; //forward declaration
class B {
public:
A* a;
};
#endif //B_H
File '''main.cpp''':
#include "a.h"
#include "b.h"
int main() {
A a;
B b;
a.b = &b;
b.a = &a;
}
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:
the solution is exactly the same as originally intended
inline functions still inline
users of A and B can include A.h and B.h in any order
Create two files, A_def.h, B_def.h. These will contain only A's and B's definition:
// A_def.h
#ifndef A_DEF_H
#define A_DEF_H
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
// B_def.h
#ifndef B_DEF_H
#define B_DEF_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
And then, A.h and B.h will contain this:
// A.h
#ifndef A_H
#define A_H
#include "A_def.h"
#include "B_def.h"
inline A::A(int val) :_val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif
// B.h
#ifndef B_H
#define B_H
#include "A_def.h"
#include "B_def.h"
inline B::B(double val) :_val(val)
{
}
inline void B::SetA(A *a)
{
_a = a;
_a->Print();
}
inline void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
#endif
Note that A_def.h and B_def.h are "private" headers, users of A and B should not use them. The public header is A.h and B.h.
Unfortunately I can't comment the answer from geza.
He is not just saying "put forward declarations into a separate header". He says that you have to spilt class definition headers and inline function definitions into different header files to allow "defered dependencies".
But his illustration is not really good. Because both classes (A and B) only need an incomplete type of each other (pointer fields / parameters).
To understand it better imagine that class A has a field of type B not B*. In addition class A and B want to define an inline function with parameters of the other type:
This simple code would not work:
// A.h
#pragme once
#include "B.h"
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
// B.h
#pragme once
class A;
class B{
A* b;
inline void Do(A a);
}
#include "A.h"
inline void B::Do(A a){
//do something with A
}
//main.cpp
#include "A.h"
#include "B.h"
It would result in the following code:
//main.cpp
//#include "A.h"
class A;
class B{
A* b;
inline void Do(A a);
}
inline void B::Do(A a){
//do something with A
}
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
//#include "B.h"
This code does not compile because B::Do needs a complete type of A which is defined later.
To make sure that it compiles the source code should look like this:
//main.cpp
class A;
class B{
A* b;
inline void Do(A a);
}
class A{
B b;
inline void Do(B b);
}
inline void B::Do(A a){
//do something with A
}
inline void A::Do(B b){
//do something with B
}
This is exactly possible with these two header files for each class wich needs to define inline functions.
The only issue is that the circular classes can't just include the "public header".
To solve this issue I would like to suggest a preprocessor extension: #pragma process_pending_includes
This directive should defer the processing of the current file and complete all pending includes.
First we need a few definitions.
Definitions
Declaration
extern int n;
int f();
template<typename T> int g(T);
struct A;
template<typename T> struct B;
Definition
int n;
int f() { return 42; }
template<typename T> int g(T) { return 42; }
struct A { int f(); };
template<typename T> struct B { int g(T*); };
The difference is that repeating a definition causes a One Definition Rule (ODR) violation. The compiler will give an error along the lines of "error: redefinition of '...'".
Note that a "forward declaration" is just a declaration. Declarations can be repeated since they don't define anything and therefore cause no ODR.
Note that default arguments may only be given once, possibly during the declaration, but only for one of the declarations if there are multiple. Therefore one could argue that that is a definition because it may not be repeated (and in a sense it is: it defines the default arguments). However, since it doesn't define the function or template, lets call those a declaration anyway. Default arguments will be ignored below.
Function definitions
(Member) function definitions generate code. Having multiple of those (in different Translation Units (TU's), otherwise you'd get an ODR violation already during compile time) normally leads to a linker error; except when the linker resolves the collision which it does for inline functions and templated functions. Both might or might not be inlined; if they are not 100% of the time inlined then a normal function (instantiation) needs to exist; that might cause the collision that I am talking about.
Non-inline, non-template (member) functions need to exist only in a single TU and should therefore be defined in a single .cpp.
However, inline- and/or template (member) functions are defined in headers, which might be included by multiple TU's, and therefore need special treatment by the linker. They too are considered to generate code however.
Class definitions
Class definitions might or might not generate code. If they do, then that is for functions that the linker will resolve any collisions of.
Of course, any member function that is defined inside the class is per definition "inline". If it is a problem that such a function is defined during the declaration of the class, it can simply be moved outside the class declaration.
Instead of,
struct A {
int f() const { return 42; }
};
do
struct A {
inline int f() const;
}; // struct declaration ends here.
int A::f() const { return 42; }
Therefore we are mostly interested in code generation (function instantiations) that both, can not be moved outside the class declaration and requires some other definition in order to be instantiated.
It turns out that this usually involves smart pointers and default destructors. Assume that struct B can not be defined, only declared, and struct A looks as follows:
struct B;
struct A { std::unique_ptr<B> ptr; };
then an instantiation of A while the definition of B is not visible (some compilers might not mind if B is defined later in the same TU) will cause an error because both, the default constructor as well as the destructor of A, cause the destructor of unique_ptr<B> to be generated, which needs the definition of B [e.g. error: invalid application of ‘sizeof’ to incomplete type ‘B’]. There is still a way around this though: do not use generated default constructor/destructor.
For example,
struct B;
struct A {
A();
~A();
std::unique_ptr<B> ptr;
};
will compile and just have two undefined symbols for A::A() and A::~A() which you can still compile inline outside of the definition of A as before (provided you define B before you do so).
Three parts, three files?
As such we can distinguish three part of a struct/class definition that we could each put in a different file.
The (forward) declaration:
A.fwd.h
The class definition:
A.h
The inline and template member function definitions:
A.inl.h
And then there is of course A.cpp with the non-inline and non-template member function definitions; but those are not relevant for circular header dependencies.
Ignoring default arguments, declarations won't require any other declaration or definition.
Class definitions might require certain other classes to be declared, yet others to be defined.
Inline/template member functions might require additional definitions.
We can therefore create the following example that show all possibilities:
struct C;
struct B
{
B();
~B();
std::unique_ptr<C> ptr; // Need declaration of C.
};
struct A
{
B b; // Needs definition of B.
C f(); // Needs declaration of C.
};
inline A g() // Needs definition of A.
{
return {};
}
struct D
{
A a = g(); // Needs definition of A.
C c(); // Needs declaration of C.
};
where B::B(), B::~B(), C A::f() and C D::c() are defined in some .cpp.
But, lets inline those as well; at that point we need to define C because all four need that (B::B and B::~B because of the unique_ptr, see above). And doing so in this TU then suddenly makes it unnecessary to put B::B() and B::~B() outside of the definition of B (at least with the compiler that I am using). Nevertheless, lets keep B as it is.
Then we get:
// C.fwd.h:
struct C;
// B.h:
struct B
{
inline B();
inline ~B();
std::unique_ptr<C> ptr;
};
// A.h:
struct A
{
B b;
inline C f();
};
// D.h:
inline A g()
{
return {};
}
struct D
{
A a = g();
inline C c();
};
// C.h:
struct C {};
// B.inl.h:
B::B() {}
B::~B() {}
// A.inl.h:
C A::f()
{
D d;
return d.c();
}
// D.inl.h:
C D::c()
{
return {};
}
In other words, the definition of A looks like this:
// A.fwd.h:
struct A;
// A.h:
#include "B.h" // Already includes C.fwd.h, but well...
#include "C.fwd.h" // We need C to be declared too.
struct A
{
B b;
inline C f();
};
// A.inl.h:
#include "A.h"
#include "C.h"
#include "D.inl.h"
C A::f()
{
D d;
return d.c();
}
Note that in theory we could make multiple .inl.h headers: one for each function, if otherwise it drags in more than required and that causes a problem.
Forbidden patterns
Note that all #include's are at the top of all files.
(In theory) .fwd.h headers do not include other headers. Therefore they can be included at will and never lead to a circular dependency.
.h definition headers might include a .inl.h header, but if that leads to a circular header dependency then that can always be avoided by moving the function that uses the inlined function from that .inl.h to the .inl.h of the current class; in the case of smart pointers that might require to also move the destructor and/or constructor to that .inl.h.
Hence, the only remaining problem is a circular inclusion of .h definition headers, ie A.h includes B.h and B.h includes A.h. In that case you must decouple the loop by replacing a class member with a pointer.
Finally, it is not possible to have a loop of pure .inl.h files. If that is necessary you probably should move them to a single file in which case the compiler might or might not be able to solve the problem; but clearly you can't get ALL functions inlined when they use eachother, so you might as well manually decide which can be non-inlined.
In some cases it is possible to define a method or a constructor of class B in the header file of class A to resolve circular dependencies involving definitions.
In this way you can avoid having to put definitions in .cc files, for example if you want to implement a header only library.
// file: a.h
#include "b.h"
struct A {
A(const B& b) : _b(b) { }
B get() { return _b; }
B _b;
};
// note that the get method of class B is defined in a.h
A B::get() {
return A(*this);
}
// file: b.h
class A;
struct B {
// here the get method is only declared
A get();
};
// file: main.cc
#include "a.h"
int main(...) {
B b;
A a = b.get();
}
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;
}
The way to think about this is to "think like a compiler".
Imagine you are writing a compiler. And you see code like this.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
When you are compiling the .cc file (remember that the .cc and not the .h is the unit of compilation), you need to allocate space for object A. So, well, how much space then? Enough to store B! What's the size of B then? Enough to store A! Oops.
Clearly a circular reference that you must break.
You can break it by allowing the compiler to instead reserve as much space as it knows about upfront - pointers and references, for example, will always be 32 or 64 bits (depending on the architecture) and so if you replaced (either one) by a pointer or reference, things would be great. Let's say we replace in A:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Now things are better. Somewhat. main() still says:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include, for all extents and purposes (if you take the preprocessor out) just copies the file into the .cc. So really, the .cc looks like:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
You can see why the compiler can't deal with this - it has no idea what B is - it has never even seen the symbol before.
So let's tell the compiler about B. This is known as a forward declaration, and is discussed further in this answer.
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
This works. It is not great. But at this point you should have an understanding of the circular reference problem and what we did to "fix" it, albeit the fix is bad.
The reason this fix is bad is because the next person to #include "A.h" will have to declare B before they can use it and will get a terrible #include error. So let's move the declaration into A.h itself.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
And in B.h, at this point, you can just #include "A.h" directly.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.
You can avoid compilation errors if you remove the method definitions from the header files and let the classes contain only the method declarations and variable declarations/definitions. The method definitions should be placed in a .cpp file (just like a best practice guideline says).
The down side of the following solution is (assuming that you had placed the methods in the header file to inline them) that the methods are no longer inlined by the compiler and trying to use the inline keyword produces linker errors.
//A.h
#ifndef A_H
#define A_H
class B;
class A
{
int _val;
B* _b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
//B.h
#ifndef B_H
#define B_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
//A.cpp
#include "A.h"
#include "B.h"
#include <iostream>
using namespace std;
A::A(int val)
:_val(val)
{
}
void A::SetB(B *b)
{
_b = b;
cout<<"Inside SetB()"<<endl;
_b->Print();
}
void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
//B.cpp
#include "B.h"
#include "A.h"
#include <iostream>
using namespace std;
B::B(double val)
:_val(val)
{
}
void B::SetA(A *a)
{
_a = a;
cout<<"Inside SetA()"<<endl;
_a->Print();
}
void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
//main.cpp
#include "A.h"
#include "B.h"
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'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:
#pragma once
class A;
a.h:
#pragma once
#include "a.fwd.h"
#include "b.fwd.h"
class A
{
public:
void f(B*);
};
b.fwd.h:
#pragma once
class B;
b.h:
#pragma once
#include "b.fwd.h"
#include "a.fwd.h"
class B
{
public:
void f(A*);
};
The maintainers of the A and B 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:
template <typename T> class Basic_B;
typedef Basic_B<char> B;
b.h:
template <typename T>
class Basic_B
{
...class definition...
};
typedef Basic_B<char> B;
...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 or a.cc instead forward-declares class B; itself:
if a.h or a.cc did include b.h later:
compilation of A will terminate with an error once it gets to the conflicting declaration/definition of B (i.e. the above change to B broke A and any other clients abusing forward declarations, instead of working transparently).
otherwise (if A didn't eventually include b.h - possible if A just stores/passes around Bs by pointer and/or reference)
build tools relying on #include analysis and changed file timestamps won't rebuild A (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.
Things to remember:
This won't work if class A has an object of class B as a member or vice versa.
Forward declaration is way to go.
Order of declaration matters (which is why you are moving out the definitions).
If both classes call functions of the other, you have to move the definitions out.
Read the FAQ:
How can I create two classes that both know about each other?
What special considerations are needed when forward declarations are used with member objects?
What special considerations are needed when forward declarations are used with inline functions?
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
// File: A.h
#ifndef __A_H__
#define __A_H__
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
// Including class B for inline usage here
#include "B.h"
inline A::A(int val) : _val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif /* __A_H__ */
...and doing the same in B.h
I've written a post about this once: Resolving circular dependencies in c++
The basic technique is to decouple the classes using interfaces. So in your case:
//Printer.h
class Printer {
public:
virtual Print() = 0;
}
//A.h
#include "Printer.h"
class A: public Printer
{
int _val;
Printer *_b;
public:
A(int val)
:_val(val)
{
}
void SetB(Printer *b)
{
_b = b;
_b->Print();
}
void Print()
{
cout<<"Type:A val="<<_val<<endl;
}
};
//B.h
#include "Printer.h"
class B: public Printer
{
double _val;
Printer* _a;
public:
B(double val)
:_val(val)
{
}
void SetA(Printer *a)
{
_a = a;
_a->Print();
}
void Print()
{
cout<<"Type:B val="<<_val<<endl;
}
};
//main.cpp
#include <iostream>
#include "A.h"
#include "B.h"
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;
}
Here is the solution for templates: How to handle circular dependencies with templates
The clue to solving this problem is to declare both classes before providing the definitions (implementations). It’s not possible to split the declaration and definition into separate files, but you can structure them as if they were in separate files.
The simple example presented on Wikipedia worked for me.
(you can read the complete description at http://en.wikipedia.org/wiki/Circular_dependency#Example_of_circular_dependencies_in_C.2B.2B )
File '''a.h''':
#ifndef A_H
#define A_H
class B; //forward declaration
class A {
public:
B* b;
};
#endif //A_H
File '''b.h''':
#ifndef B_H
#define B_H
class A; //forward declaration
class B {
public:
A* a;
};
#endif //B_H
File '''main.cpp''':
#include "a.h"
#include "b.h"
int main() {
A a;
B b;
a.b = &b;
b.a = &a;
}
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:
the solution is exactly the same as originally intended
inline functions still inline
users of A and B can include A.h and B.h in any order
Create two files, A_def.h, B_def.h. These will contain only A's and B's definition:
// A_def.h
#ifndef A_DEF_H
#define A_DEF_H
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
// B_def.h
#ifndef B_DEF_H
#define B_DEF_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
And then, A.h and B.h will contain this:
// A.h
#ifndef A_H
#define A_H
#include "A_def.h"
#include "B_def.h"
inline A::A(int val) :_val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif
// B.h
#ifndef B_H
#define B_H
#include "A_def.h"
#include "B_def.h"
inline B::B(double val) :_val(val)
{
}
inline void B::SetA(A *a)
{
_a = a;
_a->Print();
}
inline void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
#endif
Note that A_def.h and B_def.h are "private" headers, users of A and B should not use them. The public header is A.h and B.h.
Unfortunately I can't comment the answer from geza.
He is not just saying "put forward declarations into a separate header". He says that you have to spilt class definition headers and inline function definitions into different header files to allow "defered dependencies".
But his illustration is not really good. Because both classes (A and B) only need an incomplete type of each other (pointer fields / parameters).
To understand it better imagine that class A has a field of type B not B*. In addition class A and B want to define an inline function with parameters of the other type:
This simple code would not work:
// A.h
#pragme once
#include "B.h"
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
// B.h
#pragme once
class A;
class B{
A* b;
inline void Do(A a);
}
#include "A.h"
inline void B::Do(A a){
//do something with A
}
//main.cpp
#include "A.h"
#include "B.h"
It would result in the following code:
//main.cpp
//#include "A.h"
class A;
class B{
A* b;
inline void Do(A a);
}
inline void B::Do(A a){
//do something with A
}
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
//#include "B.h"
This code does not compile because B::Do needs a complete type of A which is defined later.
To make sure that it compiles the source code should look like this:
//main.cpp
class A;
class B{
A* b;
inline void Do(A a);
}
class A{
B b;
inline void Do(B b);
}
inline void B::Do(A a){
//do something with A
}
inline void A::Do(B b){
//do something with B
}
This is exactly possible with these two header files for each class wich needs to define inline functions.
The only issue is that the circular classes can't just include the "public header".
To solve this issue I would like to suggest a preprocessor extension: #pragma process_pending_includes
This directive should defer the processing of the current file and complete all pending includes.
First we need a few definitions.
Definitions
Declaration
extern int n;
int f();
template<typename T> int g(T);
struct A;
template<typename T> struct B;
Definition
int n;
int f() { return 42; }
template<typename T> int g(T) { return 42; }
struct A { int f(); };
template<typename T> struct B { int g(T*); };
The difference is that repeating a definition causes a One Definition Rule (ODR) violation. The compiler will give an error along the lines of "error: redefinition of '...'".
Note that a "forward declaration" is just a declaration. Declarations can be repeated since they don't define anything and therefore cause no ODR.
Note that default arguments may only be given once, possibly during the declaration, but only for one of the declarations if there are multiple. Therefore one could argue that that is a definition because it may not be repeated (and in a sense it is: it defines the default arguments). However, since it doesn't define the function or template, lets call those a declaration anyway. Default arguments will be ignored below.
Function definitions
(Member) function definitions generate code. Having multiple of those (in different Translation Units (TU's), otherwise you'd get an ODR violation already during compile time) normally leads to a linker error; except when the linker resolves the collision which it does for inline functions and templated functions. Both might or might not be inlined; if they are not 100% of the time inlined then a normal function (instantiation) needs to exist; that might cause the collision that I am talking about.
Non-inline, non-template (member) functions need to exist only in a single TU and should therefore be defined in a single .cpp.
However, inline- and/or template (member) functions are defined in headers, which might be included by multiple TU's, and therefore need special treatment by the linker. They too are considered to generate code however.
Class definitions
Class definitions might or might not generate code. If they do, then that is for functions that the linker will resolve any collisions of.
Of course, any member function that is defined inside the class is per definition "inline". If it is a problem that such a function is defined during the declaration of the class, it can simply be moved outside the class declaration.
Instead of,
struct A {
int f() const { return 42; }
};
do
struct A {
inline int f() const;
}; // struct declaration ends here.
int A::f() const { return 42; }
Therefore we are mostly interested in code generation (function instantiations) that both, can not be moved outside the class declaration and requires some other definition in order to be instantiated.
It turns out that this usually involves smart pointers and default destructors. Assume that struct B can not be defined, only declared, and struct A looks as follows:
struct B;
struct A { std::unique_ptr<B> ptr; };
then an instantiation of A while the definition of B is not visible (some compilers might not mind if B is defined later in the same TU) will cause an error because both, the default constructor as well as the destructor of A, cause the destructor of unique_ptr<B> to be generated, which needs the definition of B [e.g. error: invalid application of ‘sizeof’ to incomplete type ‘B’]. There is still a way around this though: do not use generated default constructor/destructor.
For example,
struct B;
struct A {
A();
~A();
std::unique_ptr<B> ptr;
};
will compile and just have two undefined symbols for A::A() and A::~A() which you can still compile inline outside of the definition of A as before (provided you define B before you do so).
Three parts, three files?
As such we can distinguish three part of a struct/class definition that we could each put in a different file.
The (forward) declaration:
A.fwd.h
The class definition:
A.h
The inline and template member function definitions:
A.inl.h
And then there is of course A.cpp with the non-inline and non-template member function definitions; but those are not relevant for circular header dependencies.
Ignoring default arguments, declarations won't require any other declaration or definition.
Class definitions might require certain other classes to be declared, yet others to be defined.
Inline/template member functions might require additional definitions.
We can therefore create the following example that show all possibilities:
struct C;
struct B
{
B();
~B();
std::unique_ptr<C> ptr; // Need declaration of C.
};
struct A
{
B b; // Needs definition of B.
C f(); // Needs declaration of C.
};
inline A g() // Needs definition of A.
{
return {};
}
struct D
{
A a = g(); // Needs definition of A.
C c(); // Needs declaration of C.
};
where B::B(), B::~B(), C A::f() and C D::c() are defined in some .cpp.
But, lets inline those as well; at that point we need to define C because all four need that (B::B and B::~B because of the unique_ptr, see above). And doing so in this TU then suddenly makes it unnecessary to put B::B() and B::~B() outside of the definition of B (at least with the compiler that I am using). Nevertheless, lets keep B as it is.
Then we get:
// C.fwd.h:
struct C;
// B.h:
struct B
{
inline B();
inline ~B();
std::unique_ptr<C> ptr;
};
// A.h:
struct A
{
B b;
inline C f();
};
// D.h:
inline A g()
{
return {};
}
struct D
{
A a = g();
inline C c();
};
// C.h:
struct C {};
// B.inl.h:
B::B() {}
B::~B() {}
// A.inl.h:
C A::f()
{
D d;
return d.c();
}
// D.inl.h:
C D::c()
{
return {};
}
In other words, the definition of A looks like this:
// A.fwd.h:
struct A;
// A.h:
#include "B.h" // Already includes C.fwd.h, but well...
#include "C.fwd.h" // We need C to be declared too.
struct A
{
B b;
inline C f();
};
// A.inl.h:
#include "A.h"
#include "C.h"
#include "D.inl.h"
C A::f()
{
D d;
return d.c();
}
Note that in theory we could make multiple .inl.h headers: one for each function, if otherwise it drags in more than required and that causes a problem.
Forbidden patterns
Note that all #include's are at the top of all files.
(In theory) .fwd.h headers do not include other headers. Therefore they can be included at will and never lead to a circular dependency.
.h definition headers might include a .inl.h header, but if that leads to a circular header dependency then that can always be avoided by moving the function that uses the inlined function from that .inl.h to the .inl.h of the current class; in the case of smart pointers that might require to also move the destructor and/or constructor to that .inl.h.
Hence, the only remaining problem is a circular inclusion of .h definition headers, ie A.h includes B.h and B.h includes A.h. In that case you must decouple the loop by replacing a class member with a pointer.
Finally, it is not possible to have a loop of pure .inl.h files. If that is necessary you probably should move them to a single file in which case the compiler might or might not be able to solve the problem; but clearly you can't get ALL functions inlined when they use eachother, so you might as well manually decide which can be non-inlined.
In some cases it is possible to define a method or a constructor of class B in the header file of class A to resolve circular dependencies involving definitions.
In this way you can avoid having to put definitions in .cc files, for example if you want to implement a header only library.
// file: a.h
#include "b.h"
struct A {
A(const B& b) : _b(b) { }
B get() { return _b; }
B _b;
};
// note that the get method of class B is defined in a.h
A B::get() {
return A(*this);
}
// file: b.h
class A;
struct B {
// here the get method is only declared
A get();
};
// file: main.cc
#include "a.h"
int main(...) {
B b;
A a = b.get();
}
I'm having an issue where it appears an implementation file is recognizing only the forward declaration of another class, and not its actual declaration. I've tried using various guards with imports and taking out the forward declaration but to no avail.
Class A has a function "decode" which takes one argument of type B that's defined in a separate file. I'd like to keep all .h's and .cpp's as distinct files. Here they are.
A.h:
class B;
class A{
private:
string sentence;
public:
A();
void decode(const B& decoder);
};
B.h:
class B{
private:
int code[26];
public:
B();
int getCode(int index);
};
A.cpp:
#include "A.h"
A::A(){}
double A::decode(const B& decoder){
B.getCode(1);
//other things
}
B.cpp:
#include "B.h"
B::B(){}
int B::getCode(int index){};
and the driver:
#include "B.h"
#include "A.h"
using namespace std;
int main(int argc, char* argv[]){
B myB;
A myA;
myA.decode(B);
}
I'm compiling this with g++ -Wall driver.cpp B.cpp A.cpp, but get hit with an error that looks like:
A.cpp:4 error: invalid use of incomplete type 'const class B'
I've looked through a ton of similar threads trying to find the answer, but nothing has worked for me yet. Any ideas?
Since you are using B's member function getCode in your A.cpp file, the forward declaration only will not suffice as it says nothing about B's member functions. The entire B declaration needs to be available. To do that, include the "B.h" header in your A.cpp file:
#include "B.h"
As pointed out in the comments you should also utilize the header guards for A.h and B.h headers.
Best practice is that every .h file includes everything it needs. That means A.h shall include B.h.
A.h:
#pragma once // Or equivalent include-guard macros
#include "B.h"
class A{
private:
string sentence;
public:
A();
void decode(const B& decoder);
};
B.h:
#ifndef B_h
#define B_h true
class B{
private:
int code[26];
public:
B();
int getCode(int index);
};
#endif
A.cpp:
#include "A.h"
A::A(){}
double A::decode(const B& decoder){
B.getCode(1);
//other things
}
B.cpp:
#include "B.h"
B::B(){}
int B::getCode(int index){};
and the driver:
#include "A.h"
void main(){
B myB;
A myA;
myA.decode(B);
}
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;
}
The way to think about this is to "think like a compiler".
Imagine you are writing a compiler. And you see code like this.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
When you are compiling the .cc file (remember that the .cc and not the .h is the unit of compilation), you need to allocate space for object A. So, well, how much space then? Enough to store B! What's the size of B then? Enough to store A! Oops.
Clearly a circular reference that you must break.
You can break it by allowing the compiler to instead reserve as much space as it knows about upfront - pointers and references, for example, will always be 32 or 64 bits (depending on the architecture) and so if you replaced (either one) by a pointer or reference, things would be great. Let's say we replace in A:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Now things are better. Somewhat. main() still says:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include, for all extents and purposes (if you take the preprocessor out) just copies the file into the .cc. So really, the .cc looks like:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
You can see why the compiler can't deal with this - it has no idea what B is - it has never even seen the symbol before.
So let's tell the compiler about B. This is known as a forward declaration, and is discussed further in this answer.
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
This works. It is not great. But at this point you should have an understanding of the circular reference problem and what we did to "fix" it, albeit the fix is bad.
The reason this fix is bad is because the next person to #include "A.h" will have to declare B before they can use it and will get a terrible #include error. So let's move the declaration into A.h itself.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
And in B.h, at this point, you can just #include "A.h" directly.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.
You can avoid compilation errors if you remove the method definitions from the header files and let the classes contain only the method declarations and variable declarations/definitions. The method definitions should be placed in a .cpp file (just like a best practice guideline says).
The down side of the following solution is (assuming that you had placed the methods in the header file to inline them) that the methods are no longer inlined by the compiler and trying to use the inline keyword produces linker errors.
//A.h
#ifndef A_H
#define A_H
class B;
class A
{
int _val;
B* _b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
//B.h
#ifndef B_H
#define B_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
//A.cpp
#include "A.h"
#include "B.h"
#include <iostream>
using namespace std;
A::A(int val)
:_val(val)
{
}
void A::SetB(B *b)
{
_b = b;
cout<<"Inside SetB()"<<endl;
_b->Print();
}
void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
//B.cpp
#include "B.h"
#include "A.h"
#include <iostream>
using namespace std;
B::B(double val)
:_val(val)
{
}
void B::SetA(A *a)
{
_a = a;
cout<<"Inside SetA()"<<endl;
_a->Print();
}
void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
//main.cpp
#include "A.h"
#include "B.h"
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'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:
#pragma once
class A;
a.h:
#pragma once
#include "a.fwd.h"
#include "b.fwd.h"
class A
{
public:
void f(B*);
};
b.fwd.h:
#pragma once
class B;
b.h:
#pragma once
#include "b.fwd.h"
#include "a.fwd.h"
class B
{
public:
void f(A*);
};
The maintainers of the A and B 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:
template <typename T> class Basic_B;
typedef Basic_B<char> B;
b.h:
template <typename T>
class Basic_B
{
...class definition...
};
typedef Basic_B<char> B;
...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 or a.cc instead forward-declares class B; itself:
if a.h or a.cc did include b.h later:
compilation of A will terminate with an error once it gets to the conflicting declaration/definition of B (i.e. the above change to B broke A and any other clients abusing forward declarations, instead of working transparently).
otherwise (if A didn't eventually include b.h - possible if A just stores/passes around Bs by pointer and/or reference)
build tools relying on #include analysis and changed file timestamps won't rebuild A (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.
Things to remember:
This won't work if class A has an object of class B as a member or vice versa.
Forward declaration is way to go.
Order of declaration matters (which is why you are moving out the definitions).
If both classes call functions of the other, you have to move the definitions out.
Read the FAQ:
How can I create two classes that both know about each other?
What special considerations are needed when forward declarations are used with member objects?
What special considerations are needed when forward declarations are used with inline functions?
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
// File: A.h
#ifndef __A_H__
#define __A_H__
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
// Including class B for inline usage here
#include "B.h"
inline A::A(int val) : _val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif /* __A_H__ */
...and doing the same in B.h
I've written a post about this once: Resolving circular dependencies in c++
The basic technique is to decouple the classes using interfaces. So in your case:
//Printer.h
class Printer {
public:
virtual Print() = 0;
}
//A.h
#include "Printer.h"
class A: public Printer
{
int _val;
Printer *_b;
public:
A(int val)
:_val(val)
{
}
void SetB(Printer *b)
{
_b = b;
_b->Print();
}
void Print()
{
cout<<"Type:A val="<<_val<<endl;
}
};
//B.h
#include "Printer.h"
class B: public Printer
{
double _val;
Printer* _a;
public:
B(double val)
:_val(val)
{
}
void SetA(Printer *a)
{
_a = a;
_a->Print();
}
void Print()
{
cout<<"Type:B val="<<_val<<endl;
}
};
//main.cpp
#include <iostream>
#include "A.h"
#include "B.h"
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;
}
Here is the solution for templates: How to handle circular dependencies with templates
The clue to solving this problem is to declare both classes before providing the definitions (implementations). It’s not possible to split the declaration and definition into separate files, but you can structure them as if they were in separate files.
The simple example presented on Wikipedia worked for me.
(you can read the complete description at http://en.wikipedia.org/wiki/Circular_dependency#Example_of_circular_dependencies_in_C.2B.2B )
File '''a.h''':
#ifndef A_H
#define A_H
class B; //forward declaration
class A {
public:
B* b;
};
#endif //A_H
File '''b.h''':
#ifndef B_H
#define B_H
class A; //forward declaration
class B {
public:
A* a;
};
#endif //B_H
File '''main.cpp''':
#include "a.h"
#include "b.h"
int main() {
A a;
B b;
a.b = &b;
b.a = &a;
}
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:
the solution is exactly the same as originally intended
inline functions still inline
users of A and B can include A.h and B.h in any order
Create two files, A_def.h, B_def.h. These will contain only A's and B's definition:
// A_def.h
#ifndef A_DEF_H
#define A_DEF_H
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
// B_def.h
#ifndef B_DEF_H
#define B_DEF_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
And then, A.h and B.h will contain this:
// A.h
#ifndef A_H
#define A_H
#include "A_def.h"
#include "B_def.h"
inline A::A(int val) :_val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif
// B.h
#ifndef B_H
#define B_H
#include "A_def.h"
#include "B_def.h"
inline B::B(double val) :_val(val)
{
}
inline void B::SetA(A *a)
{
_a = a;
_a->Print();
}
inline void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
#endif
Note that A_def.h and B_def.h are "private" headers, users of A and B should not use them. The public header is A.h and B.h.
Unfortunately I can't comment the answer from geza.
He is not just saying "put forward declarations into a separate header". He says that you have to spilt class definition headers and inline function definitions into different header files to allow "defered dependencies".
But his illustration is not really good. Because both classes (A and B) only need an incomplete type of each other (pointer fields / parameters).
To understand it better imagine that class A has a field of type B not B*. In addition class A and B want to define an inline function with parameters of the other type:
This simple code would not work:
// A.h
#pragme once
#include "B.h"
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
// B.h
#pragme once
class A;
class B{
A* b;
inline void Do(A a);
}
#include "A.h"
inline void B::Do(A a){
//do something with A
}
//main.cpp
#include "A.h"
#include "B.h"
It would result in the following code:
//main.cpp
//#include "A.h"
class A;
class B{
A* b;
inline void Do(A a);
}
inline void B::Do(A a){
//do something with A
}
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
//#include "B.h"
This code does not compile because B::Do needs a complete type of A which is defined later.
To make sure that it compiles the source code should look like this:
//main.cpp
class A;
class B{
A* b;
inline void Do(A a);
}
class A{
B b;
inline void Do(B b);
}
inline void B::Do(A a){
//do something with A
}
inline void A::Do(B b){
//do something with B
}
This is exactly possible with these two header files for each class wich needs to define inline functions.
The only issue is that the circular classes can't just include the "public header".
To solve this issue I would like to suggest a preprocessor extension: #pragma process_pending_includes
This directive should defer the processing of the current file and complete all pending includes.
First we need a few definitions.
Definitions
Declaration
extern int n;
int f();
template<typename T> int g(T);
struct A;
template<typename T> struct B;
Definition
int n;
int f() { return 42; }
template<typename T> int g(T) { return 42; }
struct A { int f(); };
template<typename T> struct B { int g(T*); };
The difference is that repeating a definition causes a One Definition Rule (ODR) violation. The compiler will give an error along the lines of "error: redefinition of '...'".
Note that a "forward declaration" is just a declaration. Declarations can be repeated since they don't define anything and therefore cause no ODR.
Note that default arguments may only be given once, possibly during the declaration, but only for one of the declarations if there are multiple. Therefore one could argue that that is a definition because it may not be repeated (and in a sense it is: it defines the default arguments). However, since it doesn't define the function or template, lets call those a declaration anyway. Default arguments will be ignored below.
Function definitions
(Member) function definitions generate code. Having multiple of those (in different Translation Units (TU's), otherwise you'd get an ODR violation already during compile time) normally leads to a linker error; except when the linker resolves the collision which it does for inline functions and templated functions. Both might or might not be inlined; if they are not 100% of the time inlined then a normal function (instantiation) needs to exist; that might cause the collision that I am talking about.
Non-inline, non-template (member) functions need to exist only in a single TU and should therefore be defined in a single .cpp.
However, inline- and/or template (member) functions are defined in headers, which might be included by multiple TU's, and therefore need special treatment by the linker. They too are considered to generate code however.
Class definitions
Class definitions might or might not generate code. If they do, then that is for functions that the linker will resolve any collisions of.
Of course, any member function that is defined inside the class is per definition "inline". If it is a problem that such a function is defined during the declaration of the class, it can simply be moved outside the class declaration.
Instead of,
struct A {
int f() const { return 42; }
};
do
struct A {
inline int f() const;
}; // struct declaration ends here.
int A::f() const { return 42; }
Therefore we are mostly interested in code generation (function instantiations) that both, can not be moved outside the class declaration and requires some other definition in order to be instantiated.
It turns out that this usually involves smart pointers and default destructors. Assume that struct B can not be defined, only declared, and struct A looks as follows:
struct B;
struct A { std::unique_ptr<B> ptr; };
then an instantiation of A while the definition of B is not visible (some compilers might not mind if B is defined later in the same TU) will cause an error because both, the default constructor as well as the destructor of A, cause the destructor of unique_ptr<B> to be generated, which needs the definition of B [e.g. error: invalid application of ‘sizeof’ to incomplete type ‘B’]. There is still a way around this though: do not use generated default constructor/destructor.
For example,
struct B;
struct A {
A();
~A();
std::unique_ptr<B> ptr;
};
will compile and just have two undefined symbols for A::A() and A::~A() which you can still compile inline outside of the definition of A as before (provided you define B before you do so).
Three parts, three files?
As such we can distinguish three part of a struct/class definition that we could each put in a different file.
The (forward) declaration:
A.fwd.h
The class definition:
A.h
The inline and template member function definitions:
A.inl.h
And then there is of course A.cpp with the non-inline and non-template member function definitions; but those are not relevant for circular header dependencies.
Ignoring default arguments, declarations won't require any other declaration or definition.
Class definitions might require certain other classes to be declared, yet others to be defined.
Inline/template member functions might require additional definitions.
We can therefore create the following example that show all possibilities:
struct C;
struct B
{
B();
~B();
std::unique_ptr<C> ptr; // Need declaration of C.
};
struct A
{
B b; // Needs definition of B.
C f(); // Needs declaration of C.
};
inline A g() // Needs definition of A.
{
return {};
}
struct D
{
A a = g(); // Needs definition of A.
C c(); // Needs declaration of C.
};
where B::B(), B::~B(), C A::f() and C D::c() are defined in some .cpp.
But, lets inline those as well; at that point we need to define C because all four need that (B::B and B::~B because of the unique_ptr, see above). And doing so in this TU then suddenly makes it unnecessary to put B::B() and B::~B() outside of the definition of B (at least with the compiler that I am using). Nevertheless, lets keep B as it is.
Then we get:
// C.fwd.h:
struct C;
// B.h:
struct B
{
inline B();
inline ~B();
std::unique_ptr<C> ptr;
};
// A.h:
struct A
{
B b;
inline C f();
};
// D.h:
inline A g()
{
return {};
}
struct D
{
A a = g();
inline C c();
};
// C.h:
struct C {};
// B.inl.h:
B::B() {}
B::~B() {}
// A.inl.h:
C A::f()
{
D d;
return d.c();
}
// D.inl.h:
C D::c()
{
return {};
}
In other words, the definition of A looks like this:
// A.fwd.h:
struct A;
// A.h:
#include "B.h" // Already includes C.fwd.h, but well...
#include "C.fwd.h" // We need C to be declared too.
struct A
{
B b;
inline C f();
};
// A.inl.h:
#include "A.h"
#include "C.h"
#include "D.inl.h"
C A::f()
{
D d;
return d.c();
}
Note that in theory we could make multiple .inl.h headers: one for each function, if otherwise it drags in more than required and that causes a problem.
Forbidden patterns
Note that all #include's are at the top of all files.
(In theory) .fwd.h headers do not include other headers. Therefore they can be included at will and never lead to a circular dependency.
.h definition headers might include a .inl.h header, but if that leads to a circular header dependency then that can always be avoided by moving the function that uses the inlined function from that .inl.h to the .inl.h of the current class; in the case of smart pointers that might require to also move the destructor and/or constructor to that .inl.h.
Hence, the only remaining problem is a circular inclusion of .h definition headers, ie A.h includes B.h and B.h includes A.h. In that case you must decouple the loop by replacing a class member with a pointer.
Finally, it is not possible to have a loop of pure .inl.h files. If that is necessary you probably should move them to a single file in which case the compiler might or might not be able to solve the problem; but clearly you can't get ALL functions inlined when they use eachother, so you might as well manually decide which can be non-inlined.
In some cases it is possible to define a method or a constructor of class B in the header file of class A to resolve circular dependencies involving definitions.
In this way you can avoid having to put definitions in .cc files, for example if you want to implement a header only library.
// file: a.h
#include "b.h"
struct A {
A(const B& b) : _b(b) { }
B get() { return _b; }
B _b;
};
// note that the get method of class B is defined in a.h
A B::get() {
return A(*this);
}
// file: b.h
class A;
struct B {
// here the get method is only declared
A get();
};
// file: main.cc
#include "a.h"
int main(...) {
B b;
A a = b.get();
}
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;
}
The way to think about this is to "think like a compiler".
Imagine you are writing a compiler. And you see code like this.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
When you are compiling the .cc file (remember that the .cc and not the .h is the unit of compilation), you need to allocate space for object A. So, well, how much space then? Enough to store B! What's the size of B then? Enough to store A! Oops.
Clearly a circular reference that you must break.
You can break it by allowing the compiler to instead reserve as much space as it knows about upfront - pointers and references, for example, will always be 32 or 64 bits (depending on the architecture) and so if you replaced (either one) by a pointer or reference, things would be great. Let's say we replace in A:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Now things are better. Somewhat. main() still says:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include, for all extents and purposes (if you take the preprocessor out) just copies the file into the .cc. So really, the .cc looks like:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
You can see why the compiler can't deal with this - it has no idea what B is - it has never even seen the symbol before.
So let's tell the compiler about B. This is known as a forward declaration, and is discussed further in this answer.
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
This works. It is not great. But at this point you should have an understanding of the circular reference problem and what we did to "fix" it, albeit the fix is bad.
The reason this fix is bad is because the next person to #include "A.h" will have to declare B before they can use it and will get a terrible #include error. So let's move the declaration into A.h itself.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
And in B.h, at this point, you can just #include "A.h" directly.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.
You can avoid compilation errors if you remove the method definitions from the header files and let the classes contain only the method declarations and variable declarations/definitions. The method definitions should be placed in a .cpp file (just like a best practice guideline says).
The down side of the following solution is (assuming that you had placed the methods in the header file to inline them) that the methods are no longer inlined by the compiler and trying to use the inline keyword produces linker errors.
//A.h
#ifndef A_H
#define A_H
class B;
class A
{
int _val;
B* _b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
//B.h
#ifndef B_H
#define B_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
//A.cpp
#include "A.h"
#include "B.h"
#include <iostream>
using namespace std;
A::A(int val)
:_val(val)
{
}
void A::SetB(B *b)
{
_b = b;
cout<<"Inside SetB()"<<endl;
_b->Print();
}
void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
//B.cpp
#include "B.h"
#include "A.h"
#include <iostream>
using namespace std;
B::B(double val)
:_val(val)
{
}
void B::SetA(A *a)
{
_a = a;
cout<<"Inside SetA()"<<endl;
_a->Print();
}
void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
//main.cpp
#include "A.h"
#include "B.h"
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'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:
#pragma once
class A;
a.h:
#pragma once
#include "a.fwd.h"
#include "b.fwd.h"
class A
{
public:
void f(B*);
};
b.fwd.h:
#pragma once
class B;
b.h:
#pragma once
#include "b.fwd.h"
#include "a.fwd.h"
class B
{
public:
void f(A*);
};
The maintainers of the A and B 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:
template <typename T> class Basic_B;
typedef Basic_B<char> B;
b.h:
template <typename T>
class Basic_B
{
...class definition...
};
typedef Basic_B<char> B;
...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 or a.cc instead forward-declares class B; itself:
if a.h or a.cc did include b.h later:
compilation of A will terminate with an error once it gets to the conflicting declaration/definition of B (i.e. the above change to B broke A and any other clients abusing forward declarations, instead of working transparently).
otherwise (if A didn't eventually include b.h - possible if A just stores/passes around Bs by pointer and/or reference)
build tools relying on #include analysis and changed file timestamps won't rebuild A (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.
Things to remember:
This won't work if class A has an object of class B as a member or vice versa.
Forward declaration is way to go.
Order of declaration matters (which is why you are moving out the definitions).
If both classes call functions of the other, you have to move the definitions out.
Read the FAQ:
How can I create two classes that both know about each other?
What special considerations are needed when forward declarations are used with member objects?
What special considerations are needed when forward declarations are used with inline functions?
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
// File: A.h
#ifndef __A_H__
#define __A_H__
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
// Including class B for inline usage here
#include "B.h"
inline A::A(int val) : _val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif /* __A_H__ */
...and doing the same in B.h
I've written a post about this once: Resolving circular dependencies in c++
The basic technique is to decouple the classes using interfaces. So in your case:
//Printer.h
class Printer {
public:
virtual Print() = 0;
}
//A.h
#include "Printer.h"
class A: public Printer
{
int _val;
Printer *_b;
public:
A(int val)
:_val(val)
{
}
void SetB(Printer *b)
{
_b = b;
_b->Print();
}
void Print()
{
cout<<"Type:A val="<<_val<<endl;
}
};
//B.h
#include "Printer.h"
class B: public Printer
{
double _val;
Printer* _a;
public:
B(double val)
:_val(val)
{
}
void SetA(Printer *a)
{
_a = a;
_a->Print();
}
void Print()
{
cout<<"Type:B val="<<_val<<endl;
}
};
//main.cpp
#include <iostream>
#include "A.h"
#include "B.h"
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;
}
Here is the solution for templates: How to handle circular dependencies with templates
The clue to solving this problem is to declare both classes before providing the definitions (implementations). It’s not possible to split the declaration and definition into separate files, but you can structure them as if they were in separate files.
The simple example presented on Wikipedia worked for me.
(you can read the complete description at http://en.wikipedia.org/wiki/Circular_dependency#Example_of_circular_dependencies_in_C.2B.2B )
File '''a.h''':
#ifndef A_H
#define A_H
class B; //forward declaration
class A {
public:
B* b;
};
#endif //A_H
File '''b.h''':
#ifndef B_H
#define B_H
class A; //forward declaration
class B {
public:
A* a;
};
#endif //B_H
File '''main.cpp''':
#include "a.h"
#include "b.h"
int main() {
A a;
B b;
a.b = &b;
b.a = &a;
}
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:
the solution is exactly the same as originally intended
inline functions still inline
users of A and B can include A.h and B.h in any order
Create two files, A_def.h, B_def.h. These will contain only A's and B's definition:
// A_def.h
#ifndef A_DEF_H
#define A_DEF_H
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
// B_def.h
#ifndef B_DEF_H
#define B_DEF_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
And then, A.h and B.h will contain this:
// A.h
#ifndef A_H
#define A_H
#include "A_def.h"
#include "B_def.h"
inline A::A(int val) :_val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif
// B.h
#ifndef B_H
#define B_H
#include "A_def.h"
#include "B_def.h"
inline B::B(double val) :_val(val)
{
}
inline void B::SetA(A *a)
{
_a = a;
_a->Print();
}
inline void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
#endif
Note that A_def.h and B_def.h are "private" headers, users of A and B should not use them. The public header is A.h and B.h.
Unfortunately I can't comment the answer from geza.
He is not just saying "put forward declarations into a separate header". He says that you have to spilt class definition headers and inline function definitions into different header files to allow "defered dependencies".
But his illustration is not really good. Because both classes (A and B) only need an incomplete type of each other (pointer fields / parameters).
To understand it better imagine that class A has a field of type B not B*. In addition class A and B want to define an inline function with parameters of the other type:
This simple code would not work:
// A.h
#pragme once
#include "B.h"
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
// B.h
#pragme once
class A;
class B{
A* b;
inline void Do(A a);
}
#include "A.h"
inline void B::Do(A a){
//do something with A
}
//main.cpp
#include "A.h"
#include "B.h"
It would result in the following code:
//main.cpp
//#include "A.h"
class A;
class B{
A* b;
inline void Do(A a);
}
inline void B::Do(A a){
//do something with A
}
class A{
B b;
inline void Do(B b);
}
inline void A::Do(B b){
//do something with B
}
//#include "B.h"
This code does not compile because B::Do needs a complete type of A which is defined later.
To make sure that it compiles the source code should look like this:
//main.cpp
class A;
class B{
A* b;
inline void Do(A a);
}
class A{
B b;
inline void Do(B b);
}
inline void B::Do(A a){
//do something with A
}
inline void A::Do(B b){
//do something with B
}
This is exactly possible with these two header files for each class wich needs to define inline functions.
The only issue is that the circular classes can't just include the "public header".
To solve this issue I would like to suggest a preprocessor extension: #pragma process_pending_includes
This directive should defer the processing of the current file and complete all pending includes.
First we need a few definitions.
Definitions
Declaration
extern int n;
int f();
template<typename T> int g(T);
struct A;
template<typename T> struct B;
Definition
int n;
int f() { return 42; }
template<typename T> int g(T) { return 42; }
struct A { int f(); };
template<typename T> struct B { int g(T*); };
The difference is that repeating a definition causes a One Definition Rule (ODR) violation. The compiler will give an error along the lines of "error: redefinition of '...'".
Note that a "forward declaration" is just a declaration. Declarations can be repeated since they don't define anything and therefore cause no ODR.
Note that default arguments may only be given once, possibly during the declaration, but only for one of the declarations if there are multiple. Therefore one could argue that that is a definition because it may not be repeated (and in a sense it is: it defines the default arguments). However, since it doesn't define the function or template, lets call those a declaration anyway. Default arguments will be ignored below.
Function definitions
(Member) function definitions generate code. Having multiple of those (in different Translation Units (TU's), otherwise you'd get an ODR violation already during compile time) normally leads to a linker error; except when the linker resolves the collision which it does for inline functions and templated functions. Both might or might not be inlined; if they are not 100% of the time inlined then a normal function (instantiation) needs to exist; that might cause the collision that I am talking about.
Non-inline, non-template (member) functions need to exist only in a single TU and should therefore be defined in a single .cpp.
However, inline- and/or template (member) functions are defined in headers, which might be included by multiple TU's, and therefore need special treatment by the linker. They too are considered to generate code however.
Class definitions
Class definitions might or might not generate code. If they do, then that is for functions that the linker will resolve any collisions of.
Of course, any member function that is defined inside the class is per definition "inline". If it is a problem that such a function is defined during the declaration of the class, it can simply be moved outside the class declaration.
Instead of,
struct A {
int f() const { return 42; }
};
do
struct A {
inline int f() const;
}; // struct declaration ends here.
int A::f() const { return 42; }
Therefore we are mostly interested in code generation (function instantiations) that both, can not be moved outside the class declaration and requires some other definition in order to be instantiated.
It turns out that this usually involves smart pointers and default destructors. Assume that struct B can not be defined, only declared, and struct A looks as follows:
struct B;
struct A { std::unique_ptr<B> ptr; };
then an instantiation of A while the definition of B is not visible (some compilers might not mind if B is defined later in the same TU) will cause an error because both, the default constructor as well as the destructor of A, cause the destructor of unique_ptr<B> to be generated, which needs the definition of B [e.g. error: invalid application of ‘sizeof’ to incomplete type ‘B’]. There is still a way around this though: do not use generated default constructor/destructor.
For example,
struct B;
struct A {
A();
~A();
std::unique_ptr<B> ptr;
};
will compile and just have two undefined symbols for A::A() and A::~A() which you can still compile inline outside of the definition of A as before (provided you define B before you do so).
Three parts, three files?
As such we can distinguish three part of a struct/class definition that we could each put in a different file.
The (forward) declaration:
A.fwd.h
The class definition:
A.h
The inline and template member function definitions:
A.inl.h
And then there is of course A.cpp with the non-inline and non-template member function definitions; but those are not relevant for circular header dependencies.
Ignoring default arguments, declarations won't require any other declaration or definition.
Class definitions might require certain other classes to be declared, yet others to be defined.
Inline/template member functions might require additional definitions.
We can therefore create the following example that show all possibilities:
struct C;
struct B
{
B();
~B();
std::unique_ptr<C> ptr; // Need declaration of C.
};
struct A
{
B b; // Needs definition of B.
C f(); // Needs declaration of C.
};
inline A g() // Needs definition of A.
{
return {};
}
struct D
{
A a = g(); // Needs definition of A.
C c(); // Needs declaration of C.
};
where B::B(), B::~B(), C A::f() and C D::c() are defined in some .cpp.
But, lets inline those as well; at that point we need to define C because all four need that (B::B and B::~B because of the unique_ptr, see above). And doing so in this TU then suddenly makes it unnecessary to put B::B() and B::~B() outside of the definition of B (at least with the compiler that I am using). Nevertheless, lets keep B as it is.
Then we get:
// C.fwd.h:
struct C;
// B.h:
struct B
{
inline B();
inline ~B();
std::unique_ptr<C> ptr;
};
// A.h:
struct A
{
B b;
inline C f();
};
// D.h:
inline A g()
{
return {};
}
struct D
{
A a = g();
inline C c();
};
// C.h:
struct C {};
// B.inl.h:
B::B() {}
B::~B() {}
// A.inl.h:
C A::f()
{
D d;
return d.c();
}
// D.inl.h:
C D::c()
{
return {};
}
In other words, the definition of A looks like this:
// A.fwd.h:
struct A;
// A.h:
#include "B.h" // Already includes C.fwd.h, but well...
#include "C.fwd.h" // We need C to be declared too.
struct A
{
B b;
inline C f();
};
// A.inl.h:
#include "A.h"
#include "C.h"
#include "D.inl.h"
C A::f()
{
D d;
return d.c();
}
Note that in theory we could make multiple .inl.h headers: one for each function, if otherwise it drags in more than required and that causes a problem.
Forbidden patterns
Note that all #include's are at the top of all files.
(In theory) .fwd.h headers do not include other headers. Therefore they can be included at will and never lead to a circular dependency.
.h definition headers might include a .inl.h header, but if that leads to a circular header dependency then that can always be avoided by moving the function that uses the inlined function from that .inl.h to the .inl.h of the current class; in the case of smart pointers that might require to also move the destructor and/or constructor to that .inl.h.
Hence, the only remaining problem is a circular inclusion of .h definition headers, ie A.h includes B.h and B.h includes A.h. In that case you must decouple the loop by replacing a class member with a pointer.
Finally, it is not possible to have a loop of pure .inl.h files. If that is necessary you probably should move them to a single file in which case the compiler might or might not be able to solve the problem; but clearly you can't get ALL functions inlined when they use eachother, so you might as well manually decide which can be non-inlined.
In some cases it is possible to define a method or a constructor of class B in the header file of class A to resolve circular dependencies involving definitions.
In this way you can avoid having to put definitions in .cc files, for example if you want to implement a header only library.
// file: a.h
#include "b.h"
struct A {
A(const B& b) : _b(b) { }
B get() { return _b; }
B _b;
};
// note that the get method of class B is defined in a.h
A B::get() {
return A(*this);
}
// file: b.h
class A;
struct B {
// here the get method is only declared
A get();
};
// file: main.cc
#include "a.h"
int main(...) {
B b;
A a = b.get();
}