天天看點

C++ 枚舉 【強類型枚舉(Strongly-typed enums)】

參考:https://www.cnblogs.com/yyxt/p/4244953.html

1、枚舉enum的用途淺例

      寫程式時,我們常常需要為某個對象關聯一組可選alternative屬性.例如,學生的成績分A,B,C,D等,天氣分sunny, cloudy, rainy等等。

      更常見的,打開一個檔案可能有三種狀态:input, output和append. 典型做法是,對應定義3個常數,即:

const int input = 1;
      const int output = 2;
      const int append = 3;      

然後,調用以下函數:

bool open_file(string file_name, int open_mode);      

比如,

open_file("Phenix_and_the_Crane", append);      

       這種做法比較簡單,但存在許多缺點,主要的一點就是無法限制傳遞給open_file函數的第2個參數的取值範圍,隻要傳遞int類型的值都是合法的。(當然,這樣的情況下的應對措施就是在open_file函數内部判斷第二個參數的取值,隻有在1,2,3範圍内才處理。)

       使用枚舉能在一定程度上減輕這種尴尬(注1),它不但能實作類似于之前定義三個常量的功能,還能夠将這三個值組合起來成為獨一無二的組。例如:

enum open_modes {input = 1, output, append};      

      以上定義了open_modes為枚舉類型enumeration type。每一個命名了的枚舉都是唯一的類型,是一個類型标示器type specifier。例如,我們可以重新寫一個open_file函數:

bool open_file(string file_name, open_modes om);      

      在open_modes枚舉中,input, output, append稱為枚舉子enumerator, 它們限定了open_modes定義的對象的取值範圍。這個時候,調用open_file函數和之前的方法還是一模一樣: 

open_file("Phenix_and_the_Crane", append);      

     但是,如果傳遞給open_file的第二個參數不是open_modes枚舉類型值的話(注1),那麼編譯器就會識别出錯誤;就算該參數取值等價于input, output, append中的某個,

也一樣會出錯哦!例如:

open_file("Phenix_and_the_Crane", 1);      

2、枚舉的定義

      一個枚舉是一個類型,可以儲存一組由使用者刻畫的值。定義之類,枚舉的使用很像一個整數類型。

枚舉的定義具有以下形式,即以關鍵詞enum開頭,接着一個可選的枚舉名,下來是由大括号{}包含着一個由逗号分隔的枚舉子清單enumerators list:

enum [enumeration name] {enumerator1[=value1], enumerator2[=value2], ...};      

3、枚舉子的類型和取值

      枚舉子的類型就是它所在的那個枚舉,例如前面說到的open_modes枚舉中,input,output和append等枚舉子的類型都是open_modes。這種做法,其實是為了賦予使用者和編譯器一些有關該變量拟議中的用途的提示。

      預設下,第一個枚舉子被指派0,接下來的枚舉子取值是前面一個枚舉子的取值+1,例如:

enum weather {sunny, cloudy, rainy, windy};      

其中

sunny == 0, 
      cloudy == 1,
      rainy == 2,
      windy == 3;      

       以上是預設情況,有時候我們希望顯式地指定某個枚舉子的值,那麼會出現什麼情況呢?看看:

enum some_fruit {apple = 3, orange, banana = 4, bear};      

       好了,apple == 3, banana == 4; 那麼orange和bear呢?記得前面說過一句,預設下”接下來的枚舉子取值是前面一個枚舉子的取值+1“。既然這兩個枚舉子沒有顯式指派,那麼就按照預設規則辦事,是以 orange == 4, bear == 5. 

       從這個例子也可以看出,同一枚舉中枚舉子的取值不需要唯一。這樣有什麼用處呢?下面是個簡單的例子:

enum some_big_cities {
                                 Guangzhou = 4, 
                                 Shenzhen    = 4, 
                                 Hongkong   = 4, 
                                 Shanghai    = 2, 
                                 Beijing         = 3, 
                                 Chongqi      = 3
                              };      

以上簡單地按區域,将五個城市按照華南(4),華東(2), 華北(3)的幾個城市分類了。

4、枚舉變量的定義、初始化和指派

     既然每個枚舉都是一個類型,那麼由這個類型自然可以聲明變量,例如,由前面定義的some_big_cities:

     some_big_cities where_I_am;

     需要注意的是,在聲明where_I_am時沒有初始化,如果這時列印where_I_am的值: 

enum some_big_cities {
                             Guangzhou = 4, 
                             Shenzhen = 4, 
                             Hongkong = 4, 
                             Shanghai = 2, 
                             Beijing = 3, 
                             Chongqi = 5
                };
int main(void)
{ 
     some_big_cities wh;
     cout<<"the value is: "<<wh<<endl;
     return 0;
}      

輸出将是the value is: 1. 然而,如果聲明wh為全局變量,則另一種情況:

enum some_big_cities {
              Guangzhou = 1,
              Shenzhen = 1, 
              Hongkong = 1, 
                        Shanghai = 2,
              Beijing = 3,   
              Chongqi = 5
            };
some_big_cities wh;
int main(void)
{ 
   cout<<"the value is: "<<wh<<endl;  
   return 0;
}      

輸出将是the value is: 0;

      以上結果是在Visual C++ 2005 Express中得到,不知道其它編譯器情況如何,也不知為什麼得到這樣的結果。下來再找找資料。

     定義一個枚舉變量時,可以給它初始化,例如:

some_big_cities wh = Guangzhou;      

     注意等号右邊隻能取枚舉子中的某一個;特别地,以Guangzhou為例,雖然Guangzhou==4, 但以下初始化是出錯的:

some_big_cities wh = 4;      

     Visual C++ 2005編譯器提示:

        error C2440: 'initializing' : cannot convert from 'int' to 'some_big_cities'

      可見,不能直接地把一個整型指派給一個枚舉變量,因為枚舉和整型是不同類型的,除非顯式轉換。關于枚舉與整型的關系,後面再講。

      除了初始化,枚舉變量也有指派運算:

some_big_cities wh;
     wh = Guangzhou;
     wh = Shanghai;      

或者

some_big_cities wh1 = Guangzhou;
    some_big_cities wh2 = Shanghai;
    wh2 = wh1;      

5、枚舉的取值範圍

   如果某個枚舉中所有枚舉子的值均非負,該枚舉的表示範圍就是[0:2^k-1],其中2^k是能使所有枚舉子都位于此範圍内的最小的2的幂;如果存在負的枚舉值,該枚舉的取值範圍就是[-2^k,2^k-1].例如:

enum e1 {dark, light}; //範圍0:1
    enum e3 {min = -10, max = 1000}; //範圍-1024:1023      

6、枚舉與整型的關系

    整型值隻能顯式地轉換成一個枚舉值,但是,如果轉換的結果位于該枚舉取值範圍之外,則結果是無定義的。

enum e1 {dark = 1, light = 10};
     e1 VAR1 = e1(50); //無定義
     e1 VAR2 = e1(3); //編譯通過      

     在這裡也說明了不允許隐式地從整型轉換到枚舉的原因,因為大部分整型值在特定的枚舉裡沒有對應的表示。 

      至于枚舉可以當作特定的整型數來用的例子,從open_modes可以體會。

7、自定義運算符

      枚舉是使用者自定義類型,是以在使用者可以為它定義自身的操作,例如++或者<<等。但是,在沒有定義之前,不能因為枚舉像整型就可以預設使用,例如:

enum SomeCities
{
   zhanjiang,
   Maoming,
   Yangjiang,
   Jiangmen,
   Zhongshan
};
SomeCities oneCity;
for (oneCity = zhanjiang; oneCity != Zhongshan; ++oneCity)
{
   cout<<oneCity<<endl;
}      

以上的++OneCity是沒有定義的,在Visual C++ 6 編譯下得到如下錯誤:

error C2675: unary '++' : 'enum main::SomeCities' does not define this operator or a conversion to a type acceptable to the predefined operator

8、Sizeof

    一個枚舉類型的sizeof就是某個能夠容納其範圍的整型的sizeof, 而且不會大于sizeof(int), 除非某個枚舉子的值不能用int或者unsigned int來表示。

      在32位機器中,sizeof(int)一般等于4。前面介紹的所有枚舉,例如,

enum SomeCities
{
   zhanjiang,
   Maoming,
   Yangjiang,
   Jiangmen,
   Zhongshan
};      

計算其sizeof, 可能是1,也可能是是4。在我的intel E2160雙核、32位機器中,得到4。

-----------------------------------------------------------------------------------

[注1, Begin]

由于通過将整型數顯式轉換就可能得到對應枚舉類型的值,是以聲明一個枚舉來達到限制傳遞給函數的參數取值範圍還是力不從心的,以下是一個例子:

enum SomeCities
{
  zhanjiang=1, //1
  Maoming,     //2
  Yangjiang,   //3
  Jiangmen,   //4
  Zhongshan = 1000 //1000
};
void printEnum(SomeCities sc)
{
  cout<<sc<<endl;
}
int main(void)
{
  SomeCities oneCity = SomeCities(50); //将50通過顯式轉換,為oneCity指派 
  printEnum(oneCity); //在VC++ 6 編譯器下得到50輸出
  return 0;
}      

以上例子說明,雖然SomeCities的定義裡沒有指派為50的枚舉值,但是,由于50在該枚舉的取值範圍内,是以通過顯式聲明得到一個有定義的枚舉值,進而成功傳遞給printEnum函數。

[注1, End]

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

一、簡述

  強類型枚舉(Strongly-typed enums),号稱枚舉類型,是C++11中的新文法,用以解決傳統C++枚舉類型存在的缺陷。傳統C++中枚舉常量被暴漏在外層作用域中,這樣若是同一作用域下有兩個不同的枚舉類型,但含有相同的枚舉常量也是不可的,比如:

enum Side{Right,Left};
enum Thing{Wrong,Right};      

這是不能一起用的。 

  另外一個缺陷是傳統枚舉值總是被隐式轉換為整形,使用者無法自定義類型。C++11中的強類型枚舉解決了這些問題。

————————————————————————— 

二、強類型枚舉

  強類型枚舉使用enum class文法來聲明,如下:

enum class Enumeration{
 VAL1,
 VAL2,
 VAL3=      

這樣,枚舉類型時安全的,枚舉值也不會被隐式轉換為整數,無法和整數數值比較,比如(Enumeration::VAL4==10會觸發編譯錯誤)。

 另外枚舉類型所使用的類型預設為int類型,也可指定其他類型,比如:

enum calss Enum:unsigned int{VAL1,VAL2};      

正如前面所說,強類型枚舉能解決傳統枚舉不同枚舉類下同枚舉值名的問題,使用枚舉類型的枚舉名時,必須指明所屬範圍,比如:Enum::VAL1,而單獨的VAL1則不再具有意義。

還有一點值得說明的是C++11中枚舉類型的前置聲明也是可行的,比如:

enum calss Enum;
enum class Enum1:unsigned int;      

————————————————————————— 

三、項目中的強類型枚舉代碼片段

1、圖像處理

enum class Color{RED,BLUE,YELLOR,BLACK,WHITE};      

2.交通燈

enum class TrafficLight{RED,YELLOR,GREEN};      

強類型枚舉值具有傳統枚舉的功能——命名枚舉值,同時又具有類的特點——具有類域的成員和無法進行預設的類型轉換。是以也稱之為枚舉類——enmu class

枚舉類的底層資料必須是有符号或無符号整型,比如char unsigned int unsigned long,預設為int。

3.前置聲明應用

enmu class Clolor:char;  //前置聲明枚舉類
void Foo(Color*p);        //前置聲明的使用
//.................... enum class Color:char{RED,GREEN,BLACK,WHITE}; //前置聲明的定義      

轉載于:https://www.cnblogs.com/lijiaxin/p/10658992.html