模板类具有循环依赖性

时间:2010-08-23 14:30:28

标签: c++ templates

我有两节课。一个是管理类,它存储了一堆工作类。工人实际上是一个模板化的班级。

#include "worker.h"    
class Management {

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

};

问题出现的原因是模板化的类需要使用Management。

示例:

class Worker{
   ...
};

#include "Worker.inl"

Worker inl文件:

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

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

通常,您可以在Worker头文件中转发声明Management.h,并将其称为一天。可悲的是,由于课程是模板化的,所以总是会被包括在内。

我想你可以声称设计很糟糕,因为模板化的类不应该被模板化,如果它需要知道这种信息,但它就是这样,我必须使用它。

您还可以将此问题视为办公室生活的缩影。

5 个答案:

答案 0 :(得分:2)

如果worker.inl没有引用Management的实际成员(即只有Management的指针/引用),您可以转发声明它:

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
}

否则,您唯一的选择可能是将方法实现移动到cpp文件中,而不包含在标题中。

请注意,Worker无法向前声明,因为它包含在Management中的值中:

  worker<type1> worker1;

因此编译器需要知道它的完整定义。

您还应该考虑将两个类定义放在同一个头文件中,以表示它们是相互依赖的,从而形成组件

答案 1 :(得分:1)

我没有看到模板如何改变这一点。转发声明以删除标头中的循环依赖。

编辑:对不起,我最初推翻了这个。第二个例子是正确的(见CodePad

    模板类工作者;

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();
}

答案 2 :(得分:1)

使用干净的语法解决这个问题的一种方法&amp;没有运行时开销是使用接口。基本上,Worker需要在Management上执行的所有操作都放在这样的界面中:

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

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

class Management : public IManagementOps
{
    ...
};

请注意,您的设计很好,并且Worker实际上适合Management

答案 3 :(得分:0)

我假设您正在使用include guards来避免由于递归包含而导致的编译错误。

但是为了解决这个问题,我认为解决方案是使用前向声明并在必要时使用指针/参考。

答案 4 :(得分:0)

如果您确实需要从工作类访问Management,则可以将Management作为附加模板参数添加到worker。 即像这样的东西:

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;

};