Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 类的前向声明不';t似乎在C+中工作+;_C++_Header_Compilation_Declaration_Forward Declaration - Fatal编程技术网

C++ 类的前向声明不';t似乎在C+中工作+;

C++ 类的前向声明不';t似乎在C+中工作+;,c++,header,compilation,declaration,forward-declaration,C++,Header,Compilation,Declaration,Forward Declaration,下面的代码是在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(); }; #include "B.h" class B; struct A { B b;

下面的代码是在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();
};
#include "B.h"

class B;

struct A
{
    B b;
};
构造一个标题

#include "A.h"

struct A;

class B
{
    public:
        A a;
        void SomeFunction();
};
#include "B.h"

class B;

struct A
{
    B b;
};
如果我将class B头更改为以下内容,则不会出现错误。但是标题声明不会在顶部

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

struct A;

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

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

替换为:

A* a;

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

这里有两个问题向我提出

1:您编写了
Struct A
,而不是
Struct A
;请注意小写字母“s”。编译器可能会考虑等价的,但我不认为它是标准的C++。
您已经定义了
a
B
之间的循环引用。每个A对象必须包含一个
B
对象,但每个
B
对象必须包含一个
A
对象!这是一个矛盾,永远不会按你希望的方式工作。解决这个问题的常用C++方法是使用指针或引用,用于<代码>:::b>代码>或<代码> b::a < /> >(或两者).< /p> < p>为了定义类或结构,编译器必须知道类的每个成员变量有多大。转发声明不能做到这一点。我只见过它用于指针和(不太常见的)引用

除此之外,你在这里试图做的事是做不到的。您不能让类a包含另一个类B的对象,该类B包含类a的对象。但是,您可以让类a包含指向包含类a对象的类B的指针

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

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

#ifndef __A_H__
#define __A_H__

// A.h contents

#endif

因此,该文件不会包含多次。

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


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

转发声明,如

struct A;

将A作为不完整的类型引入,它将保持不完整,直到到达类型定义的结尾。有些事情你可以用不完整的类型做,有些事情你做不到。你可以

  • 声明类型为“指向A的指针”和“指向A的引用”的变量(或成员)
  • 声明接受类型A或返回类型A的参数的函数
  • 你不能

  • 声明类型A的变量(或成员)
  • 取消对的引用指针或访问对的引用的任何成员
  • 定义A的子类

  • 在代码中,您试图声明类型不完整的结构成员。这是违法的。只允许使用指针和引用。

    在实际代码中,定义了预处理器宏,但此处未显示以简化代码。双下划线保留给编译器。使用不同的命名约定。双下划线是为编译器保留的。使用不同的命名约定。@GMan:当编译器没有自动生成幂等标记时,我总是使用这种约定来表示幂等标记。这是特定于编译器还是在C++规范中?@ Matt,它是C++标识符的一部分,这样的标识符被保留。我个人使用“HEADER_PATH_TO_HEADER_H_INCLUDED”或“HEADER_PATH_TO_HEADER_INCLUDED”(如果没有“.H”)。你能把它们放在同一个头文件中吗?我知道这不是一个特别技术性的答案,但如果可行的话,你可以通过这样做来避免整个问题。如果你将两个类定义放在同一个头文件中,那没关系,其中一个仍然必须放在第一位,并且无法知道另一个类的大小。谢谢你的澄清,我在这方面还是个新手,希望我没有提供不好的建议,我是这样的