为什么是“使用前声明”?类中不需要规则吗?
我想知道为什么 C++ 的“使用前声明”规则在类中不成立。
看这个例子:
#ifdef BASE
struct Base {
#endif
struct B;
struct A {
B *b;
A(){ b->foo(); }
};
struct B {
void foo() {}
};
#ifdef BASE
};
#endif
int main( ) { return 0; }
如果定义了 BASE,则代码有效。
在 A 的构造函数中,我可以使用尚未声明的 B::foo。
为什么这会起作用,而且最重要的是,为什么只在类中起作用?
I'm wondering why the declare-before-use rule of C++ doesn't hold inside a class.
Look at this example:
#ifdef BASE
struct Base {
#endif
struct B;
struct A {
B *b;
A(){ b->foo(); }
};
struct B {
void foo() {}
};
#ifdef BASE
};
#endif
int main( ) { return 0; }
If BASE is defined, the code is valid.
Within A's constructor I can use B::foo, which hasn't been declared yet.
Why does this work and, mostly, why only works inside a class?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,说句迂腐的话,C++ 中没有“使用前声明”规则。名称查找的规则非常复杂,但可以(并且通常)粗略地简化为通用的“使用前声明规则”,但有一些例外。 (在某种程度上,这种情况类似于“运算符优先级和结合性”规则。虽然语言规范没有这样的概念,但我们在实践中经常使用它们,尽管它们并不完全准确。)
这实际上是这些例外之一。 C++ 中的成员函数定义被明确且有意地排除在“使用前声明”规则之外,从某种意义上说,从这些成员的主体中执行名称查找就像它们是在类定义之后定义的一样。
语言规范在 3.4.1/8(和脚注 30)中指出了这一点,尽管它使用了不同的措辞。它表示,在从成员函数定义进行名称查找期间,将检查整个类定义,而不仅仅是成员函数定义上方的部分。脚注 30 还指出,对于类定义内部或类定义外部定义的函数,查找规则是相同的(这与我上面所说的差不多)。
你的例子有点不简单。它提出了关于嵌套类中的成员函数定义的直接问题:它们是否应该被解释为好像它们是在最封闭的类的定义之后定义的?答案是肯定的。 3.4.1/8 也涵盖了这种情况。
《C++ 的设计与演化》一书描述了这些决定背后的推理。
Well, to be pedantic there's no "declare before use rule" in C++. There are rules of name lookup, which are pretty complicated, but which can be (and often are) roughly simplified into the generic "declare before use rule" with a number of exceptions. (In a way, the situation is similar to "operator precedence and associativity" rules. While the language specification has no such concepts, we often use them in practice, even though they are not entirely accurate.)
This is actually one of those exceptions. Member function definitions in C++ are specifically and intentionally excluded from that "declare before use rule" in a sense that name lookup from the bodies of these members is performed as if they are defined after the class definition.
The language specification states that in 3.4.1/8 (and footnote 30), although it uses a different wording. It says that during the name lookup from the member function definition, the entire class definition is inspected, not just the portion above the member function definition. Footnote 30 additionally states though that the lookup rules are the same for functions defined inside the class definition or outside the class definition (which is pretty much what I said above).
Your example is a bit non-trivial. It raises the immediate question about member function definitions in nested classes: should they be interpreted as if they are defined after the definition of the most enclosing class? The answer is yes. 3.4.1/8 covers this situation as well.
"Design & Evolution of C++" book describes the reasoning behind these decisions.
这是因为成员函数仅在编译器解析整个类定义后才进行编译,即使函数定义是内联编写的,而常规函数在读取后立即编译。 C++ 标准要求这种行为。
That's because member functions are compiled only after the whole class definition has been parsed by the compiler, even when the function definition is written inline, whereas regular functions are compiled immediatedly after being read. The C++ standard requires this behaviour.
我不知道该标准的章节和章节。
但是,如果您严格在类中应用“使用前声明”规则,则也无法在类声明的底部声明成员变量。您必须首先声明它们,以便在构造函数初始化列表中使用它们。
我可以想象“使用前声明”规则在类声明中已经放宽了一点,以允许“更干净”的整体布局。
正如我所说,只是猜测。
I don't know the chapter and verse of the standard on this.
But if you would apply the "declare before use" rule strictly within a class, you would not be able to declare member variables at the bottom of the class declaration either. You would have to declare them first, in order to use them e.g. in a constructor initialization list.
I could imagine the "declare before use" rule has been relaxed a bit within the class declaration to allow for "cleaner" overall layout.
Just guesswork, as I said.