C++中交叉依赖类的最佳实践

3

我有两个相互依赖的类,如下所示:

// model.h
#include "facet.h"
class Model {
    ...
    std::map<int, std::vector<Facet*> > enqueue_list_;
}

// facet.h
#include "model.h"
class Facet {
    ...
    Model *parent_;
}

编译器在尝试编译此内容时显然非常不满。我已经通过前向类声明进行了修复,如下所示:
// model.h
#include "facet.h"
class Facet;
class Model {
    ...
    std::map<int, std::vector<Facet*> > enqueue_list_;
}

// facet.h
#include "model.h"
class Model;
class Facet {
    ...
    Model *parent_;
}

但我不喜欢这样做。对我来说,这似乎很混乱且难以维护。我认为使用头文件就可以解决这种问题。有没有更好的方法来解决我的问题?我希望不必在其他类头文件中转发声明类。我觉得我在这里缺少了重要的东西。如果我仍然遇到交叉依赖的问题,那么头文件的作用是什么?
提前致谢,
Max 编辑 感谢您的快速回复。我接受了建议并删除了头文件中的包含,并完全转向了前置声明。如果类具有直接的类分配,我仍然需要实际包含头文件,这一点我是正确的吗?
// facet.h
#include "point.h"
class Facet {
    ...
  private:
    Point normal_;
}

在这里尝试使用前向声明时,我遇到了错误。这是否确实是一个必须要使用#include的情况?


除非您实际使用该实例(例如在内联函数中),而不仅仅是声明指针,否则您根本不需要递归包含,只需前向声明即可。 - Some programmer dude
请点击您使用过的 [tag:circular-dependency] 标签,阅读其中的问题和答案。 - Lightness Races in Orbit
1个回答

8

您根本不需要使用#include,因为您仅存储指针,而不需要类的完整定义 - 您只需要声明即可。请直接使用前向声明:

// model.h
class Facet;

class Model {
    ...
    std::map<int, std::vector<Facet*> > enqueue_list_;
}

// facet.h
class Model;

class Facet {
    ...
    Model *parent_;
}

头文件的作用是在多个翻译单元中重复使用函数和对象的声明以及类的定义。在这种情况下,您不需要一个类的定义,只需要一个声明。
如果按照最初的方式,model.h将包含facet.h,facet.h将包含model.h,model.h将包含facet.h...... 这显然会导致无限递归包含。如果您的头文件有包含保护,可以防止无限递归,但其中一个类将不知道另一个类的存在。例如,如果首先对model.h进行预处理,则它将包含facet.h并能够看到Facet的定义,但随后facet.h将无法包含model.h(因为有包含保护),因此它将不知道Model的任何内容。

2
我看过的对于这些非常普遍问题之一的最佳答案之一。 - Lightness Races in Orbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接