深入解析enum

1 enum是一个关键词,我们可以把它和class放到一块理解

为什么可以放到一块理解呢?

①因为我们的enum也可以定义类型,和class一样。如:

Code:
  1. enum weekday{Monday,Tuesday};  

这里的weekday就是一种自定义类型。我们可以用这种类型来定义变量。

如:

Code:
  1. weekday day;  

我们用自定义类型定义了一个变量day。

②enum也有默认构造函数,拷贝构造函数,赋值函数。

我们的enum和类一样同样具有默认构造函数,拷贝构造函数,赋值函数。至于有没有析构函数我就不清楚了。:-)

甚至我们的enum在这方便比class还要强大,因为它可以自动生成有参构造函数,而我们的class只能为我们生成无参默认构造函数。

看个例子:

Code:
  1. #include    
  2. using namespace std;   
  3. enum weekday{Monday,Tuesday};   
  4. int main()   
  5. {   
  6.     weekday b = weekday();//调用默认构造函数,将b初始化为0   
  7.     cout << b << endl;   
  8.     weekday c(b);//调用拷贝构造函数   
  9.     cout << c << endl;   
  10.     c = Tuesday;   
  11.     weekday d = c; //调用拷贝构造函数   
  12.     cout << d << endl;   
  13.     weekday e;   
  14.     e = d; //调用赋值函数   
  15.     cout << e << endl;   
  16.     return 0;   
  17. }  

 从这个例子我们可以清楚的看到enum中默认构造函数,拷贝构造函数,赋值函数的应用。怎么样很神奇吧。还有一个更神奇的呢。enum可以自动为我们生成有参的构造函数。这点class做不到的。:-)

Code:
  1. weekday f = weekday(5);   
  2.     cout << f << endl;  

看,这就是enum为我们生成的有参的构造函数的应用。呵呵。不错吧。

哈哈。enum和class有这么多相似的地方,甚至在有些地方比class还强大些,我们是否可以把它们放到一块理解了呢。呵呵。。

小结: enum 和 class都可以定义自定义类型。

2 enum 和 class的不同

认真的同学也许早发现了。enum中的默认构造函数不像class中的那样可以自动调用,它必须由我们显示的调用它。怎么调用从上面大家就可以看出来。那类中的那种方式呢?看:

Code:
  1. weekday a;   
  2. cout << a << endl;  

结果是未定义的。从这里我们就可以看出,默认的构造函数没有被调用。这点enum又有点靠近内置类型了。即:必须由我们显示的进行初始化,否则便是未定义的。那下面这个呢?

Code:
  1. weekday a();   
  2. cout << a << endl;  

哇,开始很牛啊。。:-),好像是在调用默认构造函数似的。但编译器却不愿意了,它发出了抱怨。。我们第一行错了吗?没有。是第二行。哈哈,奇怪吧。。其实编译器这里并没有把a当成一个变量来看,而是把它当成了一个函数了。奇怪不。。我们看个例子:

Code:
  1. #include    
  2. using namespace std;   
  3. enum weekday{Monday,Tuesday};   
  4. weekday a();   
  5. int main()   
  6. {   
  7.      a();   
  8. }   
  9. weekday a()   
  10. {   
  11.     cout << "hello" << endl;   
  12.     return Monday;   
  13. }  

运行下这个函数,大家就清楚了。。:-)

对于拷贝构造函数,赋值函数的使用enum和类是一样的。然而,类中可以由用户自定义函数,enum可以吗?哇。。

这个就不清楚啦。。我试着在enum里定义函数。编译器却对我火冒三丈。。我怕了。。若你和编译器的关系好,它让你定义了,千万别忘了通知我一声哈。。O(∩_∩)O哈哈~

3 看一下enum的定义

说了老半天了,还没解释enum的定义呢。。罪过罪过。。若那位哥们等烦了,千万

Code:
  1. enum weekday{Monday,Tuesday};  

我们来看下这个定义。

一般格式 enum + 类型名 + { 常量名(可为多个)} + ;

其中类型名可以不要。常量名也可以不要(这时候就没啥具体意义了哈)。

enum定义出来的类型具体是什么类型呢?我们可以看下:

Code:
  1. weekday today;   
  2. cout << sizeof(today) << endl;  

 输出结果为4。在WIN32里这个有点类似整型哈。。呵呵。那它到底是不是整型呢?

而MSDN上是这样描述enum的:" The enum keyword specifies an enumerated type."
An enumerated type is a user-defined type consisting of a set of named constants called enumerators. By default, the first enumerator has a value of 0, and each successive enumerator is one larger than the value of the previous one, unless you explicitly specify a value for a particular enumerator. Enumerators needn’t have unique values. The name of each enumerator is treated as a constant and must be unique within the scope where the enum is defined. An enumerator can be promoted to an integer value. However, converting an integer to an enumerator requires an explicit cast, and the results are not defined.

    In C, you can use the enum keyword and the tag to declare variables of the enumerated type. In C++, you can use the tag alone.In C++, enumerators defined within a class are accessible only to member functions of that class unless qualified with the class name (for example, class_name::enumerator). You can use the same syntax for explicit access to the type name (class_name::tag).

有这段文字我们可以看出enum所定义的类型不能被理解为一个整型。我们就暂把它理解为占4个字节的类型吧。对于这段文字的其它含义,我们在下面一点一点的演示出来.

首先我们看下enum定义时 "{}"中的内容。这里面的内容我们可以称它为枚举数。这些数,都是常量。一经定义是无法改变的。

Code:
  1. #include    
  2. #include    
  3. using namespace std;   
  4. enum weekday{Monday,Tuesday};   
  5. int main()   
  6. {   
  7.     Monday = weekday(5);   
  8.     return 0;   
  9. }  

这时候编译器该发出抱怨了,说“左操作数必须是个左值".意思是说,Monday不能用来做左值。

虽无法改变,但是我们可以在定义的时候给它初始化来达到我们的目的。如:

Code:
  1. enum Days               // Declare enum type Days   
  2. {   
  3.    saturday,            // saturday = 0 by default   
  4.    sunday = 0,          // sunday = 0 as well   
  5.    monday,              // monday = 1   
  6.    tuesday,             // tuesday = 2   
  7.    wednesday,           // etc.   
  8.    thursday,   
  9.    friday   
  10. } today;  

我们可以把任意一个整型值赋给我们的枚举数来改变它的值。默认情况下,第一个枚举数的值为0,往后依次递增。当我们给一个枚举数赋初值后,该枚举数之前按默认情况,之后从该枚举数的值起依次递增。

作用域在这里同样适用。即在enum的定义体里不允许出现两个一样的名字。每个名字都是唯一的。但是各个名字间的值可以相同。即两个不同的名字可以取同样的值。如我们上面的例子中的saturday 和 sunday的值均为0.

4 如何适用enum

我们可以适用enum定义类型。就好似class一样。我们从上面也看到了enum的好多使用。现在我们看下这个使用方法:

首相我们看下类中的这个方法:

Code:
  1. #include    
  2. #include    
  3. using namespace std   
  4. class base   
  5. {   
  6. public:   
  7.     base(){cout << "hello nihao!" << endl;}   
  8. }t;   
  9. int main()   
  10. {      
  11.     return 0;   
  12. };  

大家猜下这个函数有输出结果吗?肯定会有同学说没有,是啊,主函数中什么也没有怎么会有结果呢。。O(∩_∩)O哈哈~

不过这个程序确实有,因为我们定义了一个全局变量t;在定义t的时候自动调用类base的构造函数。输出 hello nihao! 呵呵。。这种方法是不是很那啥啊。。是从结构体继承过来的。。同样enum也可以这样时候,但是enum不会自动调用构造函数。。

Code:
  1. enum weekday{Monday,Tuesday}today;  

此时,today便是一个weekday类型的变量了。但它的值是未定义的。我们如何为定义的变量赋值呢。

上面我们已经讲过了显示调用默认构造函数,有参构造函数,拷贝构造函数,赋值函数为变量赋值。那我们直接可不可以为变量赋值呢。如:

Code:
  1. today = 5;  

这是不可以的,并没有一个整型到enum定义的类型的自动转换。由此可见enum定义的类型不但不是整型,而且还差很远呢。要不咋能不能自动转换呢。:-)

我们如是想直接赋值的话,可以使用强制转换,将整型值转换成enum的定义类型:如:

Code:
  1. today = weekday(5);  

 注:我们上面的直接用类型名定义变量的方法只适用于C++,C语言中是通不过的必须在前面加上enum才可以。

The name of each enumerator is treated as a constant and must be unique within the scope where the enum is defined.

我们在上面MSDN的描述中有这么一句话,其中的几个单词比较显眼。说是枚举数必须在enum定义的范围内。这里的范围何解呢?

5 enum的范围确定

对于这点我还没体会到它的用意,我们引用他人的话来解释这个标题吧:

Code:
  1. For example:    
  2.             enum e1{ a=2, b=4 };    
  3.   
  4. 首先找到其绝对值的最大值,但为了容易理解,我先不谈负数,也就是先找到其最大值,这里的最大值是4。    
  5. 4 用二进制表示就是 100,也就是需要3bits才能最小的容纳下4这个值,而3bits所能表示的范围是 0-7,于是e1的取值范围为[0,7]。    
  6.   
  7. 现在来看看负数,    
  8.             enum e2{ a=-2, b=4 };    
  9. 其中绝对值最大的是4,需要3bits才能容纳下,但因为可以取负值(而最大元素b=4不是负值),也就是说需要增加一个符号位,那么就需要4bits。    
  10. 4bits的取值范围是 1000 - 0111(二进制表示),也就是 -8 到 7(十进制表示)。    
  11. enum e3{ a=-4, b=2 } 就只需要3bits,取值范围是[-4,3]。    
  12. [color=#0000ff]    
  13. [/color]    
  14. [color=#0000ff]简单的说就是找到最少的能容纳下所有的元素的位数[/color]    
  15. 为什么要获取enum的取值范围?因为[color=#0000ff]C++标准规定超出枚举类型表示范围的赋值结果是undefined的[/color]。    
  16. 也就是说 e2 x = (e2)6 是肯定正确的,而 e2 y = (e2)8 行为是未定义的。    
  17. undefined的含义我就不多说了,想怎么去歪解就怎么去歪解^_^    

6 enum的内存非配

enum若定义在类里面:

Code:
  1. class base   
  2. {   
  3. public:   
  4.     enum weekday{Monday,Tuesday}today;   
  5. };  

我们对这个类sizeof后的结果为4.就是today所占的空间。若我们把today去掉。这时候的结果便是1了。即一个空类(其实他已经不是空累了)的大小。即在类中定义enum是不占用空间的。我们如何访问这个enum变量呢。

Code:
  1. base::weekday t = base::weekday(5);   
  2. cout << t << endl;  

我们可以使用类型进行访问。同样对于enum里的枚举数我们也得适用类型进行访问,否则被认为是无定义的(在类外);在类中可以直接进行访问。由此可见类把enum当做static变量进行处理的。。

对于enum所定义的类型变量无论enum定义体里有多少个枚举数,它均占4个字节的空间。(可能不同的编译器不同)。

OK了。。我想对enum了解这么多。。却对是够了。。呵呵。。也许多余了。。。喜欢的了解下。。

参考文章:http://www.chinaunix.net/jh/23/1049411.html

你可能感兴趣的:(NS2)