类的前向声明似乎不适用于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" 
+0

你可以把它们放在同一个头文件?我知道这不是一个特别技术性的答案,但如果可行的话,你可以通过这样做来避免整个事情的发生。 – ihtkwot 2009-12-11 02:34:18

+0

如果将两个类定义放在同一个头文件中,则无关紧要,但仍然必须先找到并且无法知道其他类的大小。 – Peter 2009-12-11 02:58:17

+0

感谢您的澄清,我在这方面还是很新的,希望我没有提供不好的建议,我是 – ihtkwot 2009-12-11 04:12:01

为了定义一个类或结构体,编译器必须知道该类的每个成员变量有多大。前向声明不会这样做。我只见过它用于指针和(不太常见的)引用。

除此之外,你在这里试图做的事情是无法完成的。你不能有一个包含另一个类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) { } 
}; 
+5

双下划线是为编译器保留的。使用不同的命名约定。 – GManNickG 2009-12-11 03:11:32

+0

@GMan:当编译器不自动生成它时,我总是使用这个约定来处理我的幂等标记。这是特定于编译器还是C++规范? – 2009-12-11 03:31:01

+1

@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++。

您已在AB之间定义了一个循环参考。每个A对象都必须包含一个B对象,但每个B对象都必须包含一个A对象!这是一个矛盾,并且永远不会按照你想要的方式工作。解决该问题的常用C++方法是使用A::bB::a(或两者)的指针或引用。

您还包括A.h和B.h和B.h来自A.h.您至少应该使用预处理器宏:

#ifndef __A_H__ 
#define __A_H__ 

// A.h contents 

#endif 

这样文件将不会包含多次。

+0

在实际代码中,预处理器宏被定义,但这里没有显示使代码更简单。 – Lopper 2009-12-11 02:48:43

+0

双下划线是为编译器保留的。使用不同的命名约定。 – GManNickG 2009-12-11 03:10:52

如果创建A的一个实例,将创建B(构件VAR),这将创造A(构件VAR)的一个实例的一个实例,这将创造B的一个实例,这将创造A等的一个实例上... ,因为它需要无限的内存编译器应该不允许这样做。

为了解决这个问题,A或B必须使用参考/指针其他类。

前向声明,像

struct A; 

class A; 

引入作为不完全类型并且当达到类型的定义的结束,直到其处于不完整的。有些事情你可以用不完整的类型和你不能做的事情来做。可以

  1. 声明类型的变量(或成员)“指针A”和“参照”,这取类型A的参数或返回类型A

您可以

  • 声明函数“T

    1. 声明变量(也没有成员)类型的
    2. 解除引用指针A或访问引用的任何成员甲
    3. 定义A.

    的子类在你的代码试图声明不完整的类型的结构成员。这是非法的。只允许指针和引用。