简体   繁体   English

C ++在类中转发声明类

[英]C++ Forward Declaring Classes Within Classes

The following simple piece of code compiles, although I don't understand why: 以下简单的代码编译,虽然我不明白为什么:

class C {
    class B;

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

    class B {
    };
};

int main(int, char**)
{
    return 0;
}

If I then comment out the " class C " stuff, so that the forward declaration of B , the definition of A and the definition of B are no longer nested within a class, the code does not compile, since B is of an incomplete type: 如果我然后注释掉“ 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'

I understand what it means for a type to be incomplete, namely that it has not been defined yet and so the compiler can't possibly know how much space to allocate for it. 我理解一个类型不完整的含义,即它尚未定义,因此编译器不可能知道为它分配多少空间。 But why is B not considered incomplete in the code above, where A and B are both declared and defined inside of C ? 但是为什么在上面的代码中B不被认为是不完整的,其中AB都是在C声明和定义的?

I believe this is a consequence of [basic.scope.class] : 我相信这是[basic.scope.class]的结果

The potential scope of a name declared in a class consists not only of the declarative region following the name's point of declaration, but also of all function bodies, default arguments, exception-specifications , and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes). 在类中声明的名称的潜在范围不仅包括名称的声明点后面的声明性区域,还包括所有函数体,默认参数, 异常规范和非静态的括号或等于初始化器 。该类中的数据成员(包括嵌套类中的这些内容)。

That is, the scope of the full declaration of B includes the body of the member function of the nested 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)
    };
};

By comparison, if C were a namespace instead of a class, the scope of the full declaration of class B would not extend into A::getB() . 相比之下,如果C是命名空间而不是类,则类B的完整声明的范围不会扩展到A::getB() The only visible declaration would be the forward-declaration of B that I labeled (1) - so B() would be the construction of an incomplete type there. 唯一可见的声明是我标记为(1)B的前向声明 - 所以B()将在那里构造一个不完整的类型。

The body of an inline member function is not processed until the class definition has been fully processed. 在完全处理类定义之前,不会处理内联成员函数的主体。

Hence, you can use: 因此,您可以使用:

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

   class B {};
};

That also allows member variables that are not yet declared to be used in inline member function definition. 这也允许在内联成员函数定义中使用尚未声明的成员变量。

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

   int bar;
};

I am guessing the same logic is extended to inline definitions of member functions of nested classes -- ie they are not processed until the containing class definition is completely processed. 我猜测相同的逻辑扩展到嵌套类的成员函数的内联定义 - 即在完全处理包含类定义之前不会处理它们。

PS I am unable to quickly locate the reference in the standard that would verify my claim. PS我无法快速找到标准中的参考资料来验证我的索赔。

PS 2 The answer by Barry has the reference in the standard that makes the code in the question valid. PS 2 Barry的答案在标准中提供了使问题中的代码有效的参考。

The standard is explicit in mandating that the method's body is interpreted after the class that encloses it. 标准明确规定方法的主体在包含它的类之后被解释。

Thus at the time of evaluating the body of C::A::getB() , A , B and C are all complete types. 因此,在评估C::A::getB()的主体时, ABC都是完整的类型。

Besides that when I've got the need to forward declare nested classes I tend to smell some bad design in my code, the trick I use is: 除此之外,当我需要转发声明嵌套类时,我倾向于在我的代码中闻到一些糟糕的设计,我使用的技巧是:

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


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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM