[C++] ¿Por qué se prefiere la clase enum a la enumeración simple?


Answers

De las preguntas frecuentes de C ++ 11 de Bjarne Stroustrup :

Las enum class ("nuevas enumeraciones", "enums fuertes") abordan tres problemas con las enumeraciones tradicionales de C ++:

  • las enumeraciones convencionales se convierten implícitamente a int, lo que provoca errores cuando alguien no desea que una enumeración actúe como un entero.
  • las enumeraciones convencionales exportan sus enumeradores al ámbito circundante, causando conflictos de nombres.
  • el tipo subyacente de una enum no se puede especificar, lo que genera confusión, problemas de compatibilidad y hace imposible la declaración de reenvío.

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).

Entonces, como lo mencionaron otros usuarios, las "enums fuertes" harían que el código sea más seguro.

El tipo subyacente de una enum "clásica" debe ser un tipo entero lo suficientemente grande como para ajustarse a todos los valores de la enum ; esto es usualmente un int . Además, cada tipo enumerado debe ser compatible con caracteres o un tipo entero con signo / sin signo.

Esta es una descripción amplia de lo que debe ser un tipo enum subyacente, por lo que cada compilador tomará decisiones por sí mismo sobre el tipo subyacente de la enum clásica y, a veces, el resultado podría ser sorprendente.

Por ejemplo, he visto código como este un montón de veces:

enum E_MY_FAVOURITE_FRUITS
{
    E_APPLE      = 0x01,
    E_WATERMELON = 0x02,
    E_COCONUT    = 0x04,
    E_STRAWBERRY = 0x08,
    E_CHERRY     = 0x10,
    E_PINEAPPLE  = 0x20,
    E_BANANA     = 0x40,
    E_MANGO      = 0x80,
    E_MY_FAVOURITE_FRUITS_FORCE8 = 0xFF // 'Force' 8bits, how can you tell?
};

En el código anterior, algunos codificadores ingenuos piensan que el compilador almacenará los valores E_MY_FAVOURITE_FRUITS en un tipo de 8 E_MY_FAVOURITE_FRUITS sin firmar ... pero no hay garantía al respecto: el compilador puede elegir unsigned char o int o short , cualquiera de esos tipos son grandes suficiente para todos los valores vistos en la enum . Agregar el campo E_MY_FAVOURITE_FRUITS_FORCE8 es una carga y no obliga al compilador a hacer ningún tipo de elección sobre el tipo subyacente de la enum .

Si hay algún fragmento de código que se basa en el tamaño de tipo y / o asume que E_MY_FAVOURITE_FRUITS tendría algún ancho (por ejemplo, rutinas de serialización), este código podría comportarse de maneras extrañas dependiendo de los pensamientos del compilador.

Y para empeorar las cosas, si algún compañero de trabajo agrega sin cuidado un nuevo valor a nuestra enum :

    E_DEVIL_FRUIT  = 0x100, // New fruit, with value greater than 8bits

¡El compilador no se queja! Simplemente cambia el tamaño del tipo para que se ajuste a todos los valores de la enum (suponiendo que el compilador utilizara el tipo más pequeño posible, que es una suposición que no podemos hacer). Esta adición simple y descuidada a la enum podría romper la sutileza del código relacionado.

Dado que C ++ 11 es posible especificar el tipo subyacente para la clase enum y enum class (gracias rdb ), este problema se aborda con rdb :

enum class E_MY_FAVOURITE_FRUITS : unsigned char
{
    E_APPLE        = 0x01,
    E_WATERMELON   = 0x02,
    E_COCONUT      = 0x04,
    E_STRAWBERRY   = 0x08,
    E_CHERRY       = 0x10,
    E_PINEAPPLE    = 0x20,
    E_BANANA       = 0x40,
    E_MANGO        = 0x80,
    E_DEVIL_FRUIT  = 0x100, // Warning!: constant value truncated
};

Especificando el tipo subyacente si un campo tiene una expresión fuera del rango de este tipo, el compilador se quejará en lugar de cambiar el tipo subyacente.

Creo que esta es una buena mejora de seguridad.

Entonces, ¿ por qué se prefiere la clase enum a la enumeración simple? , si podemos elegir el tipo subyacente para las enum class con ámbito ( enum class ) y sin ámbito ( enum ), ¿qué más hace que la enum class sea ​​una mejor opción ?:

  • No convierten implícitamente a int .
  • No contaminan el espacio de nombres circundante.
  • Ellos pueden ser declarados adelante.
Question

Escuché a algunas personas recomendar utilizar clases enum en C ++ debido a su tipo de seguridad .

Pero, ¿qué significa esto realmente?




Las enumeraciones se utilizan para representar un conjunto de valores enteros.

La palabra clave class después de la enum especifica que la enumeración está fuertemente tipada y sus enumeradores tienen un ámbito. De esta manera, las clases enum previenen el uso indebido accidental de las constantes.

Por ejemplo:

enum class Animal{Dog, Cat, Tiger};
enum class Pets{Dog, Parrot};

Aquí no podemos mezclar los valores de Animal and Pets.

Animal a = Dog;       // Error: which DOG?    
Animal a = Pets::Dog  // Pets::Dog is not an Animal



Links