类的前向声明似乎不适用于C++
以下代码是在VC++ 6中编译的。我不明白为什么我得到编译错误C2079: 'b' uses undefined class 'B'
下面的代码。类的前向声明似乎不适用于C++
B类源
#include "B.h"
void B::SomeFunction()
{
}
B类部首
#include "A.h"
struct A;
class B
{
public:
A a;
void SomeFunction();
};
STRUCT甲部首
#include "B.h"
class B;
struct A
{
B b;
};
我f我将B类标题更改为以下内容,则不会有错误。但标题声明不会位于顶部!
B类标题怪异头部声明
struct A;
class B
{
public:
A a;
void SomeFunction();
};
#include "A.h"
为了定义一个类或结构体,编译器必须知道该类的每个成员变量有多大。前向声明不会这样做。我只见过它用于指针和(不太常见的)引用。
除此之外,你在这里试图做的事情是无法完成的。你不能有一个包含另一个类B的对象包含A级的对象 A类你可以,然而,有A类包含一个指针 B类包含一个对象 A级。
B.CPP
#include "B.h"
void B::SomeFunction()
{
}
B.h
#ifndef __B_h__ // idempotence - keep header from being included multiple times
#define __B_h__
#include "A.h"
class B
{
public:
A a;
void SomeFunction();
};
#endif // __B_h__
A.H
#ifndef __A_h__ // idempotence - keep header from being included multiple times
#define __A_h__
#include "B.h"
class B; // forward declaration
struct A
{
B *b; // use a pointer here, not an object
};
#endif // __A_h__
两点。首先,一定要使用某种形式的幂等,以保持头被包含每编译单元多次。其次,要明白在C++中类和结构之间的唯一区别是默认的公开程度 - 类默认使用私人能见度,同时结构默认使用的公共知名度。以下定义在C++中在功能上等同。
class MyClass
{
public: // classes use private visibility by default
int i;
MyClass() : i(13) { }
};
struct MyStruct
{
int i;
MyStruct() : i(13) { }
};
双下划线是为编译器保留的。使用不同的命名约定。 – GManNickG 2009-12-11 03:11:32
@GMan:当编译器不自动生成它时,我总是使用这个约定来处理我的幂等标记。这是特定于编译器还是C++规范? – 2009-12-11 03:31:01
@Matt,它是C++规范的一部分,这些标识符是保留的。我个人使用“HEADER_PATH_TO_HEADER_H_INCLUDED”或“HEADER_PATH_TO_HEADER_INCLUDED”(如果没有“.h”)。 – 2009-12-11 05:52:04
public:
A a;
您正在尝试只进行前向申报创建一个对象。这时编译器(只有正向decl)不能决定对象A的大小,因此它不能分配A所需的内存。所以你不能创建只有正向decl的对象。
与相反取代:
A* a;
指针或引用一个不带A的类定义将正常工作。
有两个问题在我这里跳出来。你写过Struct A
而不是struct A
;注意小写字母“s”。您的编译器可能会考虑等效,但我不认为它是标准的C++。
您已在A
和B
之间定义了一个循环参考。每个A对象都必须包含一个B
对象,但每个B
对象都必须包含一个A
对象!这是一个矛盾,并且永远不会按照你想要的方式工作。解决该问题的常用C++方法是使用A::b
或B::a
(或两者)的指针或引用。
如果创建A的一个实例,将创建B(构件VAR),这将创造A(构件VAR)的一个实例的一个实例,这将创造B的一个实例,这将创造A等的一个实例上... ,因为它需要无限的内存编译器应该不允许这样做。
为了解决这个问题,A或B必须使用参考/指针其他类。
前向声明,像
struct A;
或
class A;
引入作为不完全类型并且当达到类型的定义的结束,直到其处于不完整的。有些事情你可以用不完整的类型和你不能做的事情来做。可以
- 声明类型的变量(或成员)“指针A”和“参照”,这取类型A的参数或返回类型A
您可以
- 声明变量(也没有成员)类型的
- 解除引用指针A或访问引用的任何成员甲
- 定义A.
的子类在你的代码试图声明不完整的类型的结构成员。这是非法的。只允许指针和引用。
你可以把它们放在同一个头文件?我知道这不是一个特别技术性的答案,但如果可行的话,你可以通过这样做来避免整个事情的发生。 – ihtkwot 2009-12-11 02:34:18
如果将两个类定义放在同一个头文件中,则无关紧要,但仍然必须先找到并且无法知道其他类的大小。 – Peter 2009-12-11 02:58:17
感谢您的澄清,我在这方面还是很新的,希望我没有提供不好的建议,我是 – ihtkwot 2009-12-11 04:12:01