; }
Things to remember:
class Ahas an object of
class Bas a member or vice versa.
Read the FAQ: 39.11 39.12 39.13
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; }
I'm late answering this, but there's not one reasonable answer to date, despite being a popular question with highly upvoted answers....
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.
Say - instead of using a forward declaration header as explained above - code in
a.h or
a.cc instead forward-declares
class B; itself:
a.hor
a.ccdid include
b.hlater:
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)
#includeanalysis 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.
The simple example presented on Wikipedia worked for me. (you can read the complete description at )
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; }
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.