【问题标题】:C++ class, its base class and circular include includes [duplicate]C ++类,其基类和循环包含包括[重复]
【发布时间】:2010-12-11 22:09:57
【问题描述】:

文件 #1 (foo.h):

#ifndef FOO_H_
#define FOO_H_
#include "baseclass.h"
#include "bar.h"
class Bar;
class Foo : public baseclass {
public:
bar *varBar;
};
#endif

文件 #2 (bar.h):

#ifndef BAR_H_
#define BAR_H_
#include "foo.h"
class Foo;
class Bar {
public:
Foo *varFoo;
};
#endif

文件 #3 (baseclass.h):

#ifndef BASECLASS_H_
#define BASECLASS_H_
#include "foo.h"
class Foo;
class baseclass {
public:
list<Foo*> L;
};
#endif

但我在class Foo : public baseclass 行的文件#1 中遇到编译错误:

Error: expected class-name before »{« token

如果我添加class baseclass; bevor 类声明,我会收到此错误:

Error: invalid use of incomplete type »struct baseclass«

所以我的问题是,如何使用基类解决循环依赖关系?

问你是否没有得到某个点。我已经尝试更改包含标题的顺序,但到目前为止还没有运气。 感谢您的任何提示。

编辑:注意:我正在使用包含警卫 EDIT2:它不限于指针,所以我删除它们,以防万一。 EDIT3:添加了基类(忘记了 O.o) EDIT4:现在应该很清楚并且没有任何缺陷,此代码仍然存在问题。

【问题讨论】:

  • 基类是模板类吗?
  • EDIT: Note: I am using include guards: 我们在你的例子中没有看到它们,你能详细说明一下吗?
  • 你需要清理你的代码。您现在拥有的代码在问题的上下文中毫无意义,因为它根本没有以任何方式与问题相关联。您没有“与基类的循环依赖”。再一次,您的 baseclass 仅被提及一次,因此它不能参与循环依赖。编译所需的只是提供baseclass 的定义(可能应该在baseclass.h 中,但我们看不到它),并修复一些拼写错误。
  • 我会添加它,.. sry,hwo 愚蠢.. 只是忘了它。
  • 就循环依赖而言,它们已经 [几乎] 在您的代码中通过类声明解决了,只是您忘记删除实际的 #include 圆圈。从foo.h 中删除#include "bar.h" 或从`bar.h' 中删除#include "foo.h"

标签: c++ include


【解决方案1】:

通常的方法是在头文件周围添加以下内容:

#ifndef FOO_H_
#define FOO_H_
#include "baseclass.h"
#include "bar.h"
class Bar;
class Foo : public baseclass {
public:
bar *varBar;
};
#endif

#ifndef BAR_H_
#define BAR_H_
#include "foo.h"
class Foo;
class Bar {
public:
Foo *varFoo;
};
#endif

大多数编译器(gcc、VC)也接受文件开头的#pragma once,但我很确定它不是当前 C++ 标准的一部分。


编辑:

果然,正如 ISO/IEC 14882 所述,#pragma "causes the implementation to behave in an implementation-defined manner. Any pragma that is not recognized by the implementation is ignored."

目前C++0x还是一样。

所以我会坚持第一种老式的做法;-)

【讨论】:

  • 需要在#ifndef后面定义定义。
  • 您说的完全正确,谢谢!我太傻了……现在已经修好了。
  • 我很喜欢用这个,但它并不能解决问题
  • 好吧,你应该把它放在首位,因为它很容易误导......
【解决方案2】:

您似乎发布的是在Foo 中有一个Bar 成员,在Bar 中有一个Foo 成员。这是你需要打破的循环依赖——如果每个 Foo 包含一个 Bar ,其中包含一个 Foo ,那么构造要么永远不会终止。

class Foo : public baseclass {
    public:
        Bar varBar;
};

class Bar {
    public:
        Foo varFoo;
};

您需要在其中至少一个中使用指向FooBar 的指针或引用:

class Bar;
class Foo : public baseclass {
    public:
        Bar& varBar;
};

class Bar {
    public:
        Foo varFoo;
};

由于循环被破坏并且您只使用对对象的引用,因此您不需要拥有被引用类型的完整定义,并且可以使用前向声明。

包含守卫对用户有好处,但在开发时尽量不要依赖它们。如果编译器必须检查是否包含某些内容,即使它对守卫/编译指示进行了优化,它仍然可以工作。您确实需要了解什么取决于打破初始循环的因素,而对文件进行保护对您没有帮助。

【讨论】:

  • 即使它们都是指针,它仍然会中断。感谢您注意到这一点。
  • 我想我有一个混乱的 makefile -.- 感谢您指出这些事情,清理我的 makefiele 后我会有一个干净的外观。
  • @Pete:做得好,+1 表示比标题依赖项看得更远。
  • +1 - 但我不确定我是否理解包含守卫的意义。它们几乎需要出现在每个头文件中——只有少数奇怪的例外。
  • 如果你明白什么取决于什么,他们就不需要任何包含警卫。它们只有在您不假思索地包含两次时才会产生效果,这可能发生在第三方代码中,但不应该发生在您自己的代码中。
【解决方案3】:

您的标题中是否包含保护措施?上面的代码递归地包含了 a.h 和 b.h,从而定义了一大堆头文件。

前向声明 class b; 消除了 FILE1 中对 #include "b.h" 的需求。同样,#include "a.h" 应该从 FILE2 中删除。

【讨论】:

  • 更好的是,只需使用“#pragma once”指令
  • #pragma once 仅适用于 MSVCC。其他 C++ 编译器不支持。
  • 我有警卫,没有编译指示
  • //#include "Foo.h" class Foo;向我抛出这个错误:错误:不完整类型的无效使用»struct Foo«
  • @BillyONeal:它也适用于 gcc 以及 iirc
【解决方案4】:
#ifndef _BAR_H_
#define _BAR_H_    
#include "baseclass.h"

class Bar;
class Foo : public baseclass {
public:
    Bar *varBar;
};

#endif

如果一个类是前向声明的,并且您只使用一个指针或对该类成员的引用,那么您不需要包含它的标题。另一个文件中的类也是如此。但是,是的,请确保在所有头文件 (#ifndef...#endif) 中使用包含保护,以防止在编译期间多次包含头文件。

【讨论】:

  • +1 这就是前向声明类和打破循环依赖的全部意义所在。 - 但是,请避免以下划线开头的标识符(后跟大写字母)
【解决方案5】:

baseclass.h 不需要 foo.h 中的任何内容,因此请从 baseclass.h 中删除 #include "foo.h"

您的Bar 中有一个Foo 变量,Foo 中有一个Bar。那是行不通的:你不能在盒子里放鸡蛋在鸡蛋里放盒子。其中一个或两个都应该是指针。

【讨论】:

  • 基类包含一个 Foo 指针列表。所以我认为它需要包含 Foo。
猜你喜欢
  • 1970-01-01
  • 2012-08-11
  • 2011-06-08
  • 2022-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-25
相关资源
最近更新 更多