伟大的 c++ 前向声明混乱
The great c++ forward declaration confusion
考虑我有一个类A和一个类B及其相应的标头:
A.H
#ifndef CLASS_A
#define CLASS_A
/* forward declare A */
class A;
/* includes */
#include "b.h"
/* define class A */
class A {
public:
A() : p_b(nullptr) {}
B *p_b;
};
#endif
B.H
#ifndef CLASS_B
#define CLASS_B
/* forward declare B */
class B;
/* includes */
#include "a.h"
/* define class B */
class B {
public:
B() : m_a() {}
A m_a;
};
#endif
这不起作用:
为了将 A 的实现编译成一个对象文件,我首先包含 a.h,它向前声明 A,然后包含 b.h,然后声明并定义 B。但是当定义 B 时,它不知道 A 的大小,因此不能将 A 的对象声明为 B 的成员。
然而,A 不需要知道 B 的大小,因为它只有一个指向 B 的指针,并且可以在 B 定义之前完全定义。因此,在将 B 用作成员之前,可以完全知道它的大小,并且完整的声明应该没问题。
常识告诉 a.c 文件应该始终如下所示:
#include "a.h"
[...]
我可以通过在 a.c 中包含 a.h 之前的 b.h 来实际解决问题吗?这是否违反了将实现文件的第一行包含在其标头中的某种神圣惯例?
您正在以向后的方式使用前向声明。代码应该看起来更像这样:
A.H
#ifndef CLASS_A
#define CLASS_A
/* forward declare B */
class B;
/* define class A */
class A {
public:
A() : p_b(nullptr) {}
B *p_b;
};
#endif
B.H
#ifndef CLASS_B
#define CLASS_B
#include "a.h"
/* define class B */
class B {
public:
B() : m_a() {}
A m_a;
};
#endif
a.h
不需要知道B
到底是什么,因为A
包含一个B*
指针,而不是一个B
对象。因此,a.h
根本不应该使用#include "b.h"
,而应该是前向声明B
。
b.h
确实需要知道A
实际上是什么,因为B
包含一个A
对象,而不是一个A*
指针。所以b.h
应该使用#include "a.h"
,它在定义A
之前已经向前声明了B
,然后b.h
完成定义B
。
然后,a.c
可以使用#include "a.h"
引入A
声明,以便完成实现的定义,并且仅当A
的方法需要访问B
的成员时,它才能使用#include "b.h"
。
让我们看看编译器在预处理器完成其操作后看到的内容:
/* forward declare A */
class A;
/* includes */
/* forward declare B */
class B;
/* includes */
/* define class B */
class B {
public:
B() : m_a() {}
A m_a;
};
/* define class A */
class A {
public:
A() : p_b(nullptr) {}
B *p_b;
};
如您所见,B
的类定义在完全定义之前A
,因此您的程序格式不正确。
在这里,你只需要一个前向声明(B
),它应该在A.h中A
的定义之前:
#ifndef CLASS_A
#define CLASS_A
// Forward declare B so that B* p_b is legal
class B;
// Note that B.h is *not* included here
class A {
public:
A() : p_b(nullptr) {}
B *p_b;
};
#endif
在这里,您可以通过向前声明B
而不是包含B
的完整定义来打破循环包含循环。 大概在 A 中.cpp您将#include
B
的完整定义,以便您可以使用其成员。
由于每个类都依赖于另一个类,因此这两个类应在同一头文件(和同一命名空间)中定义。 如果由于某种原因它们必须位于不同的头文件中,这将起作用。
啊
#ifndef CLASS_A
#define CLASS_A
class B;
class A {
public:
A() : p_b(nullptr) {}
B *p_b;
};
#endif
B.h
#ifndef CLASS_B
#define CLASS_B
#include "a.h"
class B {
public:
B() : m_a() {}
A m_a;
};
#endif
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- #ifdef和未声明的标识符
- 没有显式声明的int[]中的foreach
- 在基于范围的for循环中使用结构化绑定声明
- 在将变量声明为引用时,堆在释放后使用
- C++:无法访问声明的受保护成员
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 伟大的 c++ 前向声明混乱
- 关于C 的声明和定义之间的差异的混乱
- 正向声明混乱
- C++转发声明混乱
- C++对象声明混乱
- 为什么声明出现在一个混乱的符号名中