我的程序越大,我就会遇到问题。例如,我收到以下错误:
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'的一行必须放在那里,因为早期的问题与此类似。我假设当前这个问题有类似的解决方案,但到目前为止我找不到它。
答案 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
方法的内联成员移动到源文件中的外联定义中。