Programming »

[6 May, 2009 | Comment | Level: 1 ]

Since the down of time mankind seek the solution to the circular dependencies in C++. Well - may be ot exactly since the "down of time" and definitly not the whole of the mankind - but it have been "always" a problem.

Traditional solution was to forward-declarate it:

  1. class A;
  2.  
  3. class B
  4. {
  5. public:
  6.   B(A *) {}
  7. };
  8.  
  9. class A
  10. {
  11.   static B b;
  12. };

However it have its limitations. For example B cannot call A methods making such solutions useless. Other solution is spliting functions and class declaration - however it may cause problems if they will not match (for example some functions remain undefined):

  1. class A;
  2.  
  3. class A
  4. {
  5.   static B<A> b;
  6. public:
  7.   void doIt();
  8. };
  9.  
  10. class B
  11. {
  12. public:
  13.   B(A *);
  14.   void doSomething();
  15. };
  16.  
  17. void A::doIt()
  18. {
  19.   b.doSomething();
  20. }
  21.  
  22. B::B(A *a)
  23. {
  24.   if(a != NULL)
  25.     a->doit();
  26. }
  27.  
  28. void B::doSomething()
  29. {
  30.  
  31. }
  32.  

There is solution, at least working on gcc 4.4. Let's define B as a template:

  1.  
  2. template<typename A>
  3. class B
  4. {
  5. public:
  6.   B(A *a)
  7.   {
  8.     if(a != NULL)
  9.       a->doit();
  10.   }
  11.   void doSomething() {}
  12. };
  13.  
  14. class A
  15. {
  16.   static B<A> b;
  17. public:
  18.   void doit()
  19.   {
  20.     b.doSomething();
  21.   }
  22. };
  23.  

Probably we consider writing each time ]]> waste of space. We can simply forward-declare class and set the default arguments:

  1.  
  2. class A;
  3.  
  4. template<typename A = ::A>
  5. class B
  6. {
  7. public:
  8.   B(A *a)
  9.   {
  10.     if(a != NULL)
  11.       a->doit();
  12.   }
  13.   void doSomething() {}
  14. };
  15.  
  16. class A
  17. {
  18.   static B<A> b;
  19. public:
  20.   void doit()
  21.   {
  22.     b.doSomething();
  23.   }
  24. };
  25.