一、继承C语言的enum
C++中的枚举是直接从C语言中继承过来的,在这过程中,也做了改进。如C语言中定义一个枚举类型的变量必须加上enum
enum QuarterFirst{JAN, FEB, MAR};//定义类型QuarterFirst
enum QuarterFirst quarter1 = JAN;//定义QuarterFirst类型的变量quarter1
这在定义变量时显得臃肿,C语言都是通过typedef解决的
typedef enum QuarterFirst{JAN, FEB, MAR} QF;
QF quarter1 = JAN;
而在C++中,定义变量时可以省略关键字enum
enum QuarterFirst{JAN, FEB, MAR};//定义类型QuarterFirst
QuarterFirst quarter1 = JAN;//C++中是合法的
但是,早期的C++也存在以下缺陷未进行修补:
- 两个不同的枚举,他们枚举列表中的标识符的作用范围是全局的,不能重复,如以下定义是错误的:
enum Month {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
enum QuarterFirst{JAN, FEB, MAR};
- 默认向整型隐式转换,这导致逻辑错误的东西在理论层面成立
#include <iostream>
enum QuarterFirst{JAN, FEB, MAR};
enum WEEK{MON, TUE, WEN};
int main(void)
{
QuarterFirst quarter1 = JAN;
WEEK week1 = MON;
std::cout << (quarter1 == week1 ? "YES" : "NO") << std::endl;
return 0;
}
虽然说
MON
和
JAN
是两个不同类型,但是在警告之后还是转换成了整型0进行比较,所以结果是
YES
- 无视底层的数据类型,如我们定义
,enum WEEK{MON, TUE, WEN = 0xffffffffU};
在WEN
和G++
下的结果分别如下:MSVC
二、C++的解决方案
将
enum
放入
class
中,默认里面的标识符都是私有的
同时还可以进行成员标识符默认类型的定义
这就相当于给了每个类型一个独立的命名空间,在访问里面的标识符时需要在前面加上类型的名称:
EnumType::Member1
测试代码:
#include <iostream>
enum class Month{JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
enum class QuarterFirst:unsigned int{JAN, FEB, MAR};
enum class WEEK:unsigned int{MON, TUE, WEN};
int main(void)
{
QuarterFirst quarter1 = QuarterFirst::JAN;
WEEK week1 = WEEK::MON;
std::cout << (quarter1 == week1 ? "YES" : "NO") << std::endl;
return 0;
}
如图所示,编译器在
quarter1 == week1
处进行了报错;并且尽管
Month
和
QuarterFirst
里面有一样的标识符,也未报错