2012-09-25 376 views
49

我是C++編程的初學者。枚舉vs強類型枚舉

今天我遇到一個新主題:強類型enum。我已經研究了一下,但直到現在我無法找出爲什麼我們需要這個,以及它的用法是什麼?

例如,如果我們有:

enum xyz{a, b, c}; 
/*a = 0, b = 1, c = 2, (Typical C format)*/ 

爲什麼我們需要這樣寫:

enum class xyz{a, b, c}; 

什麼是我們想在這裏做什麼? 我最重要的疑問是如何使用它。 你能否提供一個小例子,這會讓我明白。

+0

您是否曾瀏覽[wikipedia](http://en.wikipedia.org/wiki/C%2B%2B11#Strongly_typed_enumerations)? – Nobody

+1

@Nobody:是的,我看過'wiki',但無法理解如何使用它,以及有什麼好處。 –

回答

72

OK,第一個例子:舊式枚舉沒有自己的範圍:

enum Animals {Bear, Cat, Chicken}; 
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared! 

enum class Fruits { Apple, Pear, Orange }; 
enum class Colours { Blue, White, Orange }; // no problem! 

其次,他們含蓄地轉換爲整數類型,這可能會導致奇怪的現象:

bool b = Bear && Duck; // what? 

最後,您可以指定C++ 11枚舉的基本整數類型:

enum class Foo : char { A, B, C}; 

以前,未指定基礎類型,這可能會導致平臺之間的兼容性問題。 編輯在評論中指出,您也可以在C++ 11中指定「舊式」枚舉的基本整型。

+0

我們是否需要聲明/定義'enum class Colours'和'enum class Fruits'。因爲當我在VS 2010中編寫代碼時。它在'class'下面引發一個錯誤'「,期望定義或標籤名稱。 –

+0

可能是你是對的。我會檢查一樣的。 –

+0

另外:對於C++ 11中的「普通」枚舉類似於C++ 98,缺省底層類型未定義 – bruziuz

7

對於C-enums,enum class的值確實是enum class的類型,而不是underlying_type

enum xyz { a, b, c}; 
enum class xyz_c { d, f, e }; 

void f(xyz x) 
{ 
} 

void f_c(xyz_c x) 
{ 
} 

// OK. 
f(0); 
// OK for C++03 and C++11. 
f(a); 
// OK with C++11. 
f(xyz::a); 
// ERROR. 
f_c(0); 
// OK. 
f_c(xyz_c::d); 
13

有一篇關於枚舉的好文章this IBM page,它非常詳細,寫得很好。以下是一些重要的要點:

作用域枚舉解決了常規枚舉引起的大多數限制:完整類型安全性,定義明確的基礎類型,作用域問題和前向聲明。

  • 您通過禁止所有範圍枚舉到其他類型的隱式轉換來獲得類型安全性。
  • 您得到一個新的作用域,並且枚舉不再在封閉作用域中,從名稱衝突中保存自身。
  • 作用域枚舉使您能夠指定枚舉的基礎類型,對於作用域枚舉,如果選擇不指定它,則默認爲int。
  • 任何具有固定基礎類型的枚舉都可以前向聲明。
+1

第三點和第四點並非特定於範圍枚舉;您可以指定任何枚舉的基礎類型。 –

3

枚舉範圍

枚舉的統計員出口到周邊範圍。這有兩個缺點。首先,如果在同一範圍內聲明的不同枚舉中的兩個枚舉器具有相同的名稱,則可能導致名稱衝突;其次,不可能使用具有完全限定名稱的枚舉器,包括枚舉名稱。

enum ESet {a0, a, a1, b1, c3}; 
enum EAlpha{a, b, c} 

select = ESet::a; // error 
select = a;  // is ambigious 
2

枚舉類(「新枚舉」,「強枚舉」)解決三個問題,與傳統的C++枚舉:

  1. 傳統enums隱式轉換爲int,導致錯誤,當有人不希望的枚舉作爲一個整數。
  2. 傳統enums將他們的統計員輸出到周圍的範圍,導致姓名衝突。
  3. 無法指定enum的基礎類型,導致混淆,兼容性問題,並且使前向聲明變得不可能。

enum class(「強枚舉」)是強類型和範圍的:

enum Alert { green, yellow, orange, red }; // traditional enum 

enum class Color { red, blue }; // scoped and strongly typed enum 
            // no export of enumerator names into enclosing scope 
            // no implicit conversion to int 
enum class TrafficLight { red, yellow, green }; 

Alert a = 7;    // error (as ever in C++) 
Color c = 7;    // error: no int->Color conversion 

int a2 = red;    // ok: Alert->int conversion 
int a3 = Alert::red;  // error in C++98; ok in C++11 
int a4 = blue;   // error: blue not in scope 
int a5 = Color::blue;  // error: not Color->int conversion 

Color a6 = Color::blue; // ok 

如圖所示,傳統枚舉照常上班,但你現在可以選擇用枚舉的名字資格。

新的枚舉類型是「枚舉類」,因爲它們將傳統枚舉(名稱值)的方面與類的方面(作用域成員和沒有轉換)相結合。

能夠指定的基本類型允許枚舉的簡單的互操作性和保證尺寸:枚舉

enum class Color : char { red, blue }; // compact representation 

enum class TrafficLight { red, yellow, green }; // by default, the underlying type is int 

enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E? 
               // (whatever the old rules say; 
               // i.e. "implementation defined") 

enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U }; // now we can be specific 

這也使前向聲明:

enum class Color_code : char;  // (forward) declaration 
void foobar(Color_code* p);  // use of forward declaration 
// ... 
enum class Color_code : char { red, yellow, green, blue }; // definition 

基礎類型必須是一個有符號或無符號整數類型;默認爲int

在標準庫,enum類用於:

  1. 映射系統特定的錯誤代碼:在<system_error>enum class errc;
  2. 指針安全指標:<memory>enum class pointer_safety { relaxed, preferred, strict };
  3. I/O流誤區:<iosfwd>enum class io_errc { stream = 1 };
  4. 異步通訊錯誤處理:在<future>enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

其中幾個已運營商,如==定義。

+0

從http://www.stroustrup.com/C++11FAQ.html剽竊 – deceze