复杂的循环依赖

时间:2011-03-19 17:17:59

标签: c++ oop circular-dependency

C++中解决循环依赖的最佳做法是什么?

我可以使用前向声明,但后来出现pointer to incomplete class type is not allowed错误。这是否意味着使用彼此指针的两个类不能相关?

另外,我考虑过向前声明每个类,然后在main.cpp中包含解决方案的每个标题,所以它都在一个地方。你会推荐吗?

整个项目的片段如下所示,如果在我熟悉的例子中更好地解释问题,你可以参考它,但它只是理论上的。 感谢

Models depending on each other

3 个答案:

答案 0 :(得分:10)

您只需要正确使用前向声明:

  1. 将所有代码放入cpp文件
  2. 在头文件中添加类声明
  3. 在头文件中:
    1. 如果您只使用指针或引用,请使用前向声明。
    2. 否则您要包含头文件。 (添加不需要的包含)
  4. 在cpp文件中
    1. 包含您需要的所有标头文件。
  5. 注意:添加包含警卫。

    如果没有实际的声明,很难真正做到这一点。该图很好但没有足够的信息。一张图片可能胜过千言万语,但精确定义的语言可以非常紧凑地传达更准确的信息(与英语及其不一致性不同)。

答案 1 :(得分:7)

一种想法是引入接口并删除循环依赖关系。所以你会得到Effect,Player和EffectContainer所依赖的IE效果。可能,如果Player依赖于Effect的某些行为,EffectContainer依赖于一组不同的行为,我会考虑引入两个接口,有效地遵循Interface Segregation Principle。这也将跟随Dependency Inversion Principle

答案 2 :(得分:3)

通常,这是通过让每个头文件在其#include之前预先声明它需要的类来实现的。此外,不应将任何代码放在头文件中。所以你最终得到:

class Effect;
class Player;
class GameStack;

#include <vector>
// more includes

class EffectContainer { ... }

和每个地方的等价物。然后在.cpp个文件中,您实际#include其他类的标题。如果您的对象没有对其他类的内存布局的循环依赖,这将起作用。这意味着方法和成员只能通过引用或指针(而不是值)引用其他类。如果你有像

这样的东西,这可能会有点松鼠
 class EffectContainer {
   std::Vector<Effect> effects;
 }

 class Effect {
   boost::shared_ptr<EffectContainer> parent;
 }

因为模板扩展有时需要完整类型而不仅仅是预先声明的类型。许多库避免此问题的一种方法是使用指向私有impl模式的指针(通常称为PIMPL模式),其中每个类定义为:

class FooImpl;
class Foo {
  FooImpl* impl;
}

然后FooImpl完全在.cpp文件中定义,您的循环问题可能会被忽略。此设计也很有价值,因为它可以在库的各个版本之间保持二进制兼容性。它确实有点冗长,但没有人说C++是一种简洁的语言。