不允许嵌套类的前向声明的原因?

Posted

技术标签:

【中文标题】不允许嵌套类的前向声明的原因?【英文标题】:Reason for not allowing forward declarations of nested class? 【发布时间】:2011-07-13 05:58:25 【问题描述】:

例子:

// can't forward declare with class Foo::Bar

// actual class
class Foo

public:
    class Bar // or enum Bar
    
    
;

我接受在当前 C++ 标准下这是不允许的,但我想不出一个很好的理由来不允许它,尤其是在 C++0x 中,我们现在能够转发声明枚举。我想一个反对它的论点是,如果我们转发声明嵌套类,结果证明它是私有的,那将是不允许的。但这与前向声明命名空间中的类,然后将其声明为外部类的嵌套类并没有太大区别。编译器会简单地给出一个错误(可能沿着先前声明的行的错误消息与此声明不匹配)。

那为什么真的不允许呢?

换句话说(James McNellis),“为什么类 Foo::Bar;不提供 Foo 或 Bar 的定义是不允许的?”

** 鉴于 C++ 标准委员会通过在 C++0x 中引入枚举的前向声明,认识到使用前向声明来减少依赖关系和编译时间的好处,这肯定是同一件事的一部分,不是吗?

【问题讨论】:

正如 eric lippert 在回答有关 C# 的这类问题时多次重申的那样,在没有充分理由的情况下不会将内容放入 C# 规范中。即使是看似很小的机会的影响也可能意味着极端情况、编译时间等方面的巨大差异,因此必须证明所加入的每个功能都是合理的,并且收益必须大于成本。而且,我要补充一点,没有“简单”的功能可以实现。 ;) @Zach:不,Eric Lippert 讨论了 C#。但同样的原因也适用于 C++。 @Ben:C#?哇,看看谁在说话。该语言中有很多极端情况会导致奇怪和意外的行为。如果这个 Eric 家伙实践他所宣扬的,C# 就不会像现在这样丰富和富有表现力。 -1 表示这个问题与其说是一个问题,不如说是表达你的不满,然后当人们试图回答你的问题时变得好斗的跳板。 *** 不是一个辩论论坛,它是一个寻求帮助和回答问题的地方。 @shelley:如果有人告诉你“这不可能”。你不想找出原因吗? 【参考方案1】:

它不在语言中的原因很简单,就是没有人提出如何将它包含在语言中的好建议。功能不包括自己,必须有人写出来并解释优点,并且没有(或非常小的)缺点。

不转发声明枚举 (enum x;) 的论点只是编译器无法为枚举变量选择正确的大小,直到它看到有多少值。通过允许决定编译器 (enum x : int;) 解决了这个问题。在进入标准之前,这也已实施并证明可以正常工作。

见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf

【讨论】:

【参考方案2】:

嵌套类肯定可以前向声明:

class Foo

public:
    class Bar;
;

class Foo::Bar

;

【讨论】:

是的,但第一个声明必须(与所有成员一样)在包含类定义中。我认为问题实际上是“为什么 class Foo::Bar; 不提供 FooBar 的定义是不允许的?” @James:这是一个不同的问题,答案是:“编译器如何知道Foo 应该是类还是命名空间?” @Zach:是的,但是编译器怎么知道 Foo 是一个类或命名空间?您还没有声明Foo,因此它可能是either 或者更经典的解决方案:class Foo::class Bar; 在单个 TU 中这无关紧要,因为 namespace x class x ; 的格式不正确,但在同一程序中的一个 TU 中可以有 namespace x class foo ; ,在第二个 TU 中可以有 class x class foo ; ;,并且这两个foo 实际上是不同的(这实际上可能违反了 ODR;我不认为它确实如此,但我不是 100% 确定并且肯定不会在真正的程序中按我的运气)。在任何情况下,如果这是有效的,那么xclass x::foo; 中的命名空间还是类确实很重要(除此之外,两个foo 肯定会有不同的重命名)。【参考方案3】:

你如何转发声明一个嵌套类?为此,您必须声明它嵌套的类。一旦你去:

class ClassName 

你已经开始了一个完整的班级声明。你不能部分声明一个类;它要么都在这里,要么都不在这里。那么如果必须完全声明外部类,那么向前声明内部类有什么好处呢?

唯一原因枚举直到现在不能被前向声明是因为它们的大小是由它们的枚举数决定的。这就是为什么你必须给它们一个明确的大小来转发声明它们。

【讨论】:

为什么必须声明它嵌套的类?在所有可能性中,您为什么选择一种无法转发声明嵌套类的语法? @Zach 看到了,我不是编译器或规范设计师,所以我不能告诉你。我只知道一个功能的好处必须超过它的成本,而且我实际上不认为你已经证明它有用,只是表明它可能是一个可能的构造。无论如何,*** 并不是真正有争议的地方;我只是试图回答你的问题。它可能没有被包括在内,因为它的用途有限,因此没有被考虑过,或者因为它的有用性在设计语言和编译器时没有被认为超过负面影响。故事结束。 @Zach:你证明什么都没有。内部类具有可疑的效用。您所做的只是表明有人可能想要转发声明它们。这并不能证明它有用 @shelley:这是允许的(见我的回答)。 @Nicol:我的证明 == C++ 标准委员会认识到前向声明枚举的好处,所以这是相同的一部分。嵌套类是否有用是另一回事。如果它没有用,为什么首先将它添加到 std 中(也许你应该证明 this 有用??)???

以上是关于不允许嵌套类的前向声明的原因?的主要内容,如果未能解决你的问题,请参考以下文章

类成员的前向类声明

C++ 类的前向声明的用法

人们想要使用嵌套类的原因是啥? [复制]

java 嵌套类

Java | 嵌套类(Nested Class)

没有前向声明的嵌套函数模板实例化可以在 GCC 上编译,但不能在 clang 上编译