C++类中向前声明类

C++ Forward Declaring Classes Within Classes

本文关键字:声明 C++      更新时间:2023-10-16
编译

了以下简单的代码段,尽管我不明白为什么:

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上面的代码中不被认为是不完整的,其中AB都是在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()体时,ABC都是完全类型。

除此之外,

当我需要转发声明嵌套类时,我往往会在我的代码中闻到一些糟糕的设计,我使用的技巧是:

// Foo.h
class Foo {
    class Bar {
    };
};
class Foobar : public Foo::Bar {};

// Zoo.h
/* Fwd declare */
class FooBar;