C++ Primer第五版笔记--枚举类型
枚举类型可以将一组整型常量组织在一起;和类一样,每个枚举类型定义了一种新的类型;枚举属于字面常量类型。
C++包含两种枚举:限定作用域(C++11新标准引入)的和不限定作用域的:
定义限定作用域的枚举类型的一般形式是:首先是关键字enum class(或者等价的使用struct),之后是枚举类型名字以及用花括号括起来的以逗号分割开来的枚举成员列表,最后是一个分号:
enum class open_modes{input,output,append};
定义不限定作用域的枚举类型时省略关键字class(或struct),枚举类型的名字是可选的:
enum color{red,yelow,blue};
enum {floatPrec = 6,doublePrec = 10,double_doublePrec = 10};
枚举成员
在限定作用域的枚举类型中,枚举成员的名字遵循常规的作用域准则,并且在枚举类型的作用域外是不可访问的。与之相反,在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同:
//定义
enum color{red,yellow,green}; //不限定作用域的枚举
enum stoplight{red,yellow,green}; //报错:重复定义枚举成员
enum class Peppers{red,yellow,green}; //正确,外面的被隐藏了
//使用
coler a = green; //正确
Peppers p = green; //报错,这个green被认为是color的
Peppers p2 = Peppers::red; //正确
默认情况下,枚举成员的值是从0开始的,依次加1,不过是可以专门指定枚举成员的值,并且枚举成员的值也可以不唯一:
enum class intTypes{
charType = 8,shortType = 16,intType = 16,
longType = 32,long_longType = 64
};
枚举成员是const的,因此在初始化枚举成员时提供的枚举值必须是常量表达式,即每个枚举成员本身就是一条常量表达式,可以在任何需要常量表达式的地方使用枚举成员。例如,定义枚举类型的constexpr(有编译器检查变量是否是一个常量表达式)变量:
constexpr intTypes ch = intTypes::charType;
枚举定义新的类型
和类一样,枚举也能定义新的类型,只要enum有名字,我们就能定义并初始化enum对象并为该对象赋值,必须使用该类型的一个枚举成员或该类型的另一个对象:
open_modes om = 2; //错误,2不是该枚举的成员
om = open_modes::input; //正确
值得注意的是一个不限定作用域的枚举类型的对象或是枚举成员可以自动转换成整型,可在需要的地方使用:
int i = color::red; //正确
int j = Peppers::red; //错误,限定作用域的枚举类型不会进行隐式转换。
指定enum大小
尽管每个enum都定义了唯一的类型,但实际上enum是由某种整数类型表示的。在C++11新标准中,可以在enum的名字后面加上冒号以及想在该enum中使用的类型:
enum intValues : unsigned long long {
charTyp = 255,shortTyp = 65535,intTyp = 65536,
longTyp = 4294967296UL,
long_longTyp = 18446744073709551615ULL
};
如果没有指定类型,那么限定作用域的枚举的枚举成员类型默认会是int,
对于不限定作用域的枚举来说,不存在默认的类型,只知道成员的潜在类型足够大,肯定能容纳枚举值。
枚举类型的前置声明
在C++11新标准中,可以提前声明enum,该前置声明必须指定其成员的大小:
enum intValues : unsigned long long //不限定作用域的枚举必须指定成员类型
enum class open_modes; //限定作用域的枚举类型因为有默认的成员类型,所以不用特意指定
和其他声明一样,enum的声明和定义必须匹配,且不能在同一个文件中先声明一个不限定作用域的enum名字,然后再声明一个同名的限定作用域的enum。
形参匹配与枚举类型
初始化一个enum对象时,必须使用另个enum对象或是该枚举类型的一个枚举成员,因此,即使某个整型值与枚举成员的值相等,它也不能作为函数的enum实参使用:
//不限定作用域的枚举类型
enum Token{
INLINE = 128,VIRTUAL = 129
};
void f(Token);
void f(int);
int main(){
Token curTok = INLINE;
f(128); //精确匹配的f(int)
f(INLINE); //精确匹配的f(Token)
}
虽然不能将整型值传给枚举形参,但是可以将一个不限定作用域的枚举类型的的对象或枚举成员传给整型形参。此时,enum的值转换为int或更大的整型,实际转换的结果由枚举类型的潜在类型(由机器决定)决定:
void newf(unsigned char);
void newf(int);
unsigned char uc = VIRTUAL;
newf(VIRTUAL); //匹配newf(int)
new(uc); //匹配newf(unsigned char)