为什么嵌套类不能有一个成员,其类型是封闭类之一?

时间:2013-12-28 14:27:56

标签: c++ nested inner-classes

C的一种方法需要返回包含一对整数和struct的新实例的C。它可能看起来很尴尬,但考虑到整体设计,这很有意义(想想一个Waveform类将一系列自身作为副本返回,并指示范围的开始和结束位置。)

问题是似乎不允许这样做。我可以重新设计我的课程以避免这个问题,但是你可以解释一下为什么,从编译器的角度来看,这是不可能做到的

struct S {
    struct S2 {
        S s;
    };
};

因为S是一个不完整的类型(这是编译器错误),相反,这是完全正常的

struct C {
    struct C1 {
        C makeC() { return C(); }
    };
};

哪里有实质性差异?

5 个答案:

答案 0 :(得分:5)

在您尝试定义S::S2时,类型S仍然是不完整类型,因为其定义尚未完成。类数据成员必须具有完整的类型。

您可以像这样轻松修复:

struct S
{
    struct S2;   // declare only, don't define

    // ...
};

struct S::S2
{
    S s;         // now "S" is a complete type
};

C ++的设计决定本质上是在完成定义之前不考虑类型完成。这可以防止许多病态情况,如下例所示:

struct X
{
    struct Y { X a; };

    int b[sizeof(Y)];      // "sizeof" requires a complete type
};

答案 1 :(得分:2)

如果要定义类,则需要完整定义所有嵌入(非引用和非指针)成员。在定义类时,类没有完全定义。也就是说,在类定义中,定义下的类只是声明,而不是定义。

也就是说,您仍然可以在嵌套类中拥有类的成员。您只需在定义外部类后定义嵌套类:

struct S {
    struct S2;
};

struct S::S2 {
    S s;
};

由于S完全由第一个右大括号定义,因此在此之后它可以用作嵌入式成员。

在类定义中定义成员函数时,定义将被解析,就好像它出现在最接近的命名空间级别的类定义之后。也就是说,成员函数定义知道完全定义的类。这同样适用于嵌套类。

答案 2 :(得分:1)

我不确切知道为什么,但我可以推测这个反例:

struct S {
    struct S2 {
        S s;
    };
    S2 s2;
};

在这种情况下,尝试扫描S并在扫描S2之前确定其大小将失败。我怀疑递归可能会给编译器带来困难,而这些困难往往是标准中规则的原因。

那就是说,我认为你的解决方案不适合你所描述的问题。我会在S2上设置S模板,而不是嵌套。然后我可以使用引用S&作为模板参数,而不是S本身。因此,范围将由两个整数和对原始数组对象的引用表示。从这个范围制作一个新的副本将是一个单独的操作。

答案 3 :(得分:0)

编译器无法计算所包含类的大小。

你可以写S* s;

答案 4 :(得分:0)

这个答案主要关注两个例子之间的差异,因为其他答案已经解释了为什么第一个例子不起作用。

简而言之,您的第一个示例使用S中的S,其方式需要S完成。

您的第二个示例需要在编译函数体后立即完成C。您的代码等同于

struct C {
    struct C1 {
        C makeC();
    };
};

inline C C::C1::makeC() {
    return C();
}

这意味着,编译器会自动“推迟”函数体。对于函数声明,编译器只需知道C是一种类型,但如果C不完整,那么它就可以工作了。在编译函数定义时,类型C现已完成。