我有两节课。一个是管理类,它存储了一堆工作类。工人实际上是一个模板化的班级。
#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,并将其称为一天。可悲的是,由于课程是模板化的,所以总是会被包括在内。
我想你可以声称设计很糟糕,因为模板化的类不应该被模板化,如果它需要知道这种信息,但它就是这样,我必须使用它。
您还可以将此问题视为办公室生活的缩影。
答案 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; };