C++知识点记录【一】—— enum class
C++11里面提出了一个新的概念enum class。以下将对比新旧enum的区别。
1. 旧enum的缺点
1.1 向整型的隐式转换(Implicit conversion to an integer)
enum的整型提升可参考:https://blog.csdn.net/xiaodouhao123456/article/details/108470456
旧版enum其实并不具有非常完全的类型安全(当然它也体现了一定的类型安全:1.禁止不同枚举体之间的赋值 2.禁止整形向枚举体的隐式转换等),也就是面对整形提升,旧版enum是没有抗拒力的。
发生整型提升的例子:
#include <iostream>
enum colorA{redA,greenA,grayA};
enum colorB {redB,greenB,yellowB};
void test(int data) {
std::cout << "test called" << std::endl;
}
int main() {
colorA ca(redA);
colorB cb(greenB);
//ca = cb; ERROR , 无法从“colorB”转换为“colorA”
//ca = 2; ERROR , 无法从“int”转换为“colorA”
bool res(ca < cb); //OK,发生了整型提升
std::cout << std::boolalpha << res << std::endl;
test(ca); //OK,发生了整型提升
std::cin.get();
return 0;
}
1.2 无法指定底层所使用的数据类型(Inability to specify underlying type)
- 首先,无法指定数据类型,导致我们无法明确枚举类型所占的内存大小。这种麻烦在结构体当中尤为突出,特别是当我们需要内存对齐和填充处理的时候。
- 其次,当我们使用enum时,我们无法决定编译器底层是如何对待enum的(比如:signed和unsigned)。例如下面的示例:
#include <iostream>
enum MyEnum { num1 = 1, num2 = 2, numn = 0xFFFFFF00U };
int main() {
std::cout << num1 << std::endl;
std::cout << num2 << std::endl;
std::cout << numn << std::endl;
std::cin.get();
return 0;
}
VS2015运行结果:1 2 -256,但是CodeBlocks运行结果:1 2 4294967040
在 numn=0xFFFFFF00U;中,我们希望0xFFFFFF00表现为unsigned。但是不同的编译器其标准也不同。这就给我们的程序带来了许多的不确定性。
1.3. enum的作用域(Scope)
enum的中的 ” { } ” 大括号并没有将枚举成员的可见域限制在大括号内,导致enum成员曝露到了上一级作用域(块语句)中。
#include <iostream>
enum color{red,blue};//定义拥有两个成员的enum,red和blue在enum的大括号外部可以直接访问,而不需要使用域运算符。
int main() {
std::cout << blue << std::endl;//将成员暴露在enum外部该文件的全局作用域中了
std::cin.get();
return 0;
}
这将会导致无法定义同名的枚举成员,如下:
enum color { red, blue };
//enum MyEnum { red, yellow }; ERROR, 重定义;以前的定义是“枚举数”
1.4. 削弱了程序的可移植性
在问题2中,我们提到不同编译器解决底层数据类型的方法不统一,所以就会导致代码的可移植性变差。
新的enum的作用域不再是全局的了,原来enum名字的作用域是全局的。
enum作用域是全局的:
Alert a1 = red; //ok
Alert a2 = Alert::red; //error in C++98; ok in C++11
int red = 0; // error, red is redefined
2. enum class 和 enum struct
enum class 和 enum struct 是等价的,使用enum class\enum struct不会与现存的enum关键词冲突。而且enum class\enum struct具有更好的类型安全和类似封装的特性(scoped nature)。
2.1 声明
enum class color{red,green,yellow};
enum class colorx{red,green=100,yellow};
//....
2.2 类型转换
与整形之间不会发生隐式类型转换,但是可以强转。
#include <iostream>
enum class color { red, green, yellow};
int main() {
//int res(color::red); //ERROR , “初始化”: 无法从“color”转换为“int”
//color col(2);//ERROR , “初始化”: 无法从“int”转换为“color”
//强转
int res(static_cast<int>(color::red));//OK
color col(static_cast<color>(1));//OK
std::cin.get();
return 0;
}
2.3 指定底层数据类型(underlying type)
默认的底层数据类型是int,用户可以通过:type(冒号+类型)来指定任何整形(除了wchar_t)作为底层数据类型。
enum class color:unsigned char{red,blue};
enum calss colorb:long long{yellow,black};
2.4 域
引入了域,要通过域运算符访问,不可以直接通过枚举体成员名来访问(所以我们可以定义相同的枚举体成员而不会发生重定义的错误)
#include <iostream>
enum class color { red, green, yellow};
enum class colorX { red, green, yellow };
int main() {
//使用域运算符访问枚举体成员,强转后打印
std::cout << static_cast<int>(color::red) << std::endl;
std::cout << static_cast<int>(colorX::red) << std::endl;
std::cin.get();
return 0;
}
上一篇: es6之数组遍历的各种方式
下一篇: ES6五种遍历对象属性的方式