C++在类中转发声明类

vil*_*apx 17 c++

以下简单的代码编译,虽然我不明白为什么:

class C {
    class B;

    class A {
        B getB() { return B(); }
    };

    class B {
    };
};

int main(int, char**)
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我然后注释掉" 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'
Run Code Online (Sandbox Code Playgroud)

我理解一个类型不完整的含义,即它尚未定义,因此编译器不可能知道为它分配多少空间.但是为什么B在上面的代码中不被认为是不完整的,在哪里AB都被声明和定义C

Bar*_*rry 10

我相信这是[basic.scope.class]的结果:

在类中声明的名称的潜在范围不仅包括名称的声明点后面的声明性区域,还包括所有函数体,默认参数,异常规范和非静态的括号或等于初始化器.该类中的数据成员(包括嵌套类中的这些内容).

也就是说,完整声明的范围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)
    };
};
Run Code Online (Sandbox Code Playgroud)

相比之下,如果C是命名空间而不是类,则类的完整声明的范围B将不会延伸到A::getB().唯一可见的声明是B我标记的前向声明(1)- 所以B()那里将建造一个不完整的类型.


R S*_*ahu 9

在完全处理类定义之前,不会处理内联成员函数的主体.

因此,您可以使用:

class A 
{
   class B;
   B getB() { return B(); }

   class B {};
};
Run Code Online (Sandbox Code Playgroud)

这也允许在内联成员函数定义中使用尚未声明的成员变量.

class Foo
{
   int getBar() { return bar; }

   int bar;
};
Run Code Online (Sandbox Code Playgroud)

我猜测相同的逻辑扩展到嵌套类的成员函数的内联定义 - 即在完全处理包含类定义之前不会处理它们.

PS我无法快速找到标准中的参考资料来验证我的索赔.

PS 2 Barry的答案在标准中提供了使问题中的代码有效的参考.


Ric*_*ges 5

标准明确规定方法的主体在包含它的类之后被解释.

因此,在评估的主体时C::A::getB(),A,BC都是完全类型.