13

我想知道为什么 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。

为什么这行得通,而且大多数情况下,为什么只班级内有效?

4

4 回答 4

8

这是因为成员函数只有在编译器解析了整个类定义后才会编译,即使函数定义是内联编写的,而常规函数在读取后立即编译。C++ 标准需要这种行为。

于 2010-10-30T20:17:09.250 回答
8

好吧,为了迂腐,C++ 中没有“使用前声明规则”。名称查找的规则非常复杂,但可以(并且经常)粗略地简化为通用的“使用前声明规则”,但有一些例外。(在某种程度上,这种情况类似于“运算符优先级和关联性”规则。虽然语言规范没有这样的概念,但我们经常在实践中使用它们,尽管它们并不完全准确。)

这实际上是这些例外之一。C++ 中的成员函数定义被明确且有意地排除在“使用前声明规则”之外,从某种意义上说,从这些成员的主体中查找名称就像它们是在类定义之后定义的一样。

语言规范在 3.4.1/8(和脚注 30)中声明了这一点,尽管它使用了不同的措辞。它表示在从成员函数定义中查找名称期间,会检查整个类定义,而不仅仅是成员函数定义上方的部分。脚注 30 还指出,尽管在类定义内部或类定义外部定义的函数的查找规则是相同的(这几乎就是我上面所说的)。

你的例子有点不重要。它提出了关于嵌套类中成员函数定义的直接问题:是否应该将它们解释为好像它们是在定义最封闭的类之后定义的?答案是肯定的。3.4.1/8 也涵盖了这种情况。

“C++ 的设计与进化”一书描述了这些决定背后的原因。

于 2010-10-30T20:24:50.847 回答
3

我不知道这个标准的章节和经文。

但是如果你在一个类中严格应用“使用前声明”规则,你也不能在类声明的底部声明成员变量。您必须先声明它们,以便在构造函数初始化列表中使用它们。

我可以想象“使用前声明”规则在类声明中已经放宽了一点,以允许“更干净”的整体布局。

正如我所说,只是猜测。

于 2010-10-30T20:16:18.090 回答
1

C++ 定义中最顽固的问题与名称查找有关:名称的哪些用途指的是哪些声明?在这里,我将只描述一种查找问题:与类成员声明之间的顺序依赖关系有关的查找问题。[...]

由于目标之间的冲突而出现困难:

  1. 我们希望能够只阅读一次源文本进行语法分析。
  2. 对类的成员重新排序不应改变类的含义。
  3. 显式内联编写的成员函数体在非行内编写时应该具有相同的含义。
  4. 来自外部范围的名称应该可以在内部范围中使用(与在 C 中的方式相同)。
  5. 名称查找的规则应该独立于名称所指的内容。

如果所有这些都成立,则该语言的解析速度将相当快,并且用户不必担心这些规则,因为编译器会捕获模棱两可和近乎模棱两可的情况。目前的规则非常接近这个理想。

[C++ 的设计和演变,第 6.3.1 节称为查找问题,第 138 页]

于 2010-10-31T12:15:43.877 回答