类的前向声明似乎在C ++中不起作用

时间:2009-12-11 02:29:51

标签: c++ header compilation declaration forward-declaration

以下代码在VC ++ 6中编译。我不明白为什么我收到以下代码的编译错误C2079: 'b' uses undefined class 'B'

B类来源

#include "B.h"

void B::SomeFunction()
{
}

B类标题

#include "A.h"

struct A;

class B
{
    public:
        A a;
        void SomeFunction();
};

struct A Header

#include "B.h"

class B;

struct A
{
    B b;
};

如果我将B类标题更改为以下内容,则不会出现错误。但标题声明不会在顶部!

带有奇怪标题声明的B类标题

struct A;

class B
{
     public:
        A a;
        void SomeFunction();
};

#include "A.h"

6 个答案:

答案 0 :(得分:16)

为了定义类或结构,编译器必须知道类的每个成员变量有多大。前瞻性声明不会这样做。我只看到它用于指针和(较少经常)引用。

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

答案 1 :(得分:4)

转发声明,例如

struct A;

class A;

将A作为不完整类型引入,并且在到达类型定义的结尾之前它仍然是不完整的。你可以用不完整的类型和你不能做的事情来做。你可以

  1. 声明“指向A的指针”和“引用A”
  2. 类型的变量(或成员)
  3. 声明带有类型A的参数或返回类型A
  4. 的函数

    你不能

    1. 声明类型为A
    2. 的变量(也不是成员)
    3. 取消引用指向A或访问A
    4. 的任何引用成员
    5. 定义A。
    6. 的子类

      在您的代码中,您尝试声明不完整类型的struct成员。这是非法的。只允许指针和引用。

答案 2 :(得分:3)

public:
    A a;

您正在尝试仅使用前向声明创建A的对象。此时编译器(仅使用forward decl)无法决定对象A的大小,因此无法分配A所需的内存。因此,您无法创建仅具有前向decl的对象。

取而代之的是:

A* a;

没有A的类定义的指针或A的引用将正常工作。

答案 3 :(得分:2)

这里有两个问题突然出现在我身上。

1:您已经写过Struct A而不是struct A;注意小写的“s”。您的编译器可能会考虑等效的,但我认为它不是标准的C ++。

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

答案 4 :(得分:0)

你还可以包括B.h的A.h和A.h.的B.h.您至少应该使用预处理器宏:

#ifndef __A_H__
#define __A_H__

// A.h contents

#endif

这样该文件不会被包含多次。

答案 5 :(得分:0)

如果你创建一个A的实例,它将创建一个B(成员var)的实例,它将创建一个A(成员var)的实例,它将创建一个B的实例,它将创建一个A的实例,依此类推... 编译器不应该允许这样做,因为它需要无限的内存。

要解决此问题,A或B必须使用指向另一个类的引用/指针。