2010-03-23 16 views
114

Nel seguente frammento di codice, l'enum Color viene dichiarato all'interno della classe Car al fine di limitare l'ambito dell'enumerazione e di non "inquinare" lo spazio dei nomi globale.Dichiarazione di enum all'interno di una classe

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) È questo un buon modo per limitare la portata del Color enum? O dovrei dichiararlo al di fuori della classe Car, ma possibilmente all'interno del proprio spazio dei nomi o della sua struct? Mi sono imbattuto in questo articolo oggi, che sostiene quest'ultimo e discute alcuni punti interessanti sulle enumerazioni: http://gamesfromwithin.com/stupid-c-tricks-2-better-enums.

(2) In questo esempio, quando si lavora all'interno classe, è migliore per codificare l'enumerazione come Car::Color, o sarebbe solo Color sufficiente? (Suppongo che il primo sia migliore, nel caso esista un altro enumerazione Color dichiarato nel namespace globale. In questo modo, almeno, siamo espliciti sull'enumerazione a cui ci stiamo riferendo)

risposta

69
  1. Se Color è qualcosa che è specifico per soli Car s, allora questo è il modo in cui si limitarne la portata. Se si ha un altro enumerazione Color utilizzato da altre classi, si potrebbe anche renderlo globale (o almeno all'esterno di Car).

  2. Non fa differenza. Se è presente uno globale, viene comunque utilizzato quello locale in quanto è più vicino all'ambito corrente. Si noti che se si definisce tale funzione al di fuori della definizione della classe, sarà necessario specificare esplicitamente Car::Color nell'interfaccia della funzione.

+10

2. Sì e no. 'Car :: Color getColor()' ma 'void Car :: setColor (Color c)' perché in 'setColor' abbiamo già lo specificatore. –

1

Se stai creando un codice libreria, quindi vorrei usare namespace. Tuttavia, è ancora possibile avere solo un enum di colori all'interno di tale spazio dei nomi. Se hai bisogno di una enumerazione che potrebbe utilizzare un nome comune, ma potrebbe avere costanti diverse per classi diverse, usa il tuo approccio.

6

In generale, inserisco sempre le mie enumerazioni in un struct. Ho visto diverse linee guida tra cui "prefisso".

enum Color 
{ 
    Clr_Red, 
    Clr_Yellow, 
    Clr_Blue, 
}; 

sempre pensato che questo sembrava più C linee guida di C++ quelli (per uno a causa della sigla e anche a causa dei namespace in C++).

Quindi, per limitare la portata che ora abbiamo due alternative:

  • namespace
  • struct/classi

Io personalmente tendo ad usare un struct perché può essere utilizzato come parametri per modello programmazione mentre uno spazio dei nomi non può essere manipolato.

Esempi di manipolazione comprendono:

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

che restituisce il numero di elementi della enum all'interno della struct T :)

58

preferisco seguente approccio (codice sotto). Risolve il problema di "namespace pollution", ma è anche molto più tipografico (non puoi assegnare e nemmeno confrontare due diverse enumerazioni, o la tua enumerazione con altri tipi built-in ecc.).

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; 
}; 

Usage:

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 per facilitare l'utilizzo:

#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), 

utilizzo:

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

Alcune referenze servizievoli:

  1. Herb Sutter, Jum Hyslop, C/C++ Users Journal, 22 (5), Maggio 2004
  2. Herb Sutter, David E. Miller, Bjarne Stroustrup fortemente tipizzato enumerazioni (revisione 3), Luglio 2007
+0

Mi piace. Inoltre costringe l'enum a essere istanziato con un valore valido. Penso che un operatore di assegnazione e un costruttore di copie sarebbero utili. Anche t_ dovrebbe essere privato. I macro di cui posso fare a meno. – jmucchiello

+0

Anche a me piace questo. Grazie per i riferimenti. – anio

+1

Hai detto: * "inoltre è molto più tipografico (non puoi assegnare e nemmeno confrontare due diverse enumerazioni ..." *. Perché pensi che sia una buona caratteristica? Penso che if (c2 == Colore: : Red) 'è ragionevole e deve essere compilato, ma nel tuo esempio non lo è. Lo stesso argomento per l'assegnazione anche! – Nawaz

66

Al giorno d'oggi - utilizzando C++ 11 - è possibile utilizzare enum class per questo:

enum class Color { RED, BLUE, WHITE }; 

AFAII che fa esattamente quello che vuoi.

Problemi correlati