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)