文章参考
1. 枚举
1.1 概述
在C/C++中的枚举来自于C,处于设计上简单的目的,枚举往往对应到整型数值。:
// 匿名枚举
enum {Male, Female}; // 0, 1
// 有名枚举
enum Color {Red, Yellow=2, Blue}; // 0, 2, 3
枚举成员默认从0开始,随后向下递增,也可以自己为某个枚举成员指定值,而下面的枚举成员依旧是递增的。
1.2 缺陷
重定义:
在C/C++中,枚举的名字
以及枚举的成员名
都是全局可见的,访问时也不需要::
符,而是按照全局量的方式直接访问,这就很容易导致重定义的问题。
EG:
-
代码:
enum China {Beijing, Dongjing}; enum Japan {Dongjing, Daban};
-
分析:此时编译会报错:
Redefinition of enumerator 'Dongjing'
。这时由于两个Dongjing
都是全局可见的,因此发生了重定义。
隐式转换:
由于C中枚举被设计为常量数值别名
的版型,所有枚举的成员都可以被隐式的转换为整形,但有时我们不想这么做。
2. 强类型枚举
C++11引入枚举类
,又名强类型枚举(strong-typed enum)
。
定义:
// 默认底层类型为int
enum class Color {Red, Green, Blue};
// 指定类型:
enum class Color: char {Red, Green, Blue};
其中:
- 指定的底层类型可以是除了
wchar_t
以外的任何整形。wchar_t
:双字节类型或宽字符类型,是C/C++的一种扩展的存储方式,一般为16位或32位。主要用在国际程序的实现中。
优点:
- 强作用域:强类型枚举成员的名称不会被输出到其父级作用域空间,且必须使用有名枚举,例如:
Color::Red
。 - 转换类型限制:强枚举类型的值不能和整形进行
隐式的转换
。
注意:
- 在声明强类型枚举的时候,除了使用
enum class
,也可以使用enum struct
,二者没有区别。 enum class
没有共有、私有之分,也不会使用模板来支持泛化的声明。
EG:
-
代码:
enum class China { Shanghai, Dongjing, Beijing, Nanjing, }; enum class Japan:char { Dongjing, Daban, Hengbin, Fudao }; int main() { int m = Shanghai; // error int n = China::Shanghai; // error if ((int)China::Beijing >= 2) { cout << "ok!" << endl; } cout << "size1: " << sizeof(China::Dongjing) << endl; cout << "size2: " << sizeof(Japan::Dongjing) << endl; return 0; }
-
分析:
- 第5行:错误。强类型枚举具有强作用域,必须通过
枚举名::
才能访问到枚举成员。 - 第6行:错误。强类型枚举禁止枚举成员和整形进行隐式转换。
- 第7行:正确。在将强类型枚举的枚举成员和整形进行比较之前做了强制类型转换。
- 第11行:输出
4
,因为强类型枚举的地城类型值默认为int
。 - 第12行:输出
1
,因为显式制定了该强类型枚举的类型为char
。
- 第5行:错误。强类型枚举具有强作用域,必须通过
3. 对原有枚举进行扩展
强类型枚举虽然好用,但它带有浓厚的C++风格,和原有的属于C的枚举不相容。为了配合强类型枚举,C++11对原有的枚举类型进行了扩展:
-
底层类型:可以显式指定枚举的底层类型,方式和强类型枚举一致,在枚举名称后加上
:type
,且type可以是除了wchar_t之外的任何整形
。如果不指定,默认依旧是int
类型。enum Colors: char{ Red, Yellow, Blue };
注意:不像强类型枚举,扩展后枚举依旧支持隐式类型的转换。
enum Colors: char{ Red, Yellow, Blue }; int n = Colors::Red;
-
作用域:C++11规定枚举成员的名字除了输出到
父级作用域
,还在枚举类型定义的作用域中有效:enum Colors: char{ Red, Yellow, Blue }; int main(void){ // C++11之前 Colors c1 = Red; // C++11的扩展语法 Colors c2 = Colors::Red; return 0; }