13

以下代码在 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();
};

结构 A 标头

#include "B.h"

class B;

struct A
{
    B b;
};

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

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

struct A;

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

#include "A.h"
4

6 回答 6

20

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

除此之外,您在这里尝试做的事情无法完成。你不能让一个类 A 包含另一个类 B 的对象,而另一个类 B 的对象又包含一个类 A 的对象。但是,你可以让类 A 包含指向包含类 A对象的类 B的指针。

B.cpp

#include "B.h"

void B::SomeFunction()
{
}

溴化氢

#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__

#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) { }
};
于 2009-12-11T02:40:04.497 回答
4

前向声明,例如

struct A;

或者

class A;

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

  1. 声明类型为“pointer to A”和“reference to A”的变量(或成员)
  2. 声明接受类型 A 参数或返回类型 A 的函数

你不能

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

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

于 2009-12-11T08:52:54.907 回答
3
public:
    A a;

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

而是替换为:

A* a;

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

于 2009-12-11T02:34:15.727 回答
2

这里有两个问题跳出来。

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

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

于 2009-12-11T02:35:01.307 回答
0

您还包括来自 Bh 的 Ah 和来自 Ah 的 Bh 您至少应该使用预处理器宏:

#ifndef __A_H__
#define __A_H__

// A.h contents

#endif

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

于 2009-12-11T02:46:23.860 回答
0

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

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

于 2009-12-11T02:56:44.847 回答