C++11 新特性之枚举

       本文是C++11新特性介绍的第十二部分,涉及到枚举相关的新特性。

枚举类型定义

       若一个变量只有有限的几种可能,我们可以定义枚举(enumeration)类型,比如一个星期中取值范围只能是星期一至星期日,性别的分类只能有男或女。
       默认情况下,枚举成员值从0开始,其后的枚举成员值以依次1。我们也可以显示指定枚举成员值,则其后的枚举成员值在指定的成员值依次加1。枚举成员值必须是常量表达式。
       在C++11新标准中引入了限定作用域的枚举类型(enum class),所以在C++11中枚举类型可分为不限定作用域(enum)以及限定作用域(enum class)两种。在限定作用域的enum class中,枚举成员的作用域限定在枚举类型所声明的作用域中,所以当某个更大的作用域中包含enum class则该enum class中的枚举成员的作用域也只限定在该enum class中。
       本文章只简单介绍限定作用域的枚举类型(enum class)。

enum class

       限定作用域枚举的一般形式如下:
       形式1,声明枚举成员类型为int的有作用域枚举类型:

1
2
3
4
enum class 枚举名
{
枚举元素表列
};

       形式2,声明枚举成员类型为类型的有作用域枚举类型:

1
2
3
4
enum class 枚举名
{
枚举元素表列
};

       形式3,声明枚举成员类型为int的有作用域枚举类型的不可见枚举声明:

1
enum class 枚举名;

       形式4,声明枚举成员类型为类型的有作用域枚举类型的不可见枚举声明:

1
enum class 枚举名:类型;

       注意关键字 enum class 与 enum struct完全等价,所以上述所有形式中的enum class 可由 enum struct替代,例如下列形式等价于形式1:

1
2
3
4
enum struct 枚举名
{
枚举元素表列
};

       举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
int main()
{
enum class Color { red, green, blue };
Color r = Color::blue;
switch(r)
{
case Color::red:
std::cout << "red\n";
break;
case Color::green:
std::cout << "green\n";
break;
case Color::blue:
std::cout << "blue\n";
break;
}
return 0;
}

enum class与enum区别

       在限定作用域的枚举类型中,枚举成员的名字遵循常规的作用域准则,并且在枚举类型的作用域外是不可访问的。与之相反,在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同。

避免枚举成员重定义

       enum class的中的枚举成员作用域的范围只限定在enum class声明的作用域中,所以在包含enum class的更大的作用域就可以定义一个与枚举成员变量名相同的变量,降低了对命名空间名的污染:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
enum class Color {red, green, blue}; //red, green, blue只在该括号内有效
int main()
{
auto blue = false; //正确,这个blue并不是Color中的blue
Color a = blue; //错误,在作用域范围内没有blue这个枚举量
Color b = Color::blue; //正确
auto c = Color::blue; //正确
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
enum Sex
{
Girl,
Boy
};
int main()
{
Sex a = Girl; //正确
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
enum Sex
{
Girl,
Boy
};
enum Student
{
Girl,
Boy
};
int main()
{
Sex a = Girl; //错误:“Girl”与以前的声明冲突
Student b = Girl; //错误:“Girl”与以前的声明冲突
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
enum class Sex
{
Girl,
Boy
};
enum class Student
{
Girl,
Boy
};
int main()
{
Sex a = Sex::Girl; //正确
Student b = Student::Girl; //正确
return 0;
}

避免隐式转换

       不限范围的枚举类enum是可以发生隐式转换的,限定作用域的枚举类型enum class不允许任何隐式转化,可以显示或使用static_cast进行强制转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum class Sex
{
Girl,
Boy
};
int main()
{
Sex a = Sex::Girl;
int b = a; //错误,无法从“Girl”隐式转换为“int”。
int c = int(a); //正确,显示将enum class转换为整数
int d = static_cast<int>(a); //正确,进行强制转换
return 0;
}

声明前置

       在C++11标准中,enum class的枚举类型可以提前声明,因为枚举成员可以使用默认成员类型int,也可以按编程需要修改默认成员类型。而enum未指定枚举成员默认大小,所以必须指定成员类型:

1
2
3
4
enum class Color; //正确,声明前置,枚举成员默认类型int
enum class Corlor: uint32_t; //正确,声明前置,枚举成员默认类型为uint32_t
enum Color; //错误
enum Color: uint8_t; //正确,提前指定枚举成员默认类型,可以声明前置

总结

       1.enum class是限定作用域枚举类型,枚举成员的作用域限定在枚举类型所声明的作用域中。
       2.enum class不允许任何隐式转化,但可以显示或使用static_cast进行强制转换。
       3.enum class可以前置声明默认枚举成员是int,enum本身没有默认枚举成员默认类型,但可以指定枚举成员默认类型从而可以前置声明。

文章目录
  1. 1. 枚举类型定义
  2. 2. enum class
  3. 3. enum class与enum区别
    1. 3.1. 避免枚举成员重定义
    2. 3.2. 避免隐式转换
    3. 3.3. 声明前置
  4. 4. 总结