2012-09-25 113 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