C++ 复杂循环依赖

C++ 复杂循环依赖,c++,oop,circular-dependency,C++,Oop,Circular Dependency,在C++中解决循环依赖的最佳实践是什么 我可以使用forward声明,但是我得到了指向不允许的不完整类类型的指针。这是否意味着两个使用彼此指针的类不能相互依赖 此外,我还考虑了向前声明每个类,然后在main.cpp中包含解决方案的每个标题,这样就可以将所有内容放在一个地方。你能推荐一下吗 下面是整个项目的一个片段,如果我熟悉的一个例子能更好地解释这个问题,那么您可以参考它,但这只是理论上的。 谢谢 一个想法是引入接口并删除循环依赖项。因此,您将拥有一个效果、播放器和效果容器所依赖的IEffect

C++
中解决循环依赖的最佳实践是什么

我可以使用forward声明,但是我得到了指向不允许的不完整类类型的
指针。这是否意味着两个使用彼此指针的类不能相互依赖

此外,我还考虑了向前声明每个类,然后在
main.cpp
中包含解决方案的每个标题,这样就可以将所有内容放在一个地方。你能推荐一下吗

下面是整个项目的一个片段,如果我熟悉的一个例子能更好地解释这个问题,那么您可以参考它,但这只是理论上的。 谢谢


一个想法是引入接口并删除循环依赖项。因此,您将拥有一个效果、播放器和效果容器所依赖的IEffect。可能的话,如果玩家依赖于某个行为的效果和效果容器取决于不同的行为集,我会考虑引入两个接口,有效地跟随。通常,这是通过让每个头文件在其
包含
之前预先声明所需的类来实现的。此外,头文件中不应放入任何代码。因此,你最终会:

class Effect;
class Player;
class GameStack;

#include <vector>
// more includes

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

class FooImpl;
class Foo {
  FooImpl* impl;
}

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

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

  • 将所有代码放入cpp文件中
  • 将类声明放在头文件中
  • 在头文件中:
  • 如果只使用指针或引用,请使用正向声明
  • 否则,您需要包含头文件。(不要添加不需要的包含项)
  • 在cpp文件中
  • 包括您需要的所有头文件
  • 注:添加包括防护装置


    没有实际的声明,很难真正做到这一点。图表很好,但没有足够的信息。一张图片可能抵得上千言万语,但一种精确定义的语言可以非常简洁地传达更准确的信息(与英语及其前后矛盾不同)。

    仅供参考,因为我不相信Matt提到了这个名字,这通常被称为PIMPL成语。你可以找到许多关于谷歌搜索的文章,这些文章将详细解释它是如何工作的。很好,我确实提供了扩展“指向私有impl的指针”,但忘记了提到短名称。谢谢,但我现在将坚持使用接口。不过,这似乎非常相似。谢谢,我没有想到这可以以如此干净的方式解决。我一开始选择了这个答案,但正如@Martin指出的,正确的集合包含和转发声明也可以处理这个问题,而不会用接口使代码膨胀,我的投票结果是他的答案。哦,你说得对,先生!非常感谢您阻止我的解决方案因接口而变得臃肿。工作起来很有魅力。只是一个跟进:如果两个类在值上相互依赖,那么这个过程在第3步不是失败了吗?@Mikulas Dite:想想可能发生的情况。尝试在单个文件中执行此操作,也会失败。这是一个递归依赖项(你也可以用一个类来实现,类X有一个类型为X的成员。或者类X有一个类型为Y的成员,而类Y有一个类型为X的成员。该语言不支持这种类型的构造)。我想我以前应该考虑一下。你是对的,这样的结构真的没有意义。
    class FooImpl;
    class Foo {
      FooImpl* impl;
    }