He oído a algunas personas recomiendan el uso de la enumeración clases en C++ debido a su tipo de seguridad.

Pero ¿qué significa eso realmente?

  • Cuando alguien afirma que algunos de programación de la construcción es «malo» ellos están tratando de disuadirlo de pensar por sí mismo.
  • Esto es más de una pregunta retórica para proporcionar un FAQ de respuesta (si esto es realmente Frequenty le pide es una historia diferente).
  • hay una discusión sobre si esto debe ser un documento de preguntas frecuentes o no va en la que se inicia aquí. La entrada de la recepción.
  • A veces simplemente están tratando de protegerlo de sí mismo.
InformationsquelleAutor Oleksiy | 2013-08-20

8 Comentarios

  1. 389

    C++ dispone de dos tipos de enum:

    1. enum classes
    2. Llanura enums

    Aquí hay un par de ejemplos de cómo declarar:

     enum class Color { red, green, blue }; //enum class
     enum Animal { dog, cat, bird, human }; //plain enum 

    ¿Cuál es la diferencia entre los dos?

    • enum classes – enumerador nombres son local a la enumeración y sus valores no convertir implícitamente a otros tipos (como cualquier otro enum o int)

    • Llanura enums – donde enumerador nombres están en el mismo ámbito como el de la enumeración y sus
      los valores implícitamente convertir a enteros y otros tipos de

    Ejemplo:

    enum Color { red, green, blue };                    //plain enum 
    enum Card { red_card, green_card, yellow_card };    //another plain enum 
    enum class Animal { dog, deer, cat, bird, human };  //enum class
    enum class Mammal { kangaroo, deer, human };        //another enum class
    
    void fun() {
    
        //examples of bad use of plain enums:
        Color color = Color::red;
        Card card = Card::green_card;
    
        int num = color;    //no problem
    
        if (color == Card::red_card) //no problem (bad)
            cout << "bad" << endl;
    
        if (card == Color::green)   //no problem (bad)
            cout << "bad" << endl;
    
        //examples of good use of enum classes (safe)
        Animal a = Animal::deer;
        Mammal m = Mammal::deer;
    
        int num2 = a;   //error
        if (m == a)         //error (good)
            cout << "bad" << endl;
    
        if (a == Mammal::deer) //error (good)
            cout << "bad" << endl;
    
    }

    Conclusión:

    enum classes debe ser preferido, ya que causa menos sorpresas que potencialmente podría conducir a errores.

    • Buen ejemplo… hay una manera de combinar el tipo de seguridad de la clase de la versión con el espacio de nombres de la promoción de la enumeración versión? Es decir, si tengo una clase A con el estado, y me cree una enum class State { online, offline }; como un niño de clase A, me gustaría hacer state == online de los controles dentro de A en lugar de state == State::online … ¿es posible?
    • Nope. El espacio de nombres de la promoción es una Mala Cosa™ y la mitad de la justificación de la enum class fue para eliminarla.
    • En C++11, puede utilizar explícitamente escrito enumeraciones también, como la enumeración de los Animales: unsigned int {perro, ciervo, gato, pájaro}
    • Nota: en la parte superior de esto, ahora tenemos la explícita tipo subyacente disponible para ambos enum, lo que permite avanzar a la declaración y un control más estricto sobre diseño de clase 🙂
    • ¿Por qué es de Color «color = Color: Color:rojo» un ejemplo de «mal uso de los de la llanura de las enumeraciones»? Es malo simplemente porque es el uso de «llanura de las enumeraciones» o algo más?
    • Todo el bloque es la razón por la llanura de las enumeraciones son malos, no sólo la primera declaración.
    • Plus Plus entiendo que @Oleksiy dice que es malo. Mi pregunta no era si Oleksiy pensaba que era malo. Mi pregunta fue una petición al detalle lo es malo sobre ella. Específicamente, porque ¿ Oleksiy, por ejemplo, considerar la posibilidad de malo Color color = Color::red.
    • Ugh, una vez más, mira el código entre este comentario y » ejemplos de buen uso de la enumeración de las clases (seguro)», no sólo la primera declaración.
    • Plus Plus por Lo que el ejemplo del mal no se produce hasta el if (color == Card::red_card) línea, 4 líneas más adelante que el comentario (que veo que ahora se aplica a la primera mitad de la cuadra.) 2 líneas del bloque da la mal ejemplos. Las 3 primeras líneas no son un problema. El «todo el bloque es la razón por la llanura de las enumeraciones son malos» me tiró como pensé que eso significaba que algo estaba mal con ellos. Voy a ver ahora, es sólo un set-up. En cualquier caso, gracias por los comentarios.
    • Da ejemplos de cómo utilizar las diferentes enum tipos. Pero por qué, ¿por QUÉ no explicar exactamente (como se indica en la pregunta) porque este es el mal y que bien.
    • Otro beneficio que no se menciona es que la clase enum puede ser hacia adelante, declaró.
    • «porque causan menos sorpresas que potencialmente podría conducir a errores.» no lo entiendo. Lo que fue la gran sorpresa en este código?

  2. 213

    De Bjarne Stroustrup C++11 preguntas frecuentes:

    La enum classes («nueva enumeraciones», «fuerte enumeraciones») frente a tres problemas
    con la tradicional C++ enumeraciones:

    • convencional de las enumeraciones implícitamente convertir a int, causando errores cuando alguien no quiere una enumeración para actuar como un entero.
    • convencional de las enumeraciones de exportación de sus enumeradores para el ámbito que lo rodea, provocando el nombre de los enfrentamientos.
    • el tipo subyacente de un enum no se puede especificar, causando confusión, problemas de compatibilidad, y hace avanzar la declaración de
      imposible.

    La nueva enumeraciones son «clase enum» porque combinan aspectos de las enumeraciones tradicionales (los nombres de los valores) con los aspectos de las clases (ámbito de miembros y la ausencia de conversiones).

    Como se ha mencionado por otros usuarios, el «fuerte de las enumeraciones» iba a hacer el código más seguro.

    El tipo subyacente de un «clásico» enum será de tipo entero suficientemente grande para que quepan todos los valores de la enum; esto es generalmente un int. También cada tipo enumerado será compatible con char o un signed/unsigned integer tipo.

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

    Por ejemplo, he visto un código como este a 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 ingenuos coder es pensar que el compilador de la tienda de la E_MY_FAVOURITE_FRUITS valores en un entero de 8 bits tipo… pero no hay ninguna garantía al respecto: el compilador puede elegir unsigned char o int o short, cualquiera de esos tipos son lo suficientemente grandes como para que quepan todos los valores observados en el enum. Agregar el campo E_MY_FAVOURITE_FRUITS_FORCE8 es una carga y no obliga al compilador para que cualquier tipo de elección sobre el tipo subyacente de la enum.

    Si hay alguna pieza de código que se basan en el tipo y/o tamaño se supone que E_MY_FAVOURITE_FRUITS sería de cierta anchura (e.g: la serialización de las rutinas) este código podría comportarse en algunas formas extrañas dependiendo del compilador pensamientos.

    Y para empeorar las cosas, si algún compañero añade descuidadamente un nuevo valor a nuestros enum:

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

    Que el compilador no quejarse! Sólo cambia el tipo de adaptarse a todos los valores de la enum (suponiendo que el compilador estaban utilizando el tipo más pequeño posible, lo cual es una hipótesis que no podemos hacer). Este simple y descuidada además de la enum podría sutileza romper el código relacionado.

    Desde C++11 es posible especificar el tipo subyacente para enum y enum class (gracias rdb) por lo que este problema está perfectamente dirigido:

    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 de la gama de este tipo, el compilador se quejará en lugar de cambiar el tipo subyacente.

    Creo que esta es una buena mejora de la seguridad.

    Así ¿por Qué es la clase enum preferido sobre la llanura enum?, si podemos elegir el tipo subyacente de ámbito(enum class) y ámbito (enum) las enumeraciones ¿qué otra cosa hace enum class una mejor opción?:

    • No convertir implícitamente a int.
    • No contaminar los alrededores de espacio de nombres.
    • Que puede ser hacia adelante-declaró.
    • Supongo que podemos restringir el tipo base de la enumeración para regular las enumeraciones, así que el tiempo que tenemos de C++11
    • Lo siento, pero esta respuesta es incorrecta. «clase enum» no tiene nada que ver con la capacidad de especificar el tipo. Eso es independiente de la característica que existe tanto para regular las enumeraciones y para la enumeración de las clases.
    • tal vez estoy equivocado y que debo corregir mi respuesta, ¿cómo puedo especificar el tipo subyacente de un tradicional enum? Por CIERTO, en la preguntas frecuentes de la página vinculada usted puede leer esto: «el tipo subyacente de un enum no puede ser especificado, causando confusión, problemas de compatibilidad, y hace avanzar la declaración imposible«.
    • Al igual que este: enum A : unsigned char {...}. El artículo describe pre-C++11, en que esto no era posible. Pero esto no tiene nada que ver con la enumeración de las clases.
    • Este es el trato: * Enum clases son una nueva característica de C++11. * Escrito las enumeraciones son una nueva característica de C++11. Estos son dos separados relacionado nuevas características de C++11. Usted puede utilizar ambos, o puede utilizar cualquiera de las dos, o ninguna.
    • editado, gracias 🙂
    • Creo que Alex Allain proporciona la más completa simple explicación que yo haya visto en este blog en [cprogramming.com/c++11/…. Tradicional de enum era bueno para el uso de los nombres en lugar de los valores enteros y evitar el uso del preprocesador #define, que era una Buena Cosa – añadió claridad. clase enum elimina el concepto de un valor numérico del enumerador, y presenta el alcance y tipado fuerte que aumenta (bueno, puede aumento 🙂 programa de corrección. Se mueve un paso más cerca de pensamiento orientado a objetos.
    • wow este es el mejor de ambos mundos; typesafe por defecto, pero no binario incompatible con C.
    • Sin embargo, creo que usted tiene que definir las operaciones a nivel de bit a ti mismo que añade un montón de código repetitivo.

  3. 41

    La ventaja fundamental de utilizar la clase enum normal, enumeraciones es que usted puede tener la misma enumeración de variables para 2 diferentes enumeraciones y todavía pueden resolver ellos(que ha sido mencionado como tipo de seguro por OP)

    Por ejemplo:

    enum class Color1 { red, green, blue };    //this will compile
    enum class Color2 { red, green, blue };
    
    enum Color1 { red, green, blue };    //this will not compile 
    enum Color2 { red, green, blue };

    Como para la base de las enumeraciones, el compilador no será capaz de distinguir si red se refiere a el tipo de Color1 o Color2 como en la siguiente declaración.

    enum Color1 { red, green, blue };   
    enum Color2 { red, green, blue };
    int x = red;    //Compile time error(which red are you refering to??)
    • Ohh no leí tu pregunta correctamente. Considerar es como un add-on para los que no saben.
    • es ok! Casi me olvidé de este
    • por supuesto, usted escribiría enum { COLOR1_RED, COLOR1_GREE, COLOR1_BLUE }, fácilmente obviando problemas de espacio de nombres. El espacio de nombres argumento es el único de los tres que se mencionan aquí que no comparto en absoluto.
    • Así Que la solución es innecesario solución. Enum: enum Color1 { COLOR1_RED, COLOR1_GREEN, COLOR1_BLUE } es comparable a la clase Enum: enum class Color1 { RED, GREEN, BLUE }. El acceso es similar: COLOR1_RED vs Color1::RED, pero la Enumeración versión requiere que usted escriba «COLOR1» en cada valor, lo que da más espacio para los errores tipográficos, que el espacio de nombres de comportamiento de una clase enum evita.
    • which gives more room for typos. Lo siento, pero ese es el peor de los tirones de pelo argumento que he escuchado en 2019. Tiempo para practicar un poco y conseguir una sensación para lo que importa. Les garantizo que los seres humanos no son tan rápidos en la resolución de los identificadores como compiladores. Así que mejor no te reto a hacerlo. Que es un argumento convincente.
    • Para aclarar: Es arrancarse el cabello, porque si tienes una errata en el prefijo, las posibilidades son que el 99,99% de que el compilador va a atrapar. Para el resto de 0.01%, es probable que el programador aviso ya que el programa se comporta mal.
    • Ahora considere lo siguiente: Si usted escribe RED, GREEN y así sucesivamente (usando la clase enum), no es la oportunidad mucho mayor que la automática resolución se resuelve en la enum Banana enum en lugar de la Color1 enum? Por favor, aprendan a ser críticos y a tratar de ser objetivo.
    • Por favor utilice la crítica constructiva. Cuando digo más espacio para los errores tipográficos, me refiero a cuando originalmente definir los valores de enum Color1, que un compilador no puede coger, ya que es probable que todavía sea un ‘válido’ nombre. Si escribo RED, GREEN y así sucesivamente utilizando una clase enum, que no puede resolver a enum Banana ya que requiere que usted especifique Color1::RED para acceder al valor (el espacio de nombres de argumento). Todavía hay un buen momento para utilizar enum, pero el espacio de nombres de comportamiento de un enum class a menudo puede ser muy beneficioso.

  4. 19

    Enumeraciones se utilizan para representar un conjunto de valores enteros.

    La class palabra clave después de la enum especifica que la enumeración es inflexible y su enumeradores se encuentran en el ámbito. De esta manera enum clases, que impide el mal uso de constantes.

    Por Ejemplo:

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

    Aquí no podemos mezclar Mascotas y Animales de valores.

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

    C++11 PREGUNTAS FRECUENTES menciona los siguientes puntos:

    convencional de las enumeraciones implícitamente convertir a int, causando errores cuando alguien no quiere una enumeración para actuar como un entero.

    enum color
    {
        Red,
        Green,
        Yellow
    };
    
    enum class NewColor
    {
        Red_1,
        Green_1,
        Yellow_1
    };
    
    int main()
    {
        //! Implicit conversion is possible
        int i = Red;
    
        //! Need enum class name followed by access specifier. Ex: NewColor::Red_1
        int j = Red_1; //error C2065: 'Red_1': undeclared identifier
    
        //! Implicit converison is not possible. Solution Ex: int k = (int)NewColor::Red_1;
        int k = NewColor::Red_1; //error C2440: 'initializing': cannot convert from 'NewColor' to 'int'
    
        return 0;
    }

    convencional de las enumeraciones de exportación de sus enumeradores para el ámbito que lo rodea, provocando el nombre de los enfrentamientos.

    //Header.h
    
    enum vehicle
    {
        Car,
        Bus,
        Bike,
        Autorickshow
    };
    
    enum FourWheeler
    {
        Car,        //error C2365: 'Car': redefinition; previous definition was 'enumerator'
        SmallBus
    };
    
    enum class Editor
    {
        vim,
        eclipes,
        VisualStudio
    };
    
    enum class CppEditor
    {
        eclipes,       //No error of redefinitions
        VisualStudio,  //No error of redefinitions
        QtCreator
    };

    El tipo subyacente de una enumeración no se puede especificar, causando confusión, problemas de compatibilidad, y hace avanzar la declaración imposible.

    //Header1.h
    #include <iostream>
    
    using namespace std;
    
    enum class Port : unsigned char; //Forward declare
    
    class MyClass
    {
    public:
        void PrintPort(enum class Port p);
    };
    
    void MyClass::PrintPort(enum class Port p)
    {
        cout << (int)p << endl;
    }

    .

    //Header.h
    enum class Port : unsigned char //Declare enum type explicitly
    {
        PORT_1 = 0x01,
        PORT_2 = 0x02,
        PORT_3 = 0x04
    };

    .

    //Source.cpp
    #include "Header1.h"
    #include "Header.h"
    
    using namespace std;
    int main()
    {
        MyClass m;
        m.PrintPort(Port::PORT_1);
    
        return 0;
    }
  6. 1

    Porque, como se ha dicho en otras respuestas, la clase enum no convertir implícitamente int/bool, también ayuda a evitar buggy código como:

    enum MyEnum {
      Value1,
      Value2,
    };
    ...
    if (var == Value1 || Value2) //Should be "var == Value2" no error/warning
    • Para completar mi comentario anterior, tenga en cuenta que gcc tiene ahora una advertencia llamado -Invierno-en-bool-contexto que coger exactamente este tipo de errores.
  7. 1
    1. no convertir implícitamente a int
    2. pueden elegir qué tipo subyacen
    3. ENUMERACIÓN de nombres para evitar la contaminación suceder
    4. En comparación con el normal de la clase, puede ser declarado adelante, pero no tienen métodos
    • No es lo suficientemente clara
  8. 0

    Una cosa que no ha sido mencionado explícitamente – el alcance característica le da una opción a tener el mismo nombre para una enumeración y método de la clase. Por ejemplo:

    class Test
    {
    public:
       //these call ProcessCommand() internally
       void TakeSnapshot();
       void RestoreSnapshot();
    private:
       enum class Command //wouldn't be possible without 'class'
       {
            TakeSnapshot,
            RestoreSnapshot
       };
       void ProcessCommand(Command cmd); //signal the other thread or whatever
    };

Dejar respuesta

Please enter your comment!
Please enter your name here