在C++
中解决循环依赖的最佳做法是什么?
我可以使用前向声明,但后来出现pointer to incomplete class type is not allowed
错误。这是否意味着使用彼此指针的两个类不能相关?
另外,我考虑过向前声明每个类,然后在main.cpp
中包含解决方案的每个标题,所以它都在一个地方。你会推荐吗?
整个项目的片段如下所示,如果在我熟悉的例子中更好地解释问题,你可以参考它,但它只是理论上的。 感谢
答案 0 :(得分:10)
您只需要正确使用前向声明:
注意:添加包含警卫。
如果没有实际的声明,很难真正做到这一点。该图很好但没有足够的信息。一张图片可能胜过千言万语,但精确定义的语言可以非常紧凑地传达更准确的信息(与英语及其不一致性不同)。
答案 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++
是一种简洁的语言。