为什么在课堂内不需要“使用前声明”规则? [重复]

问题描述 投票:12回答:4

这个问题在这里已有答案:

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

为什么这有效,而且大多数情况下,为什么只能在课堂上工作?

c++ class forward-declaration
4个回答
7
投票

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


7
投票

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

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

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

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

“C ++的设计和演变”一书描述了这些决策背后的原因。


3
投票

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

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

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

正如我所说,只是猜测。


1
投票

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

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

  1. 我们希望能够只读一次源文本的语法分析。
  2. 重新排序类的成员不应该改变类的含义。
  3. 明确写入内联的成员函数体在写出时应该表示相同的内容。
  4. 外部作用域中的名称应该可以从内部作用域使用(与C中的名称相同)。
  5. 名称查找的规则应该与名称所指的内容无关。

如果所有这些都成立,那么语言将被合理地快速解析,并且用户将不必担心这些规则,因为编译器将捕获模糊且近似模糊的情况。现行规则非常接近这一理想。

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

© www.soinside.com 2019 - 2024. All rights reserved.