本周小贴士#86:带类的枚举
Posted -飞鹤-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了本周小贴士#86:带类的枚举相关的知识,希望对你有一定的参考价值。
作为totw/86最初发表于2015年1月5日
由Bradley White (bww@google.com)创作
“显示类,…并显示字符。”——贝尔.布莱恩特
enumeration,简称enum,是一种可以容纳一组指定整数中的一个类型。此集合中的某些值可以命名,它们被称为枚举值。
无作用域枚举
C++程序员很熟悉这个概念,但在C++11之前,枚举有两个重大的缺陷:枚举的名称:
- 在与枚举类型相同的作用域内,然后隐式转换为某种整形值。
因此,使用C++98…
enum CursorDirection { kLeft, kRight, kUp, kDown };
CursorDirection d = kLeft; // 可行:作用域内的枚举器
int i = kRight; // 可行:枚举器转换为整形
然而,…
// 错误:重新声明kLeft和kRight
enum PoliticalOrientation { kLeft, kCenter, kRight };
C++11以一种方式修改无作用域枚举的行为:枚举值对于枚举而言是局部的,但为了向后兼容,它会继续导出到枚举的作用域中。
因此,使用C++11…
CursorDirection d = CursorDirection::kLeft; // 在C++11中可行
int i = CursorDirection::kRight; // 可行:继续转换为整形
但PoliticalOrientation的声明依然将引起错误。
作用域枚举
已经观察到的隐式转换为整形是错误的来源,而枚举值与枚举在相同作用域造成的命名空间污染,会在大型且多库项目中引起问题。为了解决这些担忧,C++11引入了一个新的概念:作用域枚举。
在一个由关键字enum class引入的作用域枚举中,这些枚举值是:
- 仅作为枚举(它们它们不会导出到枚举的作用域中)的局部变量,并且不会被隐式转换为整形。
因此,(注意额外的class关键字)…
enum class CursorDirection { kLeft, kRight, kUp, kDown };
CursorDirection d = kLeft; // 错误,kLeft不在这个作用域内
CursorDirection d2 = CursorDirection::kLeft; // 可行
int i = CursorDirection::kRight; // 错误:无法转换
和…
// 可行:kLeft和kRigh都是每个作用域枚举的局部变量
enum class PoliticalOrientation { kLeft, kCenter, kRight };
这些简单的更改消除了普通枚举的问题,因此在所有新代码中应该优先使用enum class。
使用作用域枚举确实意味着,如果你仍然想如此的转换(例如,当记录一个枚举值时,或在类似标志的枚举值上使用按位运算时),你必须显式转换为整形。使用std::has进行散列将继续工作(例如,std::unorderd_map<CursorDirection, int>)。
底层枚举类型
C++11还为两类枚举类型引入了指定底层类型的能力。以前枚举的底层整型类形是通过枚举值的符号和大小来确定的,但是我们现在能够明确指定了。例如,…
// 使用'int'作为CursorDirection的底层类型
enum class CursorDirection : int { kLeft, kRight, kUp, kDown };
因为这个枚举值的范围很小,并且如果我们希望在存储CursorDirection时避免浪费空间,那么我们可以指定char来代替。
// 使用'char'作为CursorDirection的底层类型
enum class CursorDirection : char { kLeft, kRight, kUp, kDown };
如果一个枚举值超过了底层类型的范围,那么编译器会报错。
结论
在新代码中优先使用enum class。你将减少命名空间污染,并且将避免在隐式转换中的错误。
enum class Parting { kSoLong, kFarewell, kAufWiedersehen, kAdieu };
以上是关于本周小贴士#86:带类的枚举的主要内容,如果未能解决你的问题,请参考以下文章