C++类中向前声明类
C++ Forward Declaring Classes Within Classes
编译
了以下简单的代码段,尽管我不明白为什么:
class C {
class B;
class A {
B getB() { return B(); }
};
class B {
};
};
int main(int, char**)
{
return 0;
}
如果我注释掉"class C
"的东西,以便B
的前向声明,A
的定义和B
的定义不再嵌套在一个类中,代码不会编译,因为B
是不完整的类型:
main.cpp: In member function 'B A::getB()':
main.cpp:6: error: return type 'struct B' is incomplete
main.cpp:6: error: invalid use of incomplete type 'struct B'
main.cpp:3: error: forward declaration of 'struct B'
我理解类型不完整意味着什么,即它尚未定义,因此编译器不可能知道要为其分配多少空间。但是为什么B
上面的代码中不被认为是不完整的,其中A
和B
都是在C
中声明和定义的?
我相信这是[basic.scope.class]的结果:
在类中声明的名称的潜在作用域不仅包括 name 的声明点,以及该类中非静态数据成员的所有函数体、默认参数、异常规范和大括号或等于初始值设定项(包括嵌套中的此类内容) 类)。
也就是说,B
的完整声明的范围包括嵌套类的成员函数的主体:
class C {
class B; // (1)
class A {
B getB() {
return B(); // both (1) and (2) in scope here
// since (2) is the complete type declaration,
// this is perfectly fine
}
};
class B { // (2)
};
};
相比之下,如果C
是命名空间而不是类,则类B
的完整声明的范围不会扩展到A::getB()
。唯一可见的声明是我标记为(1)
的B
的前向声明 - 因此B()
那里将构造一个不完整的类型。
在
完全处理类定义之前,不会处理内联成员函数的主体。
因此,您可以使用:
class A
{
class B;
B getB() { return B(); }
class B {};
};
这也允许在内联成员函数定义中使用尚未声明的成员变量。
class Foo
{
int getBar() { return bar; }
int bar;
};
我猜同样的逻辑扩展到嵌套类的成员函数的内联定义——即在完全处理包含类定义之前不会处理它们。
PS 我无法在标准中快速找到可以验证我的声明的参考资料。
PS 2 Barry 的答案在标准中具有参考,使问题中的代码有效。
该标准明确要求在包含该方法的类之后解释方法的主体。
因此在评估C::A::getB()
体时,A
、B
和C
都是完全类型。
除此之外,
当我需要转发声明嵌套类时,我往往会在我的代码中闻到一些糟糕的设计,我使用的技巧是:
// Foo.h
class Foo {
class Bar {
};
};
class Foobar : public Foo::Bar {};
// Zoo.h
/* Fwd declare */
class FooBar;
相关文章:
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- #ifdef和未声明的标识符
- 没有显式声明的int[]中的foreach
- 在基于范围的for循环中使用结构化绑定声明
- 在将变量声明为引用时,堆在释放后使用
- C++:无法访问声明的受保护成员
- 为什么我不能在一个类的不同行中声明和定义成员变量?
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 使用cmake从源代码构建MySQL连接器/C++失败(与以前的声明冲突)
- 在函数内部的声明中初始化数组,并在外部使用它
- Visual Studio中的函数声明和函数定义问题
- c++类声明时,相同的例程,不同的成员变量类型
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别