C++的enum工具提供了一种创建符号常量的方式 (还有宏定义和const限定符),这种方式可以代替const和宏定义,它还允许定义新类型,但必须按严格的限制进行,使用enum的句法与使用结构体相似:
如下面的语句:
enum spectrum{red, orange, yellow, green, blue, violet, indigo, ultraviolet};
cout << red << endl;
cout << green << endl;
运行结果为:
上边那条声明语句完成两项工作:
1.让spectrum成为新类型的名称,此时spectrum被称为枚举( enumeration)类型,就像struct变量被称为结构类型一样。
2.将red , orange , yellow等作为符号常量,它们对应整数值0~7,这些常量叫作枚举量( enumerator ),在默认情况下编译器将整数值赋给枚举量,第一个枚举量的值为0,第二个枚举量的值为1,依次类推。
直接输出就能看到对应的值,这就是最简单的定义及使用。
前边说过,枚举定义时默认对应的整数值从0开始,那么如何设置自己想要的值呢?
可以使用赋值运算符来显式地设置枚举量的值:
enum bits{one = 1, two = 2,four = 4, eight = 8} ;
但指定的值必须是整数,也可以只显式地定文其中一些枚举量的值:
enum bigstep{first, second = 100,third);
这里,first在默认情况下为0, 后面没有被初始化的枚举量的值将比其前面的枚举量大1, 因此,third的值为101。
当然,也可以创建多个值相同的枚举量:
enum{ zero,null = 0,one,numero__uno = 1};
其中,zero和 null都为0,one和 numero_uno都为1。在C++早期的版本中,只能将int值(或提升为int 的值)赋给枚举量,但这种限制取消了,现在可以使用long甚至 long long类型的值(注意,都是整型)。
为了讲解枚举类型的赋值问题,这里有必要先讲解一下什么是枚举的取值范围。
所谓取值范围就是上界和下界两个值,那么如何求这两个值呢?
为了寻找上界,我们首先需要找到枚举量的最大值,找到大于这个最大值的、最小的2的幂,将它减去1,得到的便是枚举类型取值范围的上界,如果没听懂没关系,我这里举一个例子:
假设有枚举定义如下:
enum bigstep{first, second = 100,third);
在这里了,bigstep里最大值枚举值是third,也就是数字101, 在2的幂中,比这个数大的最小值为128,因此取值范围的上限为127, 要计算下限,需要知道枚举量的最小值, 如果它不小于0,则取值范围的下限为0; 否则,采用与寻找上限方式相同的方式,但加上负号, 例如,如果最小的枚举量为-6,而比它小的、最大的2的幂是-8(加上负号),因此下限为-7。
选择用多少空间来存储枚举由编译器决定。对于取值范围较小的枚举,使用一个字节或更少的空间; 而对于包含long类型值的枚举,则使用4个字节。
C++11扩展了枚举,(增加了作用域内枚举( scoped enumeration), 稍后讲。
枚举变量的属性主要包括赋值和类型转换。
1.对于枚举,只定义了赋值运算符,具体来说没有为枚举类型定义算术运算。
还是拿spectrum作为例子:
enum spectrum{red, orange, yellow, green, blue, violet, indigo, ultraviolet};
spectrum band; //定义一个枚举变量
关于赋值运算如下:
band = bule;//正确
band = 2000;//错误
可以看出,只能将定义枚举时使用的枚举量赋值给这种枚举的变量
那么问题来了,如果我想把其他值赋值给枚举的变量呢?
请继续往下看。
2.枚举量是整型,可被提升为int类型,但是int类型不能自动转换为枚举类型。
(1)枚举可以自动提升为int型
int color = blue;//正确,提升为整型
band = 3; //不正确,int不会降级为emum
color = 3 + red;//正确
在这个例子中,3对应的枚举量是green,但将3赋给 band将导致类型错误,不过将green赋给band是可以的,因为它们都是spectrum类型,表达式3 + red中的加法运算符并非属于枚举类型,而是red被转换为int类型后,使用的是int类型的加法运算符了,因此结果的类型理所当然也是 int。
虽然前面说枚举只定义了赋值运算符,但在这种情况下,可以在算术表达式中同时使用枚举和常规整数。
可能有人要问,那band++呢?
那么我在这里明确告诉你不能这么用,虽然有些编译器认为只要不超过枚举类型取值范围的上界就可以运行,但是更多的编译器则直接告诉你这属于错误代码:
(2)int型不会自动降级为枚举类型
有以下这个例子:
enum spectrum{red, orange, yellow, green, blue, violet, indigo, ultraviolet};
spectrum band; //定义一个枚举变量
band = orange + red; //错误
第三句错误的原因有些复杂,确实没有为枚举定义运算符+,但用于算术表达式中时,枚举将被转换为整数,因此表达式orange + red将被转换为1+0,这是一个合法的表达式,但其类型为int,不能将其赋给类型为spectrum的变量band。
如果 int值是有效的(在枚举类型的范围内), 则可以通过强制类型转换,将它赋给枚举变量:
band = spectrum (3); // typecast 3 to type spectrum
如果试图对一个不适当的值进行强制类型转换,将出现什么情况呢?结果是不确定的,这意味着这样做不会出错,但不能依赖得到的结果:
band = spectrum ( 40003);// undefined
至于确定哪些值合适,哪些值不合适,可以参考前面写的关于如何计算出enum的取值范围。
这里小总结一下并给个例子:
对于枚举来说,只有声明中指出的那些值是有效的,然而,C++现在通过强制类型转换,增加可赋给枚举变量的合法值,根据枚举的取值范围( range ),通过强制类型转换,可以将取值范围中的任何整数值赋给枚举变量,即使这个值不是枚举值。
例如,假设 bits 和 myflag 的定义如下:
enum bitsione = l,two = 2,four = 4, eight = 83;
bits myflag;
则下面的代码将是合法的:
myflag = bits(6);// valid,because 6 is in bits range
其中6不是枚举值,但它位于枚举定义的取值范围内。
最后需要说的是,如果我们打算只使用常量,而不创建枚举类型的变量,则可以省略枚举类型的名称,如下面的例子所示:
enum {red,orange,yellow,green,blue,violet, indigo,ultraviolet}
实际上,枚举更常被用来定义相关的符号常量,而不是新类型。
例如,可以用枚举来定义switch语句中使用的符号常量,我们接着往下看。
前面讲了那么多,我们这里来操作一下:
void useEnum(){
using namespace std;
enum {red,orange,yellow,green,blue,violet,indigo};
cout <<"Enter color code (0-6):";
int code;
cin >>code;
while (code >= red && code <= indigo){
switch (code){
case red : cout <<"Her lips were red. \n" ; break;
case orange : cout<<"Her hair was orange.\n"; break;
case yellow : cout <<"Her shoes were yellow.\n"; break;
case green : cout<<"Her nails were green.\n"; break;
case blue: cout <<"Her sweatsuit was blue.\n"; break;
case violet : cout << "Her eyes were violet.\n"; break;
case indigo : cout <<"Her mood was indigo.\n"; break;
}
cout <<"Enter color code (0-6): ";
cin >> code;
}
cout <<"Byeln";
}
运行结果如下:
传统的枚举存在一些问题,其中之一是两个枚举定义中的枚举量可能发生冲突,假设有一个处理鸡蛋和T恤的项目,其中可能包含类似下面这样的代码:
enum egg{ Small,Medium, Large, Jumbo } ;
enum t_shirt { Small, Medium, Large, Xlarge};
这将无法通过编译,因为egg的Small 和t_shirt的Small 位于相同的作用域内,它们将发生冲突。
为避免这种问题,C++11提供了一种新枚举,其枚举量的作用域为类,这种枚举的声明类似于下面这样:
enum class egg { Small,Medium,Large,Jumbo } ;
enum class t_shirt {Small,Medium,Large,Xlarge};
也可使用关键字struct代替class,无论使用哪种方式,都需要使用枚举名来限定枚举量:
egg choice = egg : :Large; //the Large enumerator of the egg enum
t_shirt Floyd = t shirt:: Large; // the Large enumerator of the t_shirt enum
枚举量的作用域为类后,不同枚举定义中的枚举量就不会发生名称冲突了。
C++11还提高了作用域内枚举的类型安全。在有些情况下,如将其赋给int变量或用于比较表达式时,常规枚举将自动转换为整型,但作用域内枚举不能隐式地转换为整型:
enum egg_old {Small, Medium, Large,Jumbo }; // unscoped
enum class t_shirt {Small, Medium, Large, Xlarge); // scoped
egg_old one = Medium; //unscoped
t_shirt rolf =t_shirt::Large; //scoped
int king = one; // implicit type conversion for unscoped
int ring = rolf; // not allowed,no implicit type conversion
if(king < Jumbo) // allowed
std::cout << "Jumbo converted to int before comparison.\n";
if(king < t_shirt::Medium) // not allowed
std::cout<< "Not allowed:;
```c
但在必要时,可进行显式类型转换:
```c
int Frodo = int(t_shirt:: Small);// Frodo set to 0
枚举用某种底层整型类型表示,在C++98中,如何选择取决于实现,因此包含枚举的结构的长度可能随系统而异,对于作用域内枚举,C++11消除了这种依赖性,默认情况下,CH+11作用域内枚举的底层类型为int,另外,还提供了一种语法, 可用于做出不同的选择:
//underlying type for pizza is short
enum class : short pizza {Small,Medium,Large,XLarge} ;
:short将底层类型指定为short。底层类型必须为整型。在C++11中,也可使用这种语法来指定常规枚举的底层类型,但如果没有指定,编译器选择的底层类型将随实现而异。
以上就是今天要讲的内容,本文主要讲解了一下如何定义枚举类型,设置枚举量的值,获取枚举的取值范围,以及枚举变量的属性,最后使用了一个switch案例讲解了一下如何将枚举量作为switch的标签。同时,我们也关注了C++11中枚举的新特性,希望能对你有所帮助。