我想知道为什么C ++中的declare-before-use规则不能保存在类中。
看看这个例子:
#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。
为什么这样做,而且大多数情况下,为什么只能在里面一个类?
答案 0 :(得分:7)
这是因为只有在编译器解析了整个类定义之后才编译成员函数,即使函数定义是内联编写的,而常规函数在读取后立即编译。 C ++标准需要这种行为。
答案 1 :(得分:7)
好吧,要迂腐,在C ++中没有“使用前声明规则”。有名称查找的规则,它们非常复杂,但可以(并且经常)大致简化为通用的“使用前声明规则”,但有许多例外。 (在某种程度上,情况类似于“运算符优先级和关联性”规则。虽然语言规范没有这样的概念,但我们经常在实践中使用它们,即使它们并不完全准确。)
这实际上是其中一个例外。 C ++中的成员函数定义被明确地和有意地排除在“使用前声明规则”之外,在某种意义上,从这些成员的主体执行名称查找就像在类定义之后定义一样。
语言规范指出在3.4.1 / 8(和脚注30)中,虽然它使用了不同的措辞。它表示在从成员函数定义进行名称查找期间,将检查整个类定义,而不仅仅是成员函数定义上面的部分。脚注30另外指出,查找规则对于类定义中或类定义之外定义的函数是相同的(这与我上面所说的几乎相同)。
你的例子有点不重要。它提出了关于嵌套类中成员函数定义的直接问题:它们是否应该被解释为它们是在最封闭类的定义之后定义的?答案是肯定的。 3.4.1 / 8也涵盖了这种情况。
“C ++的设计与演变”一书描述了这些决策背后的原因。
答案 2 :(得分:3)
我不知道标准的章节和诗句。
但是如果你在一个类中严格地应用“使用前声明”规则,你就不能在类声明的底部声明成员变量。您必须先声明它们才能使用它们,例如在构造函数初始化列表中。
我可以想象“在使用前声明”规则已经在类声明中放宽了一点,以允许“更清洁”的整体布局。
正如我所说,只是猜测。
答案 3 :(得分:1)
C ++定义中最顽固的问题与名称查找有关:完全使用名称引用哪些声明?在这里,我将仅描述一种查找问题:与类成员声明之间的顺序依赖关系相关的问题。 [...]
由于目标之间的冲突而出现困难:
- 我们希望能够只读一次源文本的语法分析。
- 重新排序班级成员不应改变班级的含义。
- 明确写入内联的成员函数体在写出时应该表示相同的内容。
- 来自外部范围的名称应该可以从内部范围使用(与C中的名称相同)。
- 名称查找规则应独立于名称所指的内容。
醇>如果所有这些都成立,语言的解析速度将相当快,用户将不必担心这些规则,因为编译器将捕获模糊和近似模糊的情况。现行规则非常接近这一理想。
[C ++的设计和演变,第6.3.1节称为查找问题第138页]