1.enum常量与enum变量
对于enum类型,定义enum时在{}中定义的属于enum常量,这些量不可以被更改,同时可以在程序中任意地方声明一个enum变量,但enum变量必须用enum常量进行赋值。
enum myenum
{
first, //enum常量
second //enum常量
};
.......
enum enumVar = first; //enum变量用enum常量进行赋值初始化,这里注意要在一个命名空间内。
2.在C语言中对于enum类型:
K&R的The C Programmingh Language 2nd,书中说:“尽管可以声明enum类型的变量,但编译器不检查这种类型的变量中存储的值是否为该枚举的有效值。不过,枚举变量提供这种检查,因此枚举比#define更具优势。”枚举变量提供这种检查,什么意思?枚举变量会自己检?当然不是,作者也许想说程序员自己可以写个程序检查付给枚举变量的值是否为该枚举的有效值。
#include < stdio.h >
/* 枚举类型 */
enum months{JAN = 1 , FEB};
/* 函数原型 */
void enumeration( enum months m);
main()
{
enum months a = 2;
enum months b = 50 ; /* C中不需要强制转换为enum months类型 */
enum months c = JAN;
enumeration(a);
enumeration(b);
return 0 ;
}
/* enumeration函数:检测枚举变量存储的值是否为该枚举的有效值 */
void enumeration( enum months m)
{
switch (m)
{
case JAN:
printf( " JAN: %d\n " , JAN);
break ;
case FEB:
printf( " FEB: %d\n " , FEB);
break ;
default :
printf( " %d不是该枚举的有效值!\n " , m);
break ;
}
}
而这段代码如果改为C++源文件编译,却不能通过。原因如下:
根据C标准的规定,枚举常量的类型为int,枚举变量的类型应该与char、有符号或无符号整型兼容。因此,枚举变量可以接受 char、有符号或无符号整型数,而不限于仅从此枚举类型所定义的枚举常量中取值。由于上述原因,在C語言中无法从語法上保证枚举变量只能在定义的枚举成员中取值,只能由程序员自身保证不使用除枚举成员之外的值。
关于這一点,很多介绍C语言的书上或者资料上的描述是不正确的,应该加以注意。
但是,如果给枚举变量赋枚举成员之外的值,有的编译器可能会对此产生警告,有的则不會。因为这种行为不违反C标准的规定,编译器对此如何反应都是有道理的。
然而对于C++来说,编译器会禁止给枚举变量赋予枚举成员之外的值。这是因为C++是一种强类型语言,枚举类型不等同于 int 等其它类型。虽然枚举类型可以隐式转化为 int 等类型,但是 int 等类型却不能自动转化为枚举类型,除非使用强制类型转化。因此,如果不使用强制类型转化的话,给枚举变量赋值则只能从枚举成员中选择。对于枚举类型要避免使用强制类型转换。原因如下:
The C++ Programming Language上说:
如果某个枚举中所有枚举值非负,枚举的表示范围为[0 : 2^k-1];其中2^K是使所有枚举成员位于此范围内的最小的2的幂;如果是负的,就是[-2^k : 2^k-1]。 因此对一个给定的整数值,如果使用强制类型转换,而其值又不在枚举的表示范围以内,其行为是未定义的。
// 包含头文件
#include < iostream.h >
int main()
{
enum months{JAN = 1 , FEB, MAR};
// enum months a = 1; // cannot convert from 'const int' to 'enum main::months'
enum months a = ( enum months) 1 ;
cout << " a: " << a << endl; // 输出: a: 1
enum months b = ( enum months) 10 ;
cout << " b: " << b << endl; // 输出: b: 10 虽然输出10,但结果是未定义的,因为此枚举的表示范围为:0~3
return 0 ;
}
在C++中使用枚举类型不需要像C#中那样需要类型名作为标识符的一部分,如HTTP在C#中需要用TransProtocol::HTTP。这样在大型项目中将可能会出现命名冲突的问题,通常主要有几种解决方法。
1) 加前缀。例如,为TransProtocol的第一个成员都增加一个前缀ETP_,即:
enum TransProtocol { ETP_HTTP, ETP_FTP };
2) 使用命名空间,例如
namespace TransProtocol { enum TransProtocol { HTTP, FTP }; }
这样,在用到HTTP或FTP时就需要在前面加上域标识符TransProtocol::HTTP。
3) 将enum定义为类的嵌套类型。
class DataTransfer
{
public:
enum TransProtocol { HTTP, FTP };
......
};
DataTransfer::TransProtocol prot = DataTransfer::HTTP;
其实,后两种方案用法基本相同,可以根据引用所定义枚举的范围选择使用,不推荐使用第1种方法。