編程語言中的所有特性都是為了滿足某種需求,達到某個目的還出現.不會莫名其妙的出現在那.
枚舉可以用來保存一組屬性的值.enum的全稱是enumeration意思是列舉
看著這句話可能覺得太書面化了,不夠通俗易懂.那舉些通俗的例子說說.日常生活中我們特喜歡分類,比如讀書時分啥數,理,化.當官的級別有啥省長,市長,縣長.軍隊有軍長,師長,團長.這樣一組組的屬性值就最適合用枚舉類型來表示.當用一個軟件時,有些頁面會有很多單選按鈕(radio button),這也特別適合用枚舉來表示你舉了哪一個.
光這樣說你可能還不能體現枚舉的好處.如果沒枚舉,表示一些組屬性的值你只能用一組數字,或者一組字符串.
數字從字面上看不出任意意義,可讀性非常差,所以很少用.那就假如要你通過比較字符串來做很多種類判斷,比如 if(HisTitle == "stadholder") else if(HistTile == "mayor") .如果讓你敲個幾十次你就知道是件多麻煩痛苦的事了,很多單詞如果敲錯一個意思就完全變了,這樣出現bug了也不容易找到.老是復制粘貼也較麻煩.所以字符串是編輯麻煩,容易出錯.如果要使用枚舉就極大的方便我們敲代碼,集成開發工具中的智能感應會給你提示,敲個點號就帶出來了.而且枚舉會做類型檢查,不會像字符串那樣只能靠你自己去對比.
上面我們講了如果沒有枚舉,一般會想到用數字或字符串表示某個類別.這樣使用肯定不方便.也許你可能會想到用宏來表示.比如#define 市長 "mayor" 或者#define 市長 2
這自然是一個方法,但一來嘛在C++中是不太推薦用宏的,盡量少用.因為C++是強類型的語言,希望通過類型檢查來降低程序中的很多錯誤,而宏只是在編譯期前做簡單替換,繞過了類型檢查,失去了強類型系統的優勢支撐. 二來嘛一組屬性值都是相關聯的信息,必須放到一起,放到一組.
枚舉類型成員是常量
這句話怎麼理解呢.也就是說enum MyEnum{ one = 1 , two , three} ;
與 const int one = 1; const int two = 2; const int three = 3; 差不多是一樣的.
說到常量其實有個非常誤導人的地方因為用宏#define 可以定義的我們說是常量,這裡只涉及到簡單的替換自然不可能存在內存分配問題.但是用const定義的也叫常量,而const定義常量貌似跟定義一般的變量只多個const關鍵字. 你可能會想當然認為常量都只是簡單替換,所以不存在內存分配.那按這個邏輯,豈不是const定義的常量,枚舉類型都沒有內存分配?
實際上大部分時候確實是這樣的.但並非總是如此,有些情況會需要分配內存的.
如果定義常量const int one = 1;然後在其他地方只是把one作為右值賦值給其他變量那就不存在內存分配.但這裡的常量跟#define定義的常量不同,宏定義的常量是編譯前簡單替換掉,而不需要做類型檢查.而const定義的常量在編譯時會幫類型檢查,編譯完之後再做替換.所以編譯完之後就看不到const的信息了,轉換成對應的值.const定義的信息只是保存在符號表中.
那同樣,如果只是enum MyEnum{ one = 1 , two , three} ;這樣定義一個枚舉類型,然後也是簡單的作右值賦值給其他變量.比如int num = MyEnum::one;那也只是保存信息在符號表中,編譯後被替換掉了.
有人可能說如果用sizeof MyEnum測下會發現會是4(這是VS裡面,不同的編譯器可能不一樣)於是認為不管是枚舉裡面有多少個元素內存分配都是4.實際上不是這意思,應該是定義一個MyEnum類型的枚舉變量時會分配內存.這跟定義了一個類一樣,你用sizeof去測一個為也會看到大小,但我們知道只有當類實例化之後才實際分配內存的.
1.)const int one;是類的成員變量 2. )extern const int one = 123; 3.)const int one = 1; int* pConst = &one;
上面三種情況會需要分配內存.
而枚舉類型,如果不是簡單的去給其他變量賦值,而是去定義一個枚舉類型變量.
比如MyEnum grade = MyEnum::one; //此時會分配4字節內存空間.(不過據說編譯器會做優化,如果枚舉類型所有值用兩個字節表示就足夠了,那實際分配的會就只會是兩字節了.不一定就是默認的int類型的長度)
一般的用法是在全局域內定義一個枚舉類型.比如
enum MyEnum { one, two, three }
如果不顯式指定,就會把第一個值默認賦值為0,然後遞增1依次賦值.如果顯式指定了某個值,則它下一個是它加1.
所以上面的例子中默認one = 0; two = 1; three= 2;
如果顯式指定enum MyEnum { one, two = 3, three }
則one = 0; two = 3; three = 4;
定義一個枚舉類型就是MyEnum grade = MyEnum::one;
類中使用枚舉這是不太常用的用法.
在類中聲明一個枚舉後,定義枚舉類型就可以省掉那個域作用前綴.比如MyEnum my = one; 在相同的作用域內也不能出現某個變量的名字和枚舉中的元素名字相同,也就是不能出現其他變量名字是on,two, three
另外枚舉還有一種少見的用法是
enum { one ,two ,three}; 就是不指定一個名字,這樣我們自然也沒法去定義一些枚舉類型了.此時就相當於const int one = 0;這樣定義三個常量一樣.
然後用的話就是int no = one;
初始化時可以賦負數, 以後的標識符仍依次加1;
x = 2;
是不允許是,如果對X進行賦值,只能對3進行類型轉換.即:
x = (string)2;
那麼這樣就對了.
如果給x賦的不是一個整形的數,而是一個字符型的,如:
x = (string)’a’;
那麼這時候x的值並不是字符’a’,而是’a’的ASCII碼,我們知道,在枚舉類型中,各常量的值只能是整形的,所以在對上例會自動的將’a’轉換成一個整數值.從內存的角度來看來話,其實C/C++中整形和字符型的變量是一樣的,它們之間可以互相轉換.
比如定義
namespace A
{
enum B { b1, b2};
class C
{
};
}
其中我們認為B是一種類型,在類型這個方面我們可以理解enmu跟class,struct是平等的,所以我們可以放心的定義
A::B = A::b1;
注意右邊的賦值,本質上b1是直接定義在命名空間A之內的,他相當於A的一個public的const量。
有時候在命名空間中直接定義了太多的enmu是不合理的,這樣會污染命名空間,所以,盡可能的,我們要在類的內部定義enmu變量。
同樣,關於enum的默認數值的問題需要主義。enmu總是從0開始的,如果我們不指定默認值,則兩個在同樣的命名空間的enum將會都從0開始,大部分時候這並不會出現問題,但是為了防患於未然,我們盡量要
1. 將enum定義在合適的命名空間中
2. 為enum指定默認值