Circular Dependency

In a situation where two types need to know about each other the solution is to use forward declaration and aggregation-by-reference in at least one of them.

You can use forward declared type T:

You can't use forward declared type T:

one.hxx:

   1 #ifndef ONE_HXX
   2 #define ONE_HXX
   3 
   4 
   5 struct two; // forward declaration
   6 
   7 
   8 struct one {
   9   one( two const& x, two const* y );
  10 
  11  private:
  12   two const& x;
  13 
  14   two const* y;
  15 };
  16 
  17 
  18 #endif

one.cxx:

   1 #include "one.hxx"
   2 #include "two.hxx"
   3 
   4 
   5 one::one( two const& x, two const* y )
   6   : x( x ),
   7     y( y ) {
   8 }

two.hxx:

   1 #ifndef TWO_HXX
   2 #define TWO_HXX
   3 
   4 
   5 struct one; // forward declaration
   6 
   7 
   8 struct two {
   9   two( one const& x, one const& y )
  10 
  11 
  12  private:
  13   one const& x;
  14 
  15   one const& y;
  16 };
  17 
  18 
  19 #endif

two.cxx:

   1 #include "one.hxx"
   2 #include "two.hxx"
   3 
   4 
   5 two::two( one const& x, one const* y )
   6   : x( x ),
   7     y( y ) {
   8 }


Access to member functions and variables.

The following is just a hack and using it usually means a design flow:

   1 struct B; // forward declaration
   2  
   3 struct A
   4 {
   5    // _Declaration_ of the function that will need access to B's members.
   6    // We can't define it yet, as we know nothing about B's members.
   7    void f(B&);  
   8    void g() { }
   9  
  10 };
  11  
  12 struct B
  13 {
  14    void f(A& a)
  15    {
  16       a.g();
  17    }
  18  
  19    void g() { }
  20 };
  21  
  22 void A::f(B& b) // _definition_ of function that uses B's member
  23 {
  24    b.g(); // B::g() is declared so we can use it here.
  25 }

It can of course be applied to data members of forward declared class as well.

CircularDependency (last edited 2007-05-22 10:53:22 by Metabol)