C 与 C++ 中的枚举范围
Scope of enum in C vs C++
为什么枚举值可以在 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;
}
[Error] 'INT' was not declared in this scope
C 和 C++ 中的枚举和范围规则是否不同?
在 C 中,枚举和结构的作用域根本没有规则。您定义枚举的地方并不重要。
在 C++ 中,在另一个东西中定义一些东西(如 class 中的枚举)使这个东西属于另一个东西。
如果你想让你的枚举在 C++ 中成为全局枚举,你必须在你的 class 之外定义它,或者从你的结构路径访问:
#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
范围内时,您才能从结构或 class 外部访问枚举类型和值,就像任何字段或函数一样。
主要区别在于,与 C 相反,C++ 具有 class 作用域。
在 C 中(6.2.1 标识符的范围)
4 Every other identifier has scope determined by the placement of its
declaration (in a declarator or type specifier). If the declarator or
type specifier that declares the identifier appears outside of any
block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit.
所以在这个程序中
#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++ 中定义了一个单独的范围 - class 范围:
3.3.7 Class 范围
1 The following rules describe the scope of names declared in classes.
1) The potential scope of a name declared in a class consists not only
of the declarative region following the name’s point of declaration,
but also of all function bodies, default arguments,
exception-specifications, and brace-or-equal-initializers of
non-static data members in that class (including such things in nested
classes).
和
2 The name of a class member shall only be used as follows:
— in the scope of its class (as described above) or a class derived
(Clause 10) from its class,
— after the . operator applied to an expression of the type of its
class (5.2.5) or a class derived from its class,
— after the -> operator applied to a pointer to an object of its class
(5.2.5) or a class derived from its class,
— after the :: scope resolution operator (5.1) applied to the name of
its class or a class derived from its class.
考虑到(9.2 Class 位成员)
1 ...Members of a class are data members, member functions (9.3),
nested types, and enumerators.
所以在这个程序中
#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;
}
您可以通过以下方式之一访问 class 成员 INT
。
tu.type = mystruct::INT;
或
tu.type = tu.INT;
甚至喜欢
tu.type = ( &tu )->INT;
Vlad 和 Arachtor 给出的答案就目前而言是好的,但有一个问题他们没有解决:为什么 C++ 的做法不同。如果有人熟悉 Stroustrup 的书,他们可能会对此进行改进,但我想:
- C 很久以前就被设计为相当容易编译,而 C++ 旨在通过使用 OO 使编程更可靠,其主要理想是“在一个地方,告诉用户他们需要知道的所有构造使用它,不再使用”;这通常具有将属于一起的东西聚集在一起的不言而喻的好处。
- 这导致决定使用类型定义来限制某些定义的范围,并将构造放置在命名空间的层次结构中。
- 通过限制嵌套枚举的范围,可以使用较短的名称而不会产生歧义或冲突的风险。
为什么枚举值可以在 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;
}
[Error] 'INT' was not declared in this scope
C 和 C++ 中的枚举和范围规则是否不同?
在 C 中,枚举和结构的作用域根本没有规则。您定义枚举的地方并不重要。
在 C++ 中,在另一个东西中定义一些东西(如 class 中的枚举)使这个东西属于另一个东西。
如果你想让你的枚举在 C++ 中成为全局枚举,你必须在你的 class 之外定义它,或者从你的结构路径访问:
#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
范围内时,您才能从结构或 class 外部访问枚举类型和值,就像任何字段或函数一样。
主要区别在于,与 C 相反,C++ 具有 class 作用域。
在 C 中(6.2.1 标识符的范围)
4 Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit.
所以在这个程序中
#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++ 中定义了一个单独的范围 - class 范围:
3.3.7 Class 范围
1 The following rules describe the scope of names declared in classes. 1) The potential scope of a name declared in a class consists not only of the declarative region following the name’s point of declaration, but also of all function bodies, default arguments, exception-specifications, and brace-or-equal-initializers of non-static data members in that class (including such things in nested classes).
和
2 The name of a class member shall only be used as follows:
— in the scope of its class (as described above) or a class derived (Clause 10) from its class,
— after the . operator applied to an expression of the type of its class (5.2.5) or a class derived from its class,
— after the -> operator applied to a pointer to an object of its class (5.2.5) or a class derived from its class,
— after the :: scope resolution operator (5.1) applied to the name of its class or a class derived from its class.
考虑到(9.2 Class 位成员)
1 ...Members of a class are data members, member functions (9.3), nested types, and enumerators.
所以在这个程序中
#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;
}
您可以通过以下方式之一访问 class 成员 INT
。
tu.type = mystruct::INT;
或
tu.type = tu.INT;
甚至喜欢
tu.type = ( &tu )->INT;
Vlad 和 Arachtor 给出的答案就目前而言是好的,但有一个问题他们没有解决:为什么 C++ 的做法不同。如果有人熟悉 Stroustrup 的书,他们可能会对此进行改进,但我想:
- C 很久以前就被设计为相当容易编译,而 C++ 旨在通过使用 OO 使编程更可靠,其主要理想是“在一个地方,告诉用户他们需要知道的所有构造使用它,不再使用”;这通常具有将属于一起的东西聚集在一起的不言而喻的好处。
- 这导致决定使用类型定义来限制某些定义的范围,并将构造放置在命名空间的层次结构中。
- 通过限制嵌套枚举的范围,可以使用较短的名称而不会产生歧义或冲突的风险。