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

发布于 2024-08-14 18:27:36 字数 655 浏览 5 评论 0原文

以下代码是在VC++6中编译的。我不明白为什么我在以下代码中收到编译错误 C2079: 'b' 使用未定义的类 'B'

B 类源

#include "B.h"

void B::SomeFunction()
{
}

B 类标头

#include "A.h"

struct A;

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

struct A 标头

#include "B.h"

class B;

struct A
{
    B b;
};

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

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

struct A;

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

#include "A.h"

The follwing code is compiled in VC++6. I don't understand why I am getting the compilation error C2079: 'b' uses undefined class 'B' for the following code.

Class B Source

#include "B.h"

void B::SomeFunction()
{
}

Class B Header

#include "A.h"

struct A;

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

struct A Header

#include "B.h"

class B;

struct A
{
    B b;
};

If I changed class B header to the following, then there will be no error. But the header declaration won't be at the top!

Class B Header with weird header declaration

struct A;

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

#include "A.h"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

夜唯美灬不弃 2024-08-21 18:27:36

为了定义一个类或结构,编译器必须知道该类的每个成员变量有多大。前向声明不会执行此操作。我只见过它用于指针和(较少)引用。

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

B.cpp

#include "B.h"

void B::SomeFunction()
{
}

Bh

#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) { }
};

In order to define a class or struct, the compiler has to know how big each member variable of the class is. A forward declaration does not do this. I've only ever seen it used for pointers and (less often) references.

Beyond that, what you're trying to do here cannot be done. You cannot have a class A that contains an object of another class B that contains an object of class A. You can, however, have class A contain a pointer to class B that contains an object of class 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__

Two points. First, be sure to use some form of idempotence to keep the headers from being included multiple times per compilation unit. Second, understand that in C++, the only difference between classes and structs is the default visibility level - classes use private visibility by default while structs use public visibility by default. The following definitions are functionally equivalent in C++.

class MyClass
{
public: // classes use private visibility by default
    int i;
    MyClass() : i(13) { }
};

struct MyStruct
{
    int i;
    MyStruct() : i(13) { }
};
如歌彻婉言 2024-08-21 18:27:36

前向声明,例如

struct A;

class A;

将 A 作为不完整类型引入,并且在到达类型定义末尾之前它保持不完整状态。对于不完整的类型,有些事情可以做,有些事情不能做。您可以

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

您不能

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

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

Forward declarations, like

struct A;

or

class A;

Introduce A as an incomplete type and it remains incomplete until end of type's definition is reached. There are things you can do with incomplete types and things you can't. You can

  1. Declare variables (or members) of type "pointer to A" and "reference to A"
  2. Declare functions which take arguments of type A or return type A

You can't

  1. Declare variables (nor members) of type A
  2. Dereference pointers to A or access any members of references to A
  3. Define subclasses of A.

In your code you try to declare struct member of incomplete type. It's illegal. Only pointers and references are allowed.

花开雨落又逢春i 2024-08-21 18:27:36
public:
    A a;

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

相反,替换为:

A* a;

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

public:
    A a;

You are trying to create the object of A with only forward declaration. Compiler at this moment ( with only forward decl) cannot decide the size of the object A and hence, it cannot allocate memory required for A. So you cannot create objects with only forward decl.

Instead replace with:

A* a;

Pointer or reference to A without A's class definition will work fine.

殤城〤 2024-08-21 18:27:36

这里有两个问题引起了我的注意。

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

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

Two issues jump out at me here.

1: You've written Struct A instead of struct A; note the lower-case "s". Your compiler might consider the equivalent, but I don't think it's standard C++.

You have defined a circular reference between A and B. Each A object must contain a B object, but each B object must contain an A object! This is a contradiction, and will never work the way you want it to. The usual C++ way to solve that problem is to use pointers or references for A::b or B::a (or both).

絕版丫頭 2024-08-21 18:27:36

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

#ifndef __A_H__
#define __A_H__

// A.h contents

#endif

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

You alse include A.h from B.h and B.h from A.h. You should at least use preprocessor macros:

#ifndef __A_H__
#define __A_H__

// A.h contents

#endif

so that file won't be included more than once.

是伱的 2024-08-21 18:27:36

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

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

If you create an instance of A, that will create an instance of B (member var) which will create an instance of A (member var) which will create an instance of B which will create an instance of A and so on...
The compiler should not allow this since it requires infinite memory.

To solve this, either A or B must use a reference/pointer to the other class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文