欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++知识点记录【一】—— enum class

程序员文章站 2022-07-16 22:58:22
...

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;
}
相关标签: c/c++知识点