C++11 强类型枚举

1.传统枚举类型的缺陷

枚举类型是用户自定义的构造类型,它是由用户定义的若干枚举常量的集合。枚举值对应整型数值,默认从 0 开始。

比如定义一个描述性别的枚举类型:

enum Gender{Male, Female};

其中枚举值 Male 被编译器默认赋值为 0,Female 赋值为 1。传统枚举类型在设计上会存在以下几个问题。

(1)同作用域同名枚举值会报重定义错误。传统 C++ 中枚举常量被暴漏在同一层作用域中,如果同一作用域下有两个不同的枚举类型,但含有同名的枚举常量也是会报编译错误的,比如:

enum Fruits{Apple,Tomato,Orange};
enum Vegetables{Cucumber,Tomato,Pepper};	// 编译报 Tomato 重定义错误

其中水果和蔬菜两个枚举类型中包含同名的Tomato枚举常量会导致编译错误。因为 enum 则是非强作用域类型,枚举常量可以直接访问,这种访问方式与 C++ 中具名的 namespace、class/struct 以及 union 必须通过"名字::成员名"的访问方式大相径庭。

(2)由于枚举类型被设计为常量数值的“别名”,所以枚举常量总是可以被隐式转换为整型,且用户无法为枚举常量定义类型。

(3)枚举常量占用存储空间以及符号性不确定。C++ 标准规定枚举所基于的“基础类型”是由编译器来具体实现,这会导致枚举类型成员的基本类型存在不确定性问题,尤其是符号性问题。考察如下示例:

enum A{A1=1,A2=2,ABig=0xFFFFFFFFU};
enum B{B1=1,B2=2,BBig=0xFFFFFFFFFUL};

int main() {
	cout<<sizeof(A1)<<endl;	//4
	cout<<ABig<<endl;		//4294967295
	cout<<sizeof(B1)<<endl;	//8
	cout<<BBig<<endl;		//68719476735
}

以上输出结果是在 Linux 平台下使用 g++ 编译输出的结果,在 VC++(VS2017)中的输出结果分别是 4、-1、4 和 -1。可见不同编译器对枚举常量的整型类型的宽度和符号有着不同的实现。GNU C++ 会根据枚举数值的类型使用不同宽度和符号的整型,VC++ 则始终以有符号 int 表示枚举值。

为了解决以上传统枚举类型的缺陷,C++11 引入了强类型枚举。

2.强类型枚举

非强作用域类型,允许隐式转换为整型,枚举常量占用存储空间以及符号性的不确定,都是枚举类缺点。针对这些缺点,C++11 引入了一种新的枚举类型——强类型枚举(strongly typed enum)。

强类型枚举使用 enum class 来声明:

enum class Enumeration{VAL1,VAL2,VAL3=100,VAL4};

强类型枚举具有如下几个优点:
(1)强作用域,强类型枚举成员的名称不会被输出到其父作用域,所以不同枚举类型定义同名枚举成员编译不会报重定义错误。进而使用枚举类型的枚举成员时,必须指明所属范围,比如Enum::VAL1,而单独的VAL1则不再具有意义;
(2)转换限制,强类型枚举成员的值不可以与整型发生隐式相互转换。比如比如Enumeration::VAL4==10;会触发编译错误;
(3)可以指定底层类型。强类型枚举默认的底层类型是int,但也可以显示地指定底层类型。具体方法是在枚举名称后面加上":type",其中type可以是除wchar_t以外的任何整型。比如:

enum class Type:char{Low,Middle,High};

注意:
(1)声明强类型枚举的时候,既可以使用关键字 enum class,也可以使用enum struct。事实上,enum struct 与 enum class 在语法上没有任何区别。
(2)由于强类型枚举是强类型作用域的,故匿名的 enum class 可能什么都做不了,如下代码会报编译错误:

enum class{
	General,
	Light,
	Medium,
	Heavy
}weapon;

int main() {
	weapon=Medium;						//编译出错
	bool b=weapon == weapon::Medium;	//编译出错
	return 0;
}

当然对于匿名强类型枚举我们还是可以使用 decltype 获得其类型并进而使用,但是这样做可能违背强类型枚举进行匿名的初衷。

3.对传统枚举类型的扩展

传统枚举类型为了配合C++11引入的强类型枚举,C++11对传统枚举类型进行了扩展。

(1)底层的基本类型可以在枚举名称后加上":type",其中 type 可以是除 wchar_t 以外的任何整型,比如:

enum Type:char{Low,Middle,High};

(2)C++11 中,枚举类型的成员可以在枚举类型的作用域内有效。比如:

enum Type{Low, Middle, High};
Type type1 = Middle;
Type type2 = Type::Middle;

其中 Middle 与 Type::Middle 都是合法的使用形式。


参考文献

深入理解C++11[M].C5.1强类型枚举.P155-161
C++11强类型枚举——枚举类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值