2012-09-25 1 views
49

Jestem początkującym programistą w C++.Enum vs Silnie typowane wyliczenie

Dziś natknąłem się na nowy temat: mocno napisany enum. Zbadałem go trochę, ale do tej pory nie jestem w stanie dowiedzieć się, dlaczego tego potrzebujemy i jaki jest pożytek z tego samego?

Na przykład jeśli mamy:

enum xyz{a, b, c}; 
/*a = 0, b = 1, c = 2, (Typical C format)*/ 

Dlaczego musimy napisać:

enum class xyz{a, b, c}; 

Co próbujemy zrobić tutaj? Moja najważniejsza wątpliwość to jak z niego korzystać. Czy możesz podać mały przykład, który pozwoli mi zrozumieć.

+0

Czy obejrzałeś [wikipedia] (http://en.wikipedia.org/wiki/C%2B%2B11#Strongly_typed_enumerations)? – Nobody

+1

@Nobody: Tak, patrzyłem na 'wiki', ale nie byłem w stanie zrozumieć, jak go używać i jakie są korzyści. –

Odpowiedz

72

OK, pierwszy przykład: teksty stałe w starym stylu nie mają własnego zakresu:

enum Animals {Bear, Cat, Chicken}; 
enum Birds {Eagle, Duck, Chicken}; // error! Chicken has already been declared! 

enum class Fruits { Apple, Pear, Orange }; 
enum class Colours { Blue, White, Orange }; // no problem! 

drugie, niejawnie przekonwertować do integralnych typach, co może prowadzić do dziwnych zachowań:

bool b = Bear && Duck; // what? 

Na koniec można określić podstawowy rodzaj całych fragmentów C++ 11:

enum class Foo : char { A, B, C}; 

Poprzednio typ bazowy nie został określony, co może powodować problemy ze zgodnością między platformami. Edycja Zostało wskazane w komentarzach, że można także określić podstawowy typ enumu "starego stylu" w C++ 11.

+0

Czy musimy zadeklarować/zdefiniować 'enum Class Colours' oraz' enum class Fruits'. Ponieważ kiedy napisałem kod w VS 2010. Zgłasza błąd "" oczekuje definicji lub nazwy znacznika "' under' class'. –

+0

Może masz rację. Sprawdzę to samo. –

+0

Ponadto: Dla "zwykłego" wyliczenia w C++ 11, tak jak w C++ 98 domyślny typ podstawowy nie jest zdefiniowany – bruziuz

7

Wartości enum class jest naprawdę typu enum class, a nie underlying_type jak w przypadku C-podlewek.

enum xyz { a, b, c}; 
enum class xyz_c { d, f, e }; 

void f(xyz x) 
{ 
} 

void f_c(xyz_c x) 
{ 
} 

// OK. 
f(0); 
// OK for C++03 and C++11. 
f(a); 
// OK with C++11. 
f(xyz::a); 
// ERROR. 
f_c(0); 
// OK. 
f_c(xyz_c::d); 
13

Istnieje dobry artykuł o wyliczeniach na this IBM page, jest bardzo szczegółowy i dobrze napisany. Oto kilka ważnych punktów w pigułce:

Wykreślone enumerale rozwiązują większość ograniczeń wynikających z wyliczeń regularnych: pełne bezpieczeństwo typu, dobrze zdefiniowany typ podstawowy, kwestie zakresu i deklaracja przekazania.

  • Otrzymujesz bezpieczeństwo typu, nie zezwalając na wszystkie niejawne konwersje na podstawie zakresu.
  • Otrzymujesz nowy zakres, a wyliczenie nie jest już w otaczającym zakresie, oszczędzając się przed konfliktami nazw.
  • Obszerne wyliczenia umożliwiają określenie podstawowego typu wyliczenia, a dla wyliczeń o zakresie domyślnym wartością domyślną jest int, jeśli nie zostanie ona określona.
  • Każde wyliczenie z ustalonym typem podstawowym może być zadeklarowane jako forward.
+1

Trzeci i czwarty punkt nie są specyficzne dla wyliczeń o zakresie; możesz określić bazowy typ dowolnego wyliczenia. –

3

Enum Zakres

Wyliczenia eksportować swoje rachmistrzów do otaczającego zakresie. Ma to dwie wady. Po pierwsze, może prowadzić do konfliktów nazw, jeśli dwa moduły wyliczające w różnych tabelach wyliczonych w tym samym zakresie mają tę samą nazwę; po drugie, nie można używać modułu wyliczającego z pełną nazwą, w tym nazwą wyliczenia.

enum ESet {a0, a, a1, b1, c3}; 
enum EAlpha{a, b, c} 

select = ESet::a; // error 
select = a;  // is ambigious 
2

Klasy enum („nowe teksty stałe”, „silne wyliczenia”) dotyczą trzech problemów z tradycyjnym C++ wyliczenia:

  1. konwencjonalny enums niejawnie przekonwertować do int, co powoduje błędy, gdy ktoś nie chce wyliczanie do działania jako liczba całkowita.
  2. konwencjonalne enums wyeksportuj ich moduły wyliczające do otaczającego zakresu, powodując konflikty nazw.
  3. Nie można określić podstawowego rodzaju obiektu enum, powodując zamieszanie, problemy ze zgodnością i uniemożliwiając przesłanie zgłoszenia do przodu.

enum class („mocne teksty stałe”) są silnie wpisane i scoped:

enum Alert { green, yellow, orange, red }; // traditional enum 

enum class Color { red, blue }; // scoped and strongly typed enum 
            // no export of enumerator names into enclosing scope 
            // no implicit conversion to int 
enum class TrafficLight { red, yellow, green }; 

Alert a = 7;    // error (as ever in C++) 
Color c = 7;    // error: no int->Color conversion 

int a2 = red;    // ok: Alert->int conversion 
int a3 = Alert::red;  // error in C++98; ok in C++11 
int a4 = blue;   // error: blue not in scope 
int a5 = Color::blue;  // error: not Color->int conversion 

Color a6 = Color::blue; // ok 

Jak widać, tradycyjne teksty stałe pracować jak zwykle, ale można teraz opcjonalnie zakwalifikować z nazwą użytkownika ENUM.

Nowe wyrazy są "klasą enum", ponieważ łączą aspekty tradycyjnych wyliczeń (wartości nazw) z aspektami zajęć (członkowie o ograniczonym zasięgu i brak konwersji).

Będąc w stanie określić typ podstawowy umożliwić prostszą interoperacyjność i gwarantowane wielkości wyliczeń:

enum class Color : char { red, blue }; // compact representation 

enum class TrafficLight { red, yellow, green }; // by default, the underlying type is int 

enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U }; // how big is an E? 
               // (whatever the old rules say; 
               // i.e. "implementation defined") 

enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U }; // now we can be specific 

Umożliwia również naprzód deklaracja teksty stałe:

enum class Color_code : char;  // (forward) declaration 
void foobar(Color_code* p);  // use of forward declaration 
// ... 
enum class Color_code : char { red, yellow, green, blue }; // definition 

typ bazowy musi być jednym z podpisane lub bez znaku liczby całkowite; wartość domyślna to int.

w bibliotece standardowej, enum zajęcia są wykorzystywane do:

  1. systemy odwzorowania poszczególnych kodów błędów: W <system_error>: enum class errc;
  2. wskaźniki bezpieczeństwa
  3. palików: W <memory>: enum class pointer_safety { relaxed, preferred, strict };
  4. błędy We/Wy stream: W <iosfwd>: enum class io_errc { stream = 1 };
  5. komunikacji asynchronicznej obsługi błędów: W <future>: enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Kilka z nich operatorów, takich jak == zdefiniowane.

+0

Plagiat z http://www.stroustrup.com/C++FAFAQ.html – deceze