导入
作用域枚举
在本节课中,我们将讨论如何使用枚举来定义包含整数常量的自定义数据类型。
枚举 允许我们定义包含整数常量的自定义数据类型。这些整数常量被称为枚举器。遗憾的是,传统的枚举存在一些缺陷。
传统 C++ 中枚举的缺点
传统枚举主要有以下三个显著缺点:
-
枚举器会隐式转换为
int。 -
枚举器会引入到外部作用域中。
-
无法指定枚举的类型。
首先来看第 3 点:由于枚举类型未知,因此无法前向声明。在传统 C++ 中,对枚举唯一能保证的是:其类型必须是整型,并且足够大以容纳枚举器的值。
第 1 和第 2 点则更为意外。请看下面的代码:
1// enumClassic.cpp 2 3#include <iostream> 4 5int main(){ 6 7 std::cout << std::endl; 8 9 enum Colour{red= 0, green= 2, blue}; 10 11 std::cout << "red: " << red << std::endl; 12 std::cout << "green: " << green << std::endl; 13 std::cout << "blue: " << blue << std::endl; 14 15 int red2 = red; 16 17 std::cout << "red2: " << red2 << std::endl; 18 19 // int red = 5; 错误 20 21}
一方面,枚举器 red、green 和 blue 被引入到外部作用域中,因此第 19 行定义变量 red 会导致冲突。另一方面,red 可以被隐式转换为 int。
如果我们不给枚举命名,例如使用 enum {red, green, blue},那么枚举器同样会被引入到外部作用域中。
但这一切在 C++11 中得到了改变。
强类型枚举
作用域枚举通常被称为强类型枚举。强类型枚举遵循更严格的规则:
-
枚举器只能在其所属的作用域内访问。
-
枚举器不会隐式转换为
int。 -
枚举器不会被导入到外部作用域中。
-
枚举器的默认类型是
int,因此我们可以对枚举进行前向声明。
强类型枚举与传统枚举之间的语法差异非常小,唯一的区别在于增加了 class 或 struct 关键字。
如果需要将枚举器当作 int 使用,必须显式地通过 static_cast 进行转换。
1// enumCast.cpp 2 3#include <iostream> 4 5enum OldEnum{ 6 one = 1, 7 ten = 10, 8 hundred = 100, 9 thousand = 1000 10}; 11 12enum struct NewEnum{ 13 one = 1, 14 ten = 10, 15 hundred = 100, 16 thousand = 1000 17}; 18 19int main(){ 20 21 std::cout << std::endl; 22 23 std::cout << "C++11 = " << 2*thousand + 0*hundred + 1*ten + 1*one << std::endl; 24 std::cout << "C++11 = " << 2*static_cast<int>(NewEnum::thousand) + 25 0*static_cast<int>(NewEnum::hundred) + 26 1*static_cast<int>(NewEnum::ten) + 27 1*static_cast<int>(NewEnum::one) << std::endl; 28 29}
为了计算或输出枚举器的值,必须将其转换为整型。强类型枚举不支持直接的加法运算或输出操作。
在本课中,我们讨论了传统枚举与强类型枚举的区别。通常,它们也被称为无作用域枚举和有作用域枚举。