【问题标题】:Do class functions/variables have to be declared before being used?类函数/变量是否必须在使用前声明?
【发布时间】:2012-10-17 04:33:08
【问题描述】:

所以我在学习课程时偶然发现了一些对我来说很尴尬的东西。

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

        void printout()
        {
            printout2();
        }

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

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

你可以看到我在声明之前使用了printout(), printout2()

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

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

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

谢谢

【问题讨论】:

  • 我还没有看到这个的具体答案,但我猜这是由于编译器对类做了两次传递。
  • @chris 你的意思是编译器在类上做了两次传递
  • This comment 似乎强化了这种猜测。这个问题有点涉及这个概念。

标签: c++ class function variables prototype


【解决方案1】:

之所以能够这样做,是因为当您调用testprintoutprintout2 时,它们已经被创建。如果你在实现之前在任意函数之外调用函数,那么你会得到一个错误。

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

【讨论】:

  • 让我看看我理解正确,是不是因为所有函数/变量都是在声明对象后声明的?
【解决方案2】:

好问题;我多年来一直依赖该功能而没有考虑它。我翻阅了几本 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 的 The Annotated C++ Reference Manual 的 p.170 中有说明:“成员列表定义了类的完整成员集。不能在其他地方添加任何成员。 "

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

【讨论】:

  • 感谢您的夸奖。我确信我写的内容,如果您担心标准和编译器兼容性,这可能还不够好。我认为 aschepler 的回答比我的更“100% 肯定”。
  • @Philip:如果您想要更好的示例,请使用 typedefs:ideone.com/Es28Zq。 C++按顺序完成所有声明,然后是方法体。
  • 内联方法呢?
【解决方案3】:

澄清一下,这是 C++ 标准所要求的,而不仅仅是几个编译器处理类定义的方式。

N3242 3.3.7:

类中声明的名称的潜在范围不仅包括名称声明点之后的声明区域,还包括所有函数体,brace-or-equal-initializers - 静态数据成员,以及该类中的默认参数(包括嵌套类中的此类内容)。

【讨论】:

    【解决方案4】:

    除了 Philip 的好评之外,Stroustrup 在The Design and Evolution of C++中对Name Lookup Rules做了很好的解释。这在“6.3 说明”中有所描述。在 6.3.1.1,“ARM 名称查找规则”,他提到了 ARM 中定义的 2 条规则:

    [1]类型重定义规则:类型名在类中使用后不得重定义。

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-19
      • 1970-01-01
      • 1970-01-01
      • 2011-11-03
      相关资源
      最近更新 更多