开发者

Templated Class has a Circular Dependency

I have two classes. One is a management class, which stores a bunch of worker classes. The workers are actually a templated class.

#include "worker.h"    
class Management {

     private: 
      worker<type1> worker1;
      worker<type2> worker2;
      ...

};

The problem arises due to the fact that the templated classes needs to use Management.

Example:

class Worker{
   ...
};

#include "Worker.inl"

The Worker inl file:

#include "Management.h"  //Circular Dependency!

Worker::Worker(){
    //Management is accessed here
    Management mgmt1();
    mgmt1.doSomething(); //Can't use that forward declaration!
}
...

Normally you would forward declare Management.h in the Worker header file, and call it a day. Sadly, since the class is templated, it is always going to get included.

I guess you can claim that the design is bad, since a templated class shouldn't be templated if it needs to know this sort of information, but it is what it is, and I have to work with it.

You ca开发者_StackOverflown also view this question as a microcosm of office life.


If no actual members of Management are referred by worker.inl (i.e. only pointers/references to Management), you could forward declare it:

class Management;

Worker::Worker(){
    Management* mgmt1; // fine
    Management& mgmt2; // fine
    //mgmt1 = new Management(); // won't compile with forward declaration
    //mgmt2.doSomething(); // won't compile with forward declaration
}

Otherwise your only option may be to move the method implementations into a cpp file, not included in the headers.

Note that Worker can not be forward declared, since it is contained by value in Management:

  worker<type1> worker1;

thus the compiler needs to know its full definition at this point.

You should also consider putting the two class definitions into the same header file, to express that they are interdependent, thus form a component.


I don't see how templates change this. Forward declare to remove circular dependencies in headers.

EDIT: Sorry, I reversed this initially. The second example is correct though (see CodePad)

template class worker;

class Managment
{
    worker<type1> a;
    worker<type2> b;
};

template<typename T> class worker
{
///... okay to use class Managment here.
};

#include <iostream>

class type1 {};
class type2 {};

class Managment;

template<typename T> struct worker
{
    inline void doSomethingElse();
};

class Managment
{
    worker<type1> a;
    worker<type2> b;
public:
    inline void doSomething();
};


inline void Managment::doSomething()
{
    a.doSomethingElse();
    b.doSomethingElse();
}

template<typename T>
inline void worker<T>::doSomethingElse()
{
    std::cout << "Hello!";
}

int main()
{
    Managment mgmt;
    mgmt.doSomething();
}


One way to solve this with clean syntax & no runtime overhead is to use an interface. Basically, all the operations that Worker needs to perform on Management, put into some interface like this:

interface IManagementOps
{
public:
    void DoStuff() = 0;
};

class Worker
{
    IManagementOps* pOps;
    ...     
};

class Management : public IManagementOps
{
    ...
};

Please be careful that your design is good though and that it's actually appropriate for Worker to be doing things with Management.


I assume you're using include guards to avoid the compile error due to recursive inclusion.

But to solve the problem, i believe the solution is to use forward declarations and use Pointers/References when necessary.


if you actually need to access Management from worker class you can add Management as additional template parameter to worker. I.e. something like this:

template <class mngmnt, int type >
class worker{
  mngmnt* p_mngmnt;  
public:
  char* getManagementName(){return p_mngmnt->management_name;}
};


class Management {

public:
 char* management_name;

 private: 
   worker<Management,1> worker1;
   worker<Management,2> worker2;

};

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜