22

所以我在学习课程时,偶然发现了一些我觉得很尴尬的东西。

class Nebla 
{
    public:
        int test()
        {
            printout();
            return x;
        }

        void printout()
        {
            printout2();
        }

    private:
        int x,y;
        void printout2()
        {
            cout<<"Testing my class";
        }
};

我发现在一个类中我可以在声明它们之前使用函数(原型它们)

你可以看到我在 decleration 之前printout()使用过。printout2()

我也可以在声明变量之前使用它们

你可以看到我做到了return x;在声明 x 之前。

为什么我可以在声明之前在类中使用函数和变量,但在类之外使用函数和变量,如果这样做会出错?

谢谢

4

4 回答 4

24

好问题; 我多年来一直依赖该功能而没有考虑它。我翻阅了几本 C++ 书籍以找到答案,包括 Stroustrup 的The C++ Programming LanguageThe Annotated C++ Reference Manual,但没有人承认或解释其中的区别。但是,我想我可以通过它推理。

我相信,您的示例有效的原因是您的正文testprintout没有真正出现在您的文件中。编码

class MyClass {
  void someFun() {
    x = 5;
  }
  int x;
};

...这似乎违反了在使用变量之前必须声明变量的规则,实际上相当于:

class MyClass {
  void someFun();
  int x;
};

void MyClass::someFun() {
  x = 5;
}

一旦我们像这样重写它,很明显你定义中的东西MyClass实际上是一个声明列表。这些可以按任何顺序排列。x在它被宣布之前,你不会依赖它。我知道这是真的,因为如果您要像这样重写示例,

void MyClass::someFun() {
  x = 5;
}

class MyClass {
  void someFun();
  int x;
};

...它将不再编译!所以类定义首先出现(及其完整的成员列表),然后您的方法可以使用任何成员,而无需考虑它们在类中声明的顺序。

最后一个难题是 C++ 禁止在类定义之外声明任何类成员,因此一旦编译器处理了您的类定义,它就会知道类成员的完整列表。这在 Stroustrup 的注释 C++ 参考手册的 p.170 中有说明:“成员列表定义了类的完整成员集。不能在其他地方添加任何成员。”

感谢您让我对此进行调查;我今天学了些新东西。:)

于 2012-10-26T22:11:56.530 回答
10

为了清楚起见,这是 C++ 标准所要求的,而不仅仅是几个编译器处理类定义的方式。

N3242 3.3.7:

类中声明的名称的潜在范围不仅包括名称声明点之后的声明区域,还包括所有函数体、非静态数据成员的大括号或等号初始化器以及其中的默认参数类(包括嵌套类中的此类内容)。

于 2012-10-26T22:19:08.007 回答
1

除了 Philip 的好评之外,Stroustrup在The Design and Evolution of C++中对Name Lookup Rules给出了很好的解释。这在“6.3 说明”中进行了描述。在 6.3.1.1, "The ARM Name Lookup Rules"中,他提到了ARM中定义的 2 条规则:

[1]类型重定义规则:一个类型名称在一个类中被使用后不能被重定义。

[2] 重写规则:分析内联定义的成员函数,就好像它们是在类声明结束后立即定义的一样。

因此,在您的情况下,它将应用重写规则(正如菲利普推断的那样),这就是您可以转发引用这些类成员的原因。

这本书可能主要具有历史意义(写于 94 年),但我认为这些规则在今天同样适用。

于 2012-10-26T23:35:29.580 回答
0

您能够这样做的原因是,当您调用test,printoutprintout2时,它们已经被创建了。如果在执行之前在任意函数之外调用该函数,则会出现错误。

将类成员函数视为与类其余部分的评估流程异步。这不适用于独立函数,但您可以访问尚未实例化的数据成员。我不完全确定为什么我们能够做到这一点,但我认为这与类对象的实例化有关。

于 2012-10-26T21:50:15.517 回答