枚举类型(enumeration)是C及C++中一个基本的内置类型,不过也是一个有点”奇怪”的类型。从枚举的本意上来讲,就是要定义一个类别,并穷举同一类别下的个体以供代码中使用。由于枚举来源于C,所以出于设计上的简单的目的,枚举值常常是对应到整型数值的一些名字,比如:
// 匿名枚举
enum {Red, Green, Blue};
// 有名枚举
enum Colors{Red, Green, Blue};
在枚举类型中的枚举值编译器会默认从0开始赋值,而后依次向下递增,也就是说Red=0,Green=1,Blue=2。
代码示例:
#include
using namespace std;
enum Day {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
void test01() {
Day day = Thursday;
if (day == 3) {
cout << "今天星期四, 明天星期五" << endl;
}
if (day == Thursday) {
cout << "今天星期四, 明天星期五" << endl;
}
}
int main() {
test01();
return 0;
}
程序会输出两行 “今天星期四, 明天星期五”
也就是说既可以用数字也可以用原文
当然也可以显示指定枚举常量的值, 后面没指定的就会依次递增:
enum Day {
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
void test01() {
Day day = Thursday;
if (day == 3) {
cout << "今天星期四, 明天星期五" << endl;
}
if (day == Thursday) {
cout << "今天星期四, 明天星期五" << endl;
}
}
这样只会输入一条语句 “今天星期四, 明天星期五”
Thursday = 4;
如果再test01中加入这一句, 就会报错: 表达式必须是可以修改的左值
也就是说我把周四改为100的话,那周五六日就是101, 102, 103, 但是前面的值不变
enum Day {
Monday = 1,
Tuesday,
Wednesday,
Thursday = 100,
Friday,
Saturday,
Sunday
};
void test03() {
cout << (int)Tuesday << endl; // 2
cout << (int)Friday << endl; // 101
}
enum color {red,green};
int main()
{
enum color white; //定义一个新枚举成员,无初始值
white=(enum color)4;
printf("%d\n",white); //4
white=red;
printf("%d\n",white); //0
return 0;
}
C/C++的enum有个很”奇怪” 的设定,就是具名(有名字)的enum类型的名字,以及 enum 的成员的名字都是全局可见的。这与 C++中具名的 namespace、class/struct 及 union 必须通过名字::成员名的方式访问相比是格格不入的,编码过程中一不小心程序员就容易遇到问题。比如∶
enum China {Shanghai, Dongjing, Beijing, Nanjing};
enum Japan {Dongjing, Daban, Hengbin, Fudao};
上面定义的两个枚举在编译的时候,编译器会报错,具体信息如下:
error C2365: “Dongjing”: 重定义;以前的定义是“枚举数”
错误的原因上面也提到了,在这两个具名的枚举中Dongjing是全局可见的,所有编译器就会提示其重定义了。
另外,由于C中枚举被设计为常量数值的”别名”的本性,所以枚举的成员总是可以被隐式地转换为整型,但是很多时候我们并不想这样。
针对枚举的缺陷,C++11标准引入了一种新的枚举类型,即枚举类,又称强类型枚举(strong-typed enum)。声明强类型枚举非常简单,只需要在 enum 后加上关键字 class。比如∶
// 定义强类型枚举
enum class Colors{Red, Green, Blue};
强类型枚举具有以下几点优势∶
::
来访问枚举常量。enum class Colors :char { Red, Green, Blue };
wchar_t 是什么?
再看普通枚举的例子, 再Day前面加上Class后, test01的代码应该为:
void test01() {
Day day = Day::Thursday;
if ((int)day == 3) {
cout << "今天星期四, 明天星期五" << endl;
}
if (day == Day::Thursday) {
cout << "今天星期四, 明天星期五" << endl;
}
}
了解了强类型枚举的优势之后,我们再看一段程序:
enum class China { Shanghai, Dongjing, Beijing, Nanjing, };
enum class Japan :char { Dongjing, Daban, Hengbin, Fudao };
void test02()
{
// int m = Shanghai; // error
// int n = China::Shanghai; // error
if ((int)China::Beijing >= 2)
{
cout << "ok!" << endl;
}
cout << "size1: " << sizeof(China::Dongjing) << endl;
cout << "size2: " << sizeof(Japan::Dongjing) << endl;
}
相比于原来的枚举,强类型枚举更像是一个属于C++的枚举。但为了配合新的枚举类型,C++11还对原有枚举类型进行了扩展:
enum Colors : char { Red, Green, Blue };
enum Colors : char { Red, Green, Blue };
int main()
{
Colors c1 = Green; // C++11以前的用法
Colors c2 = Colors::Green; // C++11的扩展语法, 更严谨
return 0;
}
上面程序中第4、5行的写法都是合法的。
C++11中对原有枚举类型的这两个扩展都保留了向后兼容性,也方便了程序员在代码中同时操作两种枚举类型。此外,我们在声明强类型枚举的时候,也可以使用关键字enum struct。实际上 enum struct 和enum class在语法上没有任何区别(enum class 的成员没有公有私有之分,也不会使用模板来支持泛化的声明 )。