Warum wird die Enum-Klasse gegenüber der einfachen Enum bevorzugt?

Lesezeit: 12 Minuten

Warum wird die Enum Klasse gegenuber der einfachen Enum bevorzugt
Oleksiy

Ich habe gehört, dass einige Leute empfohlen haben, enum zu verwenden Klassen in C++ wegen ihrer Typ Sicherheit.

Aber was bedeutet das wirklich?

  • Wenn jemand behauptet, dass ein Programmierkonstrukt “böse” ist, versucht er, Sie davon abzuhalten, für sich selbst zu denken.

    – Peter Becker

    20. August 2013 um 13:44 Uhr

  • @NicolBolas: Dies ist eher eine rethorische Frage, um eine FAQ-Antwort zu geben (ob dies wirklich so ist Häufigkeit gefragt ist eine andere Geschichte).

    – David Rodríguez – Dribeas

    20. August 2013 um 13:51 Uhr

  • @David, es gibt eine Diskussion, ob dies eine FAQ sein sollte oder nicht, die hier beginnt. Eingabe erwünscht.

    – sbi

    21. August 2013 um 9:21 Uhr

  • @PeteBecker Manchmal versuchen sie es nur beschützen du von dir selbst.

    – pikant

    11. Mai 2018 um 16:15 Uhr


  • geeksforgeeks.org/… Dies ist auch ein guter Ort, um zu verstehen enum vs enum class.

    – mr_azad

    20. April 2020 um 15:53 ​​Uhr


Warum wird die Enum Klasse gegenuber der einfachen Enum bevorzugt
Oleksiy

C++ hat zwei Arten von enum:

  1. enum classes
  2. Einfach enumS

Hier sind ein paar Beispiele, wie man sie deklariert:

 enum class Color { red, green, blue }; // enum class
 enum Animal { dog, cat, bird, human }; // plain enum 

Was ist der Unterschied zwischen den beiden?

  • enum classes – Aufzählungsnamen sind lokal auf die Aufzählung und ihre Werte tun nicht implizit in andere Typen konvertieren (wie eine andere enum oder int)

  • Einfach enums – wobei Aufzählungsnamen im selben Bereich wie die Aufzählung liegen und ihre Werte implizit in Ganzzahlen und andere Typen konvertiert werden

Beispiel:

enum Color { red, green, blue };                    // plain enum 
enum Card { red_card, green_card, yellow_card };    // another plain enum 
enum class Animal { dog, deer, cat, bird, human };  // enum class
enum class Mammal { kangaroo, deer, human };        // another enum class

void fun() {

    // examples of bad use of plain enums:
    Color color = Color::red;
    Card card = Card::green_card;

    int num = color;    // no problem

    if (color == Card::red_card) // no problem (bad)
        cout << "bad" << endl;

    if (card == Color::green)   // no problem (bad)
        cout << "bad" << endl;

    // examples of good use of enum classes (safe)
    Animal a = Animal::deer;
    Mammal m = Mammal::deer;

    int num2 = a;   // error
    if (m == a)         // error (good)
        cout << "bad" << endl;

    if (a == Mammal::deer) // error (good)
        cout << "bad" << endl;

}

Fazit:

enum classes sollte bevorzugt werden, da sie weniger Überraschungen hervorrufen, die potenziell zu Fehlern führen könnten.

  • Gutes Beispiel … gibt es eine Möglichkeit, die Typsicherheit der Klassenversion mit der Namensraumförderung der Enum-Version zu kombinieren? Das heißt, wenn ich eine Klasse habe A mit Zustand, und ich erstelle eine enum class State { online, offline }; als Klassenkind Awürde ich gerne machen state == online überprüft innen A anstatt state == State::online… ist das möglich?

    – Kennzeichen

    20. August 2013 um 13:48 Uhr

  • Nö. Die Namespace-Werbung ist eine schlechte Sache™ und die halbe Rechtfertigung dafür enum class war es zu beseitigen.

    – Hündchen

    20. August 2013 um 13:59 Uhr

  • In C++11 können Sie auch explizit typisierte Aufzählungen verwenden, wie enum Animal: unsigned int {dog, deer, cat, bird}

    – Blasius Secundus

    20. August 2013 um 14:16 Uhr

  • @Cat Plus Plus Ich verstehe, dass @Oleksiy sagt, dass es schlecht ist. Meine Frage war nicht, ob Oleksiy es schlecht fand. Meine Frage war eine Detailanfrage was ist schlecht dabei. Speziell, warum hält zum Beispiel Oleksiy für schlecht Color color = Color::red.

    – chux – Wiedereinsetzung von Monica

    21. August 2013 um 18:56 Uhr

  • @Cat Plus Plus Also das Beispiel Schlecht erfolgt erst am if (color == Card::red_card) Zeile, 4 Zeilen später als der Kommentar (was ich jetzt sehe gilt für die erste Hälfte des Blocks.) 2 Zeilen des Blocks ergibt die Schlecht Beispiele. Die ersten 3 Zeilen sind kein Problem. Der “gesamte Block ist der Grund, warum einfache Aufzählungen schlecht sind” warf mich zurück, als ich dachte, Sie meinten, dass auch mit diesen etwas nicht stimmte. Ich sehe jetzt, es ist nur ein Setup. Danke auf jeden Fall für die Rückmeldung.

    – chux – Wiedereinsetzung von Monica

    21. August 2013 um 19:32 Uhr

Warum wird die Enum Klasse gegenuber der einfachen Enum bevorzugt
PaperBirdMaster

Von Häufig gestellte Fragen zu C++11 von Bjarne Stroustrup:

Die enum classes (“new enums”, “strong enums”) adressiert drei Probleme mit traditionellen C++-Enumerationen:

  • Herkömmliche Aufzählungen werden implizit in int konvertiert, was zu Fehlern führt, wenn jemand nicht möchte, dass eine Aufzählung als ganze Zahl fungiert.
  • Herkömmliche Enumerationen exportieren ihre Enumeratoren in den umgebenden Gültigkeitsbereich, was zu Namenskonflikten führt.
  • der zugrunde liegende Typ von an enum kann nicht angegeben werden, was zu Verwirrung und Kompatibilitätsproblemen führt und eine Vorwärtsdeklaration unmöglich macht.

Die neuen Aufzählungen sind “Aufzählungsklassen”, weil sie Aspekte traditioneller Aufzählungen (Namenswerte) mit Aspekten von Klassen (Mitglieder mit Geltungsbereich und fehlende Konvertierungen) kombinieren.

Wie von anderen Benutzern erwähnt, würden die “starken Enums” den Code sicherer machen.

Der zugrunde liegende Typ eines “Klassikers” enum muss ein ganzzahliger Typ sein, der groß genug ist, um alle Werte von aufzunehmen enum; das ist normalerweise ein int. Außerdem soll jeder aufgezählte Typ kompatibel sein char oder ein vorzeichenbehafteter/vorzeichenloser ganzzahliger Typ.

Dies ist eine breite Beschreibung dessen, was ein enum Der zugrunde liegende Typ muss sein, daher trifft jeder Compiler seine eigenen Entscheidungen über den zugrunde liegenden Typ des Klassikers enum und manchmal könnte das Ergebnis überraschend sein.

Zum Beispiel habe ich Code wie diesen ein paar Mal gesehen:

enum E_MY_FAVOURITE_FRUITS
{
    E_APPLE      = 0x01,
    E_WATERMELON = 0x02,
    E_COCONUT    = 0x04,
    E_STRAWBERRY = 0x08,
    E_CHERRY     = 0x10,
    E_PINEAPPLE  = 0x20,
    E_BANANA     = 0x40,
    E_MANGO      = 0x80,
    E_MY_FAVOURITE_FRUITS_FORCE8 = 0xFF // 'Force' 8bits, how can you tell?
};

Im obigen Code denkt ein naiver Programmierer, dass der Compiler die speichern wird E_MY_FAVOURITE_FRUITS Werte in einen vorzeichenlosen 8-Bit-Typ … aber es gibt keine Garantie dafür: Der Compiler kann wählen unsigned char oder int oder shortjeder dieser Typen ist groß genug, um alle Werte aufzunehmen, die in angezeigt werden enum. Feld hinzufügen E_MY_FAVOURITE_FRUITS_FORCE8 ist eine Last und zwingt den Compiler nicht, irgendeine Wahl über den zugrunde liegenden Typ von zu treffen enum.

Wenn es einen Code gibt, der sich auf die Schriftgröße stützt und/oder davon ausgeht E_MY_FAVOURITE_FRUITS von einiger Breite wäre (z. B. Serialisierungsroutinen), könnte sich dieser Code je nach Compiler-Gedanken auf seltsame Weise verhalten.

Und um die Sache noch schlimmer zu machen, wenn irgendein Arbeitskollege unseren unachtsam einen neuen Wert hinzufügt enum:

    E_DEVIL_FRUIT  = 0x100, // New fruit, with value greater than 8bits

Der Compiler beschwert sich nicht darüber! Es passt einfach die Größe des Typs an alle Werte von an enum (unter der Annahme, dass der Compiler den kleinstmöglichen Typ verwendet hat, was eine Annahme ist, die wir nicht tun können). Diese einfache und sorglose Ergänzung zum enum könnte verwandten Code auf subtile Weise brechen.

Seit C++11 ist es möglich, den zugrunde liegenden Typ für anzugeben enum und enum class (danke rdb) also ist dieses Problem ordentlich angegangen:

enum class E_MY_FAVOURITE_FRUITS : unsigned char
{
    E_APPLE        = 0x01,
    E_WATERMELON   = 0x02,
    E_COCONUT      = 0x04,
    E_STRAWBERRY   = 0x08,
    E_CHERRY       = 0x10,
    E_PINEAPPLE    = 0x20,
    E_BANANA       = 0x40,
    E_MANGO        = 0x80,
    E_DEVIL_FRUIT  = 0x100, // Warning!: constant value truncated
};

Wenn Sie den zugrunde liegenden Typ angeben, wenn ein Feld einen Ausdruck außerhalb des Bereichs dieses Typs hat, beschwert sich der Compiler, anstatt den zugrunde liegenden Typ zu ändern.

Ich denke, dass dies eine gute Verbesserung der Sicherheit ist.

Damit Warum wird die Enum-Klasse gegenüber der einfachen Enum bevorzugt?wenn wir den zugrunde liegenden Typ für scoped(enum class) und ohne Bereich (enum) enums was sonst noch macht enum class eine bessere Wahl?:

  • Sie konvertieren nicht implizit in int.
  • Sie verschmutzen den umgebenden Namensraum nicht.
  • Sie können vorwärts deklariert werden.

  • Ich nehme an, wir können den Enum-Basistyp auch für reguläre Enums einschränken, solange wir C++ 11 haben

    – Sagar Padhye

    28. Dezember 2015 um 11:35 Uhr


  • Entschuldigung, aber diese Antwort ist falsch. “enum class” hat nichts mit der Möglichkeit zu tun, den Typ anzugeben. Das ist eine unabhängige Funktion, die sowohl für reguläre Aufzählungen als auch für Aufzählungsklassen existiert.

    – rdb

    6. Mai 2016 um 11:01 Uhr

  • Das ist der Deal: * Enum-Klassen sind ein neues Feature in C++11. * Typisierte Aufzählungen sind ein neues Feature in C++11. Dies sind zwei separate, nicht zusammenhängende neue Features in C++11. Sie können beide verwenden, oder Sie können eines oder keines verwenden.

    – rdb

    6. Mai 2016 um 13:20 Uhr

  • Ich denke, dass Alex Allain am vollständigsten ist einfach Erklärung habe ich noch in diesem Blog unter gesehen [cprogramming.com/c++11/…. Traditional enum was good for using names instead of integer values and avoiding using preprocessor #defines, which was a Good Thing – it added clarity. enum class removes the concept of a numeric value of the enumerator, and introduces scope and strong typing which increases (well, can increase 🙂 program correctness. It moves you one step closer to thinking object oriented.

    – Jon Spencer

    Jan 6, 2017 at 21:10

  • As an aside, it’s always amusing when you’re reviewing code and suddenly One Piece happens.

    – Justin Time – Reinstate Monica

    Sep 25, 2019 at 17:32

Warum wird die Enum Klasse gegenuber der einfachen Enum bevorzugt
Saksham

The basic advantage of using enum class over normal enums is that you may have same enum variables for 2 different enums and still can resolve them(which has been mentioned as type safe by OP)

For eg:

enum class Color1 { red, green, blue };    //this will compile
enum class Color2 { red, green, blue };

enum Color1 { red, green, blue };    //this will not compile 
enum Color2 { red, green, blue };

As for the basic enums, compiler will not be able to distinguish whether red is refering to the type Color1 or Color2 as in hte below statement.

enum Color1 { red, green, blue };   
enum Color2 { red, green, blue };
int x = red;    //Compile time error(which red are you refering to??)

  • @Oleksiy Ohh I didn’t read your question properly. Consider is as an add-on for those who didn’t know.

    – Saksham

    Aug 20, 2013 at 13:12


  • it’s ok! I almost forgot about this

    – Oleksiy

    Aug 20, 2013 at 13:14

  • of course, you’d write enum { COLOR1_RED, COLOR1_GREE, COLOR1_BLUE }, easily obviating namespace issues. The namespace argument is the one of the three mentioned here that I don’t buy at all.

    – Jo So

    Oct 26, 2018 at 18:48

  • @Jo So That solution is an unnecessary workaround. Enum: enum Color1 { COLOR1_RED, COLOR1_GREEN, COLOR1_BLUE } is comparable to Enum class: enum class Color1 { RED, GREEN, BLUE }. Accessing is similar: COLOR1_RED vs Color1::RED, but the Enum version requires you type “COLOR1” in each value, which gives more room for typos, which the namespace behaviour of an enum class avoids.

    – cdgraham

    Mar 5, 2019 at 19:15


  • Please use constructive criticism. When I say more room for typos, I mean when you originally define the values of enum Color1, which a compiler can’t catch since it would likely still be a ‘valid’ name. If I write RED, GREEN and so on using an enum class, than it can’t resolve to enum Banana because it requires you specify Color1::RED in order to access the value (the namespace argument). There are still good times to use enum, but the namespace behavior of an enum class can often be very beneficial.

    – cdgraham

    Mar 7, 2019 at 13:50

1647108610 802 Warum wird die Enum Klasse gegenuber der einfachen Enum bevorzugt
themeeman

It’s worth noting, on top of these other answers, that C++20 solves one of the problems that enum class has: verbosity. Imagining a hypothetical enum class, Color.

void foo(Color c)
  switch (c) {
    case Color::Red: ...;
    case Color::Green: ...;
    case Color::Blue: ...;
    // etc
  }
}

This is verbose compared to the plain enum variation, where the names are in the global scope and therefore don’t need to be prefixed with Color::.

However, in C++20 we can use using enum to introduce all of the names in an enum to the current scope, solving the problem.

void foo(Color c)
  using enum Color;
  switch (c) {
    case Red: ...;
    case Green: ...;
    case Blue: ...;
    // etc
  }
}

So now, there is no reason not to use enum class.

  1. do not implicitly convert to int
  2. can choose which type underlie
  3. ENUM namespace to avoid polluting happen
  4. Compared with normal class, can be declared forward, but do not have methods

C++11 FAQ mentions below points:

conventional enums implicitly convert to int, causing errors when someone does not want an enumeration to act as an integer.

enum color
{
    Red,
    Green,
    Yellow
};

enum class NewColor
{
    Red_1,
    Green_1,
    Yellow_1
};

int main()
{
    //! Implicit conversion is possible
    int i = Red;

    //! Need enum class name followed by access specifier. Ex: NewColor::Red_1
    int j = Red_1; // error C2065: 'Red_1': undeclared identifier

    //! Implicit converison is not possible. Solution Ex: int k = (int)NewColor::Red_1;
    int k = NewColor::Red_1; // error C2440: 'initializing': cannot convert from 'NewColor' to 'int'

    return 0;
}

conventional enums export their enumerators to the surrounding scope, causing name clashes.

// Header.h

enum vehicle
{
    Car,
    Bus,
    Bike,
    Autorickshow
};

enum FourWheeler
{
    Car,        // error C2365: 'Car': redefinition; previous definition was 'enumerator'
    SmallBus
};

enum class Editor
{
    vim,
    eclipes,
    VisualStudio
};

enum class CppEditor
{
    eclipes,       // No error of redefinitions
    VisualStudio,  // No error of redefinitions
    QtCreator
};

The underlying type of an enum cannot be specified, causing confusion, compatibility problems, and makes forward declaration impossible.

// Header1.h
#include <iostream>

using namespace std;

enum class Port : unsigned char; // Forward declare

class MyClass
{
public:
    void PrintPort(enum class Port p);
};

void MyClass::PrintPort(enum class Port p)
{
    cout << (int)p << endl;
}

.

// Header.h
enum class Port : unsigned char // Declare enum type explicitly
{
    PORT_1 = 0x01,
    PORT_2 = 0x02,
    PORT_3 = 0x04
};

.

// Source.cpp
#include "Header1.h"
#include "Header.h"

using namespace std;
int main()
{
    MyClass m;
    m.PrintPort(Port::PORT_1);

    return 0;
}

1647108611 72 Warum wird die Enum Klasse gegenuber der einfachen Enum bevorzugt
Arnaud

Because, as said in other answers, class enum are not implicitly convertible to int/bool, it also helps to avoid buggy code like:

enum MyEnum {
  Value1,
  Value2,
};
...
if (var == Value1 || Value2) // Should be "var == Value2" no error/warning

  • To complete my previous comment, note that gcc now has a warning called -Wint-in-bool-context which will catch exactly this kind of errors.

    – Arnaud

    Jan 4, 2019 at 13:42

994750cookie-checkWarum wird die Enum-Klasse gegenüber der einfachen Enum bevorzugt?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy