包含标题的一些规则是什么?

时间:2009-10-14 20:06:02

标签: c++ include

我的程序越大,我就会遇到问题。例如,我收到以下错误:

In file included from WidgetText.h:8,
                 from LCDText.h:17,
                 from WidgetText.cpp:13:
Generic.h:21: error: expected class-name before ',' token

以下是这些行:

#include "Generic.h" // WidgetText.h:8

#include "WidgetText.h" // LCDText.h:17

#include "LCDText.h" // WidgetText.cpp:13

class Generic: public virtual LCDText, public CFG, public virtual Evaluator { // Generic.h:21

以下是各种头文件的内容:

//Generic.h
#include "CFG.h"
#include "Evaluator.h"
#include "LCDText.h"
#include "Widget.h"

//WidgetText.h
#include "Generic.h"
#include "Property.h"
#include "Widget.h"

//LCDText.h
class Generic;
#include "LCDBase.h"
#include "WidgetText.h"

这并不提供太多;我知道。我不确定还包括什么。每个标头定义一个以其标头命名的类,因此LCDText.h有一个名为LCDText的类。

在LCDText.h中声明类'Generic'的一行必须放在那里,因为早期的问题与此类似。我假设当前这个问题有类似的解决方案,但到目前为止我找不到它。

4 个答案:

答案 0 :(得分:7)

你有一个循环依赖:Generic.h包括LCDText.h,其中包括WidgetText.h,其中包括Generic.h;错误源于这个基本问题。如果您可以重新设计标题以消除此循环,则错误可能会在重构中解决,或者问题将变得比现在更加明显。

答案 1 :(得分:3)

根据此处提供的代码,您似乎多次包含头文件。为了防止出现问题,您需要在头文件中使用条件保护。

答案 2 :(得分:2)

解决方案的一部分是添加一些forward declarations以消除这些编译器错误(就像使用class Generic行一样)。谷歌将就如何做到这一点提出很多建议。

使用前向声明可以消除本答案中描述的循环/循环#include

前向声明允许您包含对前向声明的类的引用和指针,它允许您将前向声明的类作为参数传递,但它不允许您派生或包含前向的实例成员-declared类。因此,您的Generic类需要一种方法#include(而不仅仅是前向声明)LCDText,CFG和Evaluator的头文件。如果它不能这样做因为LCDText,CFG或Evaluator需要#include(而不仅仅是前向声明)Generic,那么你需要重新安排你的层次结构来修复它(例如,通过创建一个成员变量对类的指针或引用,而不是使它成为类的实例。)

然而,使用这样的多重继承(尤其是使用两个虚拟继承所隐含的钻石继承)是一种明确的代码气味。它表明你应该以不同的方式设计你的类层次结构。例如,也许你需要支持组合而不是继承。这将使清理前向声明和循环依赖变得更加容易。

编辑:您提到您在代码库变大时已经遇到了这个问题。我被告知John Lakos的Large-Scale C++ Software Design是管理大型项目中头文件依赖性等问题的一个很好的参考,尽管现在你的项目可能有点过分。

答案 3 :(得分:2)

其他人已经指出了循环依赖,但如果你仍然不确定如何解决它,那么它会查找全世界,好像你需要在WidgetText.h中转发声明Generic,即第8行变为

class Generic;

如果您已经尝试过,听起来好像有,那么您需要检查如何在WidgetText.h中使用Generic,看看是否可以消除您依赖的地方完整的定义,例如。将聚合的Generic更改为Generic*或将访问Generic方法的内联成员移动到源文件中的外联定义中。