2012-09-25 16 views
49

Soy un principiante en la programación en C++.Enum vs Enum fuertemente tipada

Hoy encuentro un nuevo tema: fuertemente tipado enum. Lo he investigado un poco, pero hasta ahora no puedo averiguar por qué lo necesitamos y de qué sirve el mismo.

Por ejemplo si tenemos:

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

¿Por qué es necesario para escribir:

enum class xyz{a, b, c}; 

Lo que estamos tratando de hacer aquí? Mi duda más importante es cómo usarlo. Podría darme un pequeño ejemplo que me haga entender.

+0

¿Has echado un vistazo a [wikipedia] (http://en.wikipedia.org/wiki/C%2B%2B11#Strongly_typed_enumerations)? – Nobody

+1

@ Nadie: Sí, miré 'wiki' pero no pude entender cómo usarlo, y cuáles son los beneficios. –

Respuesta

72

OK, primer ejemplo: las enumeraciones de estilo antiguo no tienen su propio ámbito:

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! 

En segundo lugar, implícitamente convertir a tipos enteros, lo que puede conducir a un comportamiento extraño:

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

Finalmente, puede especificar el tipo integral subyacente de C++ 11 enumeraciones:

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

Anteriormente, no se especificaba el tipo subyacente, lo que podría causar problemas de compatibilidad entre plataformas. Editar Se ha señalado en los comentarios que también se puede especificar el tipo integral subyacente de una enumeración de "estilo antiguo" en C++ 11.

+0

¿Necesitamos declarar/definir 'enum class Colours' y' enum class Fruits'. Porque cuando escribí el código en VS 2010. Se arroja un error "espera una definación o un nombre de etiqueta" bajo "clase". –

+0

Puede ser que tengas razón. Verificare lo mismo. –

+0

También: para la enumeración "ordinaria" en C++ 11 como en C++ 98 el tipo subyacente predeterminado no está definido – bruziuz

7

Los valores de enum class son realmente del tipo enum class, no underlying_type como para C-enums.

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

Hay un buen artículo sobre enums en this IBM page, es muy detallado y está bien escrito. Estos son algunos puntos importantes en pocas palabras:

Las enumeraciones delimitadas resuelven la mayoría de las limitaciones incurridas por las enumeraciones regulares: tipo completo de seguridad, tipo subyacente bien definido, problemas de alcance y declaración directa.

  • Obtiene seguridad de tipo texto al no permitir todas las conversiones implícitas de enumeraciones de ámbito a otros tipos.
  • Obtiene un nuevo ámbito, y la enumeración ya no se encuentra en el alcance adjunto, salvándose de los conflictos de nombres.
  • Enums con ámbito le da la capacidad de especificar el tipo subyacente de la enumeración, y para las enumeraciones de ámbito, por defecto se establece en int si elige no especificarlo.
  • Cualquier enum con un tipo subyacente fijo se puede anunciar.
+1

El tercer y cuarto punto no son específicos de las enumeraciones con ámbito; puede especificar el tipo subyacente de cualquier enumeración. –

3

Enum Alcance

enumeraciones exportar sus enumeradores al ámbito circundante. Esto tiene dos inconvenientes. En primer lugar, puede generar conflictos de nombres si dos enumeradores en enum diferentes declarados en el mismo ámbito tienen el mismo nombre; segundo, no es posible usar un enumerador con un nombre completamente calificado, incluido el nombre enum.

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

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

Las clases de enumeración ("nuevas enumeraciones", "enumeraciones fuertes") frente a tres problemas con la tradicional C enumeraciones ++:

  1. convencional enums implícitamente convertir a int, causando errores cuando alguien no quiere una enumeración para actuar como un entero.
  2. convencional enums exportan sus enumeradores al ámbito circundante, causando conflictos de nombres.
  3. No se puede especificar el tipo subyacente de enum, lo que genera confusión, problemas de compatibilidad y hace imposible la declaración de reenvío.

enum class ("enumeraciones fuertes") son de tipo firme y scoped:

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 

Como se muestra, las enumeraciones trabajo tradicional, como de costumbre, pero ahora se puede calificar opcionalmente con el nombre de la enumeración.

Las nuevas enumeraciones son "clase enum" porque combinan aspectos de enumeraciones tradicionales (valores de nombres) con aspectos de clases (miembros con ámbito y ausencia de conversiones).

Ser capaz de especificar el tipo subyacente permiten la interoperabilidad simple y tamaños garantizados de enumeraciones:

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 

También permite la declaración de avance de las enumeraciones:

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 

El tipo subyacente debe ser una de las tipos enteros con signo o sin signo; el valor predeterminado es int.

En la biblioteca estándar, enum clases se usan para:

  1. sistemas de cartografía códigos de error específicos: En <system_error>: enum class errc;
  2. indicadores de seguridad
  3. Puntero: En <memory>: enum class pointer_safety { relaxed, preferred, strict };
  4. de E/S de errores de transmisión en: En <iosfwd>: enum class io_errc { stream = 1 };
  5. comunicaciones asíncronas de gestión de errores: En <future>: enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

varios de estos han operadores, tales como == definido.

+0

plagiado de http://www.stroustrup.com/C++11FAQ.html – deceze