2009-11-15 13 views
5

Cerco di mantenere le cose il più possibile locali, quindi metto enumerazioni nell'ambito della classe, anche se sono condivise tra due classi (l'ho messo nella classe che "va meglio" con esso.) Questo ha ha funzionato alla grande, ma di recente ho riscontrato un problema in cui si verifica una dipendenza circolare se inserisco l'enumerazione nell'ambito della classe.Problemi di enum scoping

L'enumerazione diventerà un argomento di costruzione per più classi e la classe in cui si trova (e la classe che ha più senso per essere inclusa) include tali classi. Pertanto, non è possibile utilizzare l'enumerazione come argomento del costruttore per le classi incluse poiché determinerà una dipendenza circolare.

Sarebbe meglio mettere semplicemente questa enumerazione nel proprio file di intestazione, e se sì, dovrei mettere tutte le enumerazioni nel file di intestazione per essere coerenti? Ci sono altre soluzioni a questo problema (che sono logiche)?

+0

hai provato in avanti dichiarazioni? –

+0

Le dichiarazioni di inoltro consentono solo di accedere al nome del tipo. Non puoi accedere all'interfaccia o creare un'istanza o fare qualcosa del genere. – Anonymous

risposta

3

se l'enum viene utilizzato da più classi di allora direi che non appartiene in realtà nella definizione di una singola classe, ma nello spazio dei nomi in cui risiedono tali classi.

ovvero a meno che l'enumerazione non venga passata attraverso una classe al costruttore di un'altra, nel qual caso può avere più senso istanziare separatamente la classe dipendente da enum e passarla come parametro al costruttore della classe contenitore.

+0

La seconda cosa che hai descritto è il caso, ma il metodo che hai descritto non funzionerà. Ho deciso di rendere l'enumerazione disponibile in un'intestazione di utilità che ha metodi comunemente usati, ecc. – Anonymous

-2

Si può cercare di trasmettere dichiarare l'enum come questo:

enum MyEnum; 
+2

Le enumerazioni non possono essere inoltrate dichiarate. – Anonymous

+1

E anche se fosse possibile, non è possibile inoltrare i tipi annidati. O meglio, non puoi inoltrare un tipo annidato senza la definizione del tipo di nidificazione. –

+0

Come nota storica, dal momento che C++ 11 È possibile inoltrare-dichiarare un 'enum classe' (o' enum struct'), ma questi sono distinte da vecchio stile 'enum's. – Quackmatic

1

Si dovrebbe inserire l'enum al di fuori di qualsiasi classe se è condivisa, ma si può ancora applicare l'enum. Posizionarlo nella spazio dei nomi in modo che i enumeratori non lo fanno "fuga", ingombrare spazio dei nomi del progetto:

namespace Project { // you already have this, right? :) 
    namespace COLOR { // naming styles differ, use what you like 
    enum Color { 
     red, 
     green, 
     blue 
    }; 
    } 
    using COLOR::Color; // now you can use the type 'normally' 

    // examples: 
    struct A { 
    Color c; 
    A() : c(COLOR::red) {} 
    }; 
    void f(Color c) { 
    using namespace COLOR; 
    // inside this function, we no longer have to prefix COLOR:: 
    if (c == green) { 
     go(); 
    } 
    else if (c == red) { 
     stop(); 
    } 
    } 
} 
+0

Dovrò provare ad usare la dichiarazione 'using' s = come fai tu per vedere se mi piace meglio del Il pasticcio di typedef che sto usando. Penso che mi piacerà (ma potrebbe usare una convenzione di denominazione diversa da tutte le maiuscole per il tipo enum). Grazie! –

+0

Ho usato CAPS perché sembrava che Color sarebbe stato usato più di COLOR :: red, altrimenti useresti spesso quest'ultimo e puoi usare una direttiva using all'ambito della funzione. 'typedef COLOR :: Color Color;' è equivalente a 'using COLOR :: Color;' qui. –

2

spesso messo i miei enumerazioni in uno spazio dei nomi per evitare che i vari valori enum dalla ingombrano lo spazio dei nomi globale. Penso che questo sia quello che stai cercando di metterli in classe. Ma se non 'fit' bene in una classe, uno spazio dei nomi funziona più o meno altrettanto bene per questo scopo:

namespace FooSettings 
{ 
    enum FooSettings 
    { 
     foo, 
     bar 
    }; 
} 
typedef enum FooSettings::FooSettings FooSettingsEnum; 


int main() 
{ 
    FooSettingsEnum x = FooSettings::foo; 
}; 

Ho un frammento di editore che costruisce il contorno per un nuovo conteggio dato solo il suo nome , compresa la linea

typedef enum FooSettings::FooSettings FooSettingsEnum; 

che crea un typedef quindi è un po 'più leggibile per dichiarare le variabili con il tipo di enumerazione.

ho il sospetto che Stroustrup avrebbe fatto i nomi di valore di enumerazione ambito al l'enumerazione se avesse avuto la possibilità, ma la compatibilità C forzato la mano (questo è solo speculazione - forse un giorno mi guarderò in D & E e vedere se menziona qualcosa).

+1

Personalmente preferisco una struct che uno spazio dei nomi perché una struct è quindi manipolabile dai template. –

+0

@Matthieu - L'uso di una struttura non mi è mai venuto in mente. Non posso dire di aver perso il fatto di non essere in grado di manipolare l'enumerazione con i modelli, ma di certo non vedo svantaggi nell'usare una struttura per avvolgere l'ambito enum. Ancora un'altra buona idea per me da usare. Grazie. –

+0

Ho provato ad incapsulare enum in un namespace e anche in una struct, e alcune cose funzionano meglio con una struct.Quindi faccio spesso quanto segue: struct MyEnum {enum Values ​​{a, b}; }; typedef MyEnum :: Valori MyEnum_t; Ora posso usare 'MyEnum_t' per riferirsi all'enumerazione come un tipo, e' MyEnum :: a', 'MyEnum :: b' per fare riferimento ai suoi membri come se l'enum fosse un tipo aggregato. Ho sperimentato un po 'prima di scegliere le convenzioni di denominazione particolari qui e ho trovato nel tempo quanto sopra per essere il meglio che posso. – Permaquid

7

io uso una variante di quello che Michael e Roger fanno:

namespace Color 
{ 
    enum Type 
    { 
     red, 
     green, 
     blue 
    }; 
}; 

void paintHouse(Color::Type color) {...} 

main() 
{ 
    paintHouse(Color::red); 
} 

trovo Color::Type di essere più bella e più auto-documentazione di Color::Color o COLOR::Color. Se trovi Color::Type troppo prolisso, puoi usare Color::T.

Non prefisso i miei valori enumerati (ad esempio COLOR_RED) perché lo spazio dei nomi attorno all'enum diventa effettivamente il prefisso.

Ho smesso di utilizzare la convenzione ALL_CAPS per le mie costanti con ambito perché si scontrano con le macro nelle librerie C (ad esempio NULL). Le macro non sono scope negli spazi dei nomi che sono definiti in

+0

Sto considerando di adottare il suggerimento di Matthieu M di utilizzare struct anziché namespace per poterlo passare come parametro template. Tuttavia, non riesco a pensare a una ragione per cui passare Color anziché Color :: Type come parametro del template. –

11

Dal C++ 11, è possibile utilizzare un enum class. (O enum struct - la stessa cosa, ha dichiarato in modo diverso), in cui i valori enum sono scope al nome del enum . Ad esempio, ecco una dichiarazione C++ 11 valida.

enum class token_type { 
    open_paren, 
    close_paren, 
    identifier 
}; 

per accedere ai valori della enum, tuttavia, è necessario portata correttamente utilizzando l'operatore ::. Quindi, questo è un compito valido in C++ 11:

token_type type = token_type::close_paren; 

Ma non è questo:

token_type type = close_paren; 

questo risolve il conflitto di denominazione, e significa che non c'è bisogno di usare namespace contenitore o strutturare solo per fermare la portata dei valori che perdono dove non dovrebbero. Ciò significa che il seguente enum può esistere nello stesso ambito token_type:

enum class other_enum { 
    block, 
    thingy, 
    identifier 
}; 

Ora i due valori chiamati identifier nelle due differenti struct non interferiranno.

1

Sono d'accordo con Emile. Un'altra opzione se si utilizza C++ 98 è quello di utilizzare struct invece di namespace, come segue

struct Color 
{ 
    enum Type 
    { 
    red, 
    green, 
    blue 
    }; 
}; 

lo preferisco in quanto idealmente vorrei utilizzare uno spazio dei nomi per rappresentare un modulo che contiene più classi, piuttosto che solo scoping un enum ...