2010-03-23 18 views
114

En el siguiente fragmento de código, la enumeración Color se declara dentro de la clase Car para limitar el alcance de la enumeración e intentar no "contaminar" el espacio de nombres global.Declarar una enumeración dentro de una clase

class Car 
{ 
public: 

    enum Color 
    { 
     RED, 
     BLUE, 
     WHITE 
    }; 

    void SetColor(Car::Color color) 
    { 
     _color = color; 
    } 

    Car::Color GetColor() const 
    { 
     return _color; 
    } 

private: 

    Car::Color _color; 

}; 

(1) ¿Es esta una buena manera de limitar el alcance de la Color enumeración? O, ¿debería declararlo fuera de la clase Car, pero posiblemente dentro de su propio espacio de nombres o estructura? Acabo de encontrar este artículo hoy, que defiende lo último y analiza algunos puntos agradables sobre enums: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums.

(2) En este ejemplo, cuando se trabaja dentro de la clase, es lo mejor para codificar la enumeración como Car::Color, o acaba de Color suficiente? (Supongo que el primero es mejor, en caso de que haya otra enumeración Color declarada en el espacio de nombres global. De esa forma, al menos, somos explícitos sobre la enumeración a la que nos referimos)

Respuesta

69
  1. Si Color es algo que es específico para sólo Car s entonces esa es la forma que lo haría limitar su alcance. Si va a tener otra enumeración Color que utilizan otras clases, entonces también puede hacerlo global (o al menos fuera de Car).

  2. No hace la diferencia. Si hay uno global, el local se sigue utilizando de todos modos, ya que está más cerca del alcance actual. Tenga en cuenta que si define esas funciones fuera de la definición de la clase, deberá especificar explícitamente Car::Color en la interfaz de la función.

+10

2. Sí y no. 'Car :: Color getColor()' pero 'void Car :: setColor (Color c)' porque en 'setColor' ya tenemos el especificador. –

1

Si está creando un código biblioteca, entonces usaría el espacio de nombres. Sin embargo, solo puede tener una Enumeración de color dentro de ese espacio de nombres. Si necesita una enumeración que podría usar un nombre común, pero podría tener constantes diferentes para diferentes clases, use su enfoque.

6

En general, siempre pongo mis enums en un struct. He visto varias pautas que incluyen "prefixing".

enum Color 
{ 
    Clr_Red, 
    Clr_Yellow, 
    Clr_Blue, 
}; 

Siempre pensaron que esto parecía más C directrices de los C++ (por uno a causa de la abreviatura y también debido a los espacios de nombres en C++).

lo tanto limitar el alcance ahora tenemos dos alternativas:

  • espacios de nombres
  • structs/clases

personalmente tiendo a usar un struct, ya que se puede utilizar como parámetros para la plantilla programación mientras que un espacio de nombres no puede ser manipulado.

Ejemplos de manipulación incluyen:

template <class T> 
size_t number() { /**/ } 

que devuelve el número de elementos de enum dentro de la struct T :)

58

yo prefiero enfoque siguiente (código de abajo). Resuelve el problema de "contaminación del espacio de nombres", pero también es mucho más seguro (no se puede asignar e incluso comparar dos enumeraciones diferentes, o su enumeración con cualquier otro tipo incorporado, etc.).

struct Color 
{ 
    enum Type 
    { 
     Red, Green, Black 
    }; 
    Type t_; 
    Color(Type t) : t_(t) {} 
    operator Type() const {return t_;} 
private: 
    //prevent automatic conversion for any other built-in types such as bool, int, etc 
    template<typename T> 
    operator T() const; 
}; 

Uso:

Color c = Color::Red; 
switch(c) 
{ 
    case Color::Red: 
    //некоторый код 
    break; 
} 
Color2 c2 = Color2::Green; 
c2 = c; //error 
c2 = 3; //error 
if (c2 == Color::Red) {} //error 
If (c2) {} error 

creo macro para facilitar el uso:

#define DEFINE_SIMPLE_ENUM(EnumName, seq) \ 
struct EnumName {\ 
    enum type \ 
    { \ 
     BOOST_PP_SEQ_FOR_EACH_I(DEFINE_SIMPLE_ENUM_VAL, EnumName, seq)\ 
    }; \ 
    type v; \ 
    EnumName(type v) : v(v) {} \ 
    operator type() const {return v;} \ 
private: \ 
    template<typename T> \ 
    operator T() const;};\ 

#define DEFINE_SIMPLE_ENUM_VAL(r, data, i, record) \ 
    BOOST_PP_TUPLE_ELEM(2, 0, record) = BOOST_PP_TUPLE_ELEM(2, 1, record), 

de uso:

DEFINE_SIMPLE_ENUM(Color, 
      ((Red, 1)) 
      ((Green, 3)) 
      ) 

Algunas referencias servicial:

  1. Herb Sutter, Jum Hyslop, C/C++ Diario de Usuarios, 22 (5), mayo de 2004
  2. Herb Sutter, David E. Miller, Bjarne Stroustrup fuertemente tipado enumeraciones (revisión 3), Julio 2007
Hoy en día
+0

Me gusta esto. También fuerza a la enumeración a ser instanciada con un valor válido. Creo que un operador de asignación y un constructor de copia serían útiles. También t_ debe ser privado. Las macros que puedo prescindir. – jmucchiello

+0

A mí también me gusta esto. Gracias por las referencias. – anio

+1

Has dicho: * "también es mucho más seguro (no puedes asignar e incluso comparar dos enumeraciones diferentes ..." *. ¿Por qué crees que es una buena característica? Creo que 'si (c2 == Color: : Rojo) 'es razonable y debe compilarse, pero en su ejemplo no. ¡El mismo argumento para la asignación también! – Nawaz

66

- usando C++ 11 - se puede utilizar enum class para esto:

enum class Color { RED, BLUE, WHITE }; 

AFAII esto hace exactamente lo que quiere.

Cuestiones relacionadas