web-dev-qa-db-de.com

Enum vs Stark typisierte Enumeration

Ich bin ein Anfänger in der C++ Programmierung.

Heute bin ich auf ein neues Thema gestoßen: stark typisiert enum. Ich habe ein bisschen recherchiert, aber bis jetzt kann ich nicht herausfinden, warum wir das brauchen und wofür das gleiche verwendet wird.

Zum Beispiel wenn wir haben:

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

Warum müssen wir schreiben:

enum class xyz{a, b, c};

Was versuchen wir hier zu tun? Mein wichtigster Zweifel ist, wie man es benutzt. Könnten Sie mir ein kleines Beispiel geben, das mich verständlich machen wird?.

78

OK, erstes Beispiel: Aufzählungen im alten Stil haben keinen eigenen Gültigkeitsbereich:

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!

Zweitens werden sie implizit in ganzzahlige Typen konvertiert, was zu merkwürdigem Verhalten führen kann:

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

Schließlich können Sie den zugrunde liegenden Integraltyp von C++ 11-Enums angeben:

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

Bisher wurde der zugrunde liegende Typ nicht angegeben, was zu Kompatibilitätsproblemen zwischen Plattformen führen kann. Bearbeiten In Kommentaren wurde darauf hingewiesen, dass Sie in C++ 11 auch den zugrunde liegenden Integraltyp einer Aufzählung "alten Stils" angeben können.

108
juanchopanza

Es gibt einen guten Artikel über Aufzählungen unter diese IBM-Seite , er ist sehr detailliert und gut geschrieben. Hier sind einige wichtige Punkte auf den Punkt gebracht:

Die Aufzählungen lösen die meisten Einschränkungen, die bei regulären Aufzählungen auftreten: vollständige Typensicherheit, genau definierter zugrunde liegender Typ, Geltungsbereichsprobleme und Vorwärtsdeklaration.

  • Sie erhalten Typensicherheit, indem Sie alle impliziten Konvertierungen von bereichsspezifischen Enums in andere Typen deaktivieren.
  • Sie erhalten einen neuen Bereich, und die Aufzählung befindet sich nicht mehr im umschließenden Bereich. Dadurch werden Namenskonflikte vermieden.
  • Mit Bereichsaufzählungen können Sie den zugrunde liegenden Typ der Aufzählung angeben, und für Bereichsaufzählungen ist der Standardwert int, wenn Sie ihn nicht angeben.
  • Jede Aufzählung mit einem festen zugrunde liegenden Typ kann vorwärts deklariert werden.
15
SingerOfTheFall

Werte von enum class ist wirklich vom Typ enum class, nicht underlying_type wie bei C-enums.

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);
9
ForEveR

Die Aufzählungsklassen ("neue Aufzählungen", "starke Aufzählungen") behandeln drei Probleme mit herkömmlichen C++ - Aufzählungen:

  1. konventionell enums implizit in int konvertieren, was zu Fehlern führt, wenn eine Aufzählung nicht als Ganzzahl fungieren soll.
  2. konventionelle enums exportieren ihre Enumeratoren in den umgebenden Bereich, was zu Namenskonflikten führt.
  3. Der zugrunde liegende Typ eines enum kann nicht angegeben werden, was zu Verwirrung und Kompatibilitätsproblemen führt und eine Vorwärtsdeklaration unmöglich macht.

enum class ("starke Aufzählungen") sind stark typisiert und umfassen:

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

Wie gezeigt, funktionieren herkömmliche Aufzählungen wie gewohnt, aber Sie können sich jetzt optional mit dem Namen der Aufzählung qualifizieren.

Die neuen Aufzählungen sind "Aufzählungsklassen", da sie Aspekte traditioneller Aufzählungen (Namenswerte) mit Aspekten von Klassen (Bereichsmitglieder und fehlende Konvertierungen) kombinieren.

Die Angabe des zugrunde liegenden Typs ermöglicht eine einfachere Interoperabilität und eine garantierte Anzahl von Aufzählungen:

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

Es ermöglicht auch die Vorabdeklaration von Aufzählungen:

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

Der zugrunde liegende Typ muss einer der ganzzahligen Typen mit oder ohne Vorzeichen sein. Der Standardwert ist int.

In der Standardbibliothek werden enum Klassen verwendet für:

  1. Systemspezifische Fehlercodes zuordnen: In <system_error>: enum class errc;
  2. Zeigersicherheitsindikatoren: In <memory>: enum class pointer_safety { relaxed, preferred, strict };
  3. E/A-Stream-Fehler: In <iosfwd>: enum class io_errc { stream = 1 };
  4. Fehlerbehandlung bei der asynchronen Kommunikation: In <future>: enum class future_errc { broken_promise, future_already_retrieved, promise_already_satisfied };

Einige von ihnen haben Operatoren wie == definiert.

4
Jnana

Enum Scope

Aufzählungen exportieren ihre Enumeratoren in den umgebenden Bereich. Dies hat zwei Nachteile. Erstens kann es zu Namenskonflikten kommen, wenn zwei im selben Bereich deklarierte Enumeratoren in unterschiedlichen Enumerationen denselben Namen haben. Zweitens ist es nicht möglich, einen Enumerator mit einem vollständig qualifizierten Namen einschließlich des Aufzählungsnamens zu verwenden.

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

select = ESet::a; // error
select = a;       // is ambigious
3
Ram