【问题标题】:Scope of enum in C vs C++C 与 C++ 中的枚举范围
【发布时间】:2015-05-05 07:46:51
【问题描述】:

为什么枚举值可以在 C 中定义的块之外访问,而在 C++ 中却不能?

考虑以下 C 程序。

#include <stdio.h>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;
    tu.integer = 100;
    return 0;
}

它在 C 中编译并运行良好。

但在 C++ 中编译失败。

#include <iostream>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;
    tu.integer = 100;
    return 0;
}

[错误] 'INT' 未在此范围内声明

C 和 C++ 中的枚举和作用域规则是否不同?

【问题讨论】:

  • 了解“命名空间”
  • @meet C++ 具有类作用域。看我的回答。

标签: c++ c enums


【解决方案1】:

在 C 中,对于枚举和结构的范围没有任何规则。定义枚举的地方并不重要。

在 C++ 中,在另一个东西中定义一些东西(如类中的枚举)使这个东西属于另一个东西。

如果你想让你的枚举在 C++ 中是全局的,你必须在你的类之外定义它,或者从你的结构路径访问:

#include <iostream>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

int main()
{
    tu.type = mystruct::INT; // INT is not in global scope, I have to precise it.
    tu.integer = 100;
    return 0;
}

注意:这在本例中有效,因为您使用的是struct,默认情况下所有内容都是public。当心;仅当枚举位于 public 范围内时,您才能从结构或类外部访问枚举类型和值,就像任何字段或函数一样。

【讨论】:

  • 你对 C 有点太苛刻了。它肯定有名称范围,块范围,例如 { int i; }。但这是特定于函数的。
  • C 的问题在于它没有适用于 C++ 中使用 :: 运算符的任何内容的范围——因为 C 中没有这样的运算符。
  • 定义枚举的地方并不重要。 你是什么意思?我不能把定义放在我正在使用的变量之后。
  • 这个答案不正确。在功能块中定义的枚举在 C 中的该范围之外是不可见的。
  • @Rusland,你是说C的好处? ;-) 开个玩笑,在下划线上使用:: 有什么好处?
【解决方案2】:

主要区别在于与C相反,C++有一个类作用域。

在 C 中(6.2.1 标识符的范围)

4 每个其他标识符的范围由其位置决定 声明(在声明符或类型说明符中)。如果声明者或 声明标识符的类型说明符出现在任何 块或参数列表,标识符具有文件范围,其中 在翻译单元的末尾终止。

因此在这个程序中

#include <stdio.h>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;
    tu.integer = 100;
    return 0;
}

枚举器 INT、FLOAT、STRING 在任何块范围之外声明,因此具有文件范围。

在 C++ 中定义了一个单独的范围 - 类范围:

3.3.7 类范围

1 以下规则描述了类中声明的名称的范围。 1) 类中声明的名称的潜在范围不仅包括 在名称的声明点之后的声明区域, 还有所有函数体,默认参数, 异常规范和大括号或等式初始化器 该类中的非静态数据成员(包括嵌套中的此类内容 类)。

2 类成员的名称只能按如下方式使用:

——在其类(如上所述)或派生类的范围内 (第 10 条)从其类中,

——在 .运算符应用于其类型的表达式 类 (5.2.5) 或从其类派生的类,

— 在 -> 运算符应用于指向其类对象的指针之后 (5.2.5) 或从其类派生的类,

— 在 :: 范围解析运算符 (5.1) 之后应用于名称 它的类或从它的类派生的类。

考虑到(9.2 类成员)

1 ...类的成员是数据成员、成员函数 (9.3)、 嵌套类型和枚举器

因此在这个程序中

#include <iostream>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;  // Invalid access of class member
    tu.integer = 100;
    return 0;
}

您应通过以下方式之一访问班级成员INT

    tu.type = mystruct::INT;

    tu.type = tu.INT;

甚至喜欢

    tu.type = ( &tu )->INT;

【讨论】:

    【解决方案3】:

    Vlad 和 Arachtor 给出的答案就他们而言是很好的,但是他们没有解决一个问题:为什么 C++ 会做不同的事情。如果有人熟悉 Stroustrup 的书,他们也许可以改进这一点,但我想:

    • C 很久以前就被设计为相当容易编译,而 C++ 旨在通过使用 OO 使编程更可靠,其主要理想是“在一个地方,告诉用户使用它所需的所有知识仅此而已”;这样做的好处往往是不言而喻的,即把属于的东西放在一起。
    • 这导致决定使用类型定义来限制某些定义的范围,并将构造置于命名空间的层次结构中。
    • 通过限制嵌套枚举的范围,可以使用更短的名称,而不会有歧义或冲突的风险。

    【讨论】:

      猜你喜欢
      • 2017-04-21
      • 1970-01-01
      • 2018-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-06
      • 2019-06-15
      • 1970-01-01
      相关资源
      最近更新 更多