Freigeben über


Enumerationen (C++)

Eine Aufzählung ist ein benutzerdefinierter Typ, der aus einer Gruppe benannter integraler Konstanten besteht, die als Enumeratoren bezeichnet werden.

Hinweis

In diesem Artikel werden der ISO-Standard-C++-Sprachtyp enum und der bereichsbezogene (oder stark typierte) enum class Typ behandelt, der in C++11 eingeführt wird. Informationen zu den public enum class Typen in C++/CLI und C++/CX finden Sie unter enum class (C++/CLI und C++/CX)private enum class.

Syntax

enum-name:
identifier

enum-specifier:
enum-head { enumerator-list optieren}
enum-head { enumerator-list , }

enum-head:
enum-key attribute-specifier-seq optierenenum-head-nameoptierenenum-baseoptieren

enum-head-name:
nested-name-specifier wählenidentifier

opaque-enum-declaration:
enum-key attribute-specifier-seq optierenenum-head-nameenum-baseoptieren;

enum-key:
enum
enum class
enum struct

enum-base:
: type-specifier-seq

enumerator-list:
enumerator-definition
enumerator-list , enumerator-definition

enumerator-definition:
enumerator
enumerator = constant-expression

enumerator:
identifier attribute-specifier-seq optieren

Verwendung

// unscoped enum:
// enum [identifier] [: type] {enum-list};

// scoped enum:
// enum [class|struct] [identifier] [: type] {enum-list};

// Forward declaration of enumerations  (C++11):
enum A : int;          // non-scoped enum must have type specified
enum class B;          // scoped enum defaults to int but ...
enum class C : short;  // ... may have any integral underlying type

Die Parameter

identifier
Der Typname, der der Enumeration zugewiesen wird.

type
Der zugrunde liegende Typ der Enumerationen; alle Enumeratoren weisen den gleichen zugrunde liegenden Typ auf. Kann ein beliebiger integraler Typ sein.

enum-list
Durch Trennzeichen getrennte Liste der Enumeratoren in der Enumeration. Jeder Enumerations- oder Variablenname im Bereich muss eindeutig sein. Die Werte können jedoch dupliziert werden. In einer nicht bereichsbezogenen Enumeration ist der Bereich der umgebende Bereich; in einer bereichsbezogenen Enumeration ist der Bereich der enum-list selbst. In einer bereichsbezogenen Enumeration kann die Liste leer sein, die tatsächlich einen neuen integralen Typ definiert.

class
Wenn Sie dieses Schlüsselwort in der Deklaration verwenden, geben Sie den Bereich der Enumeration an und identifier müssen angegeben werden. Sie können auch das struct Schlüsselwort anstelle von class, da sie semantisch gleichwertig in diesem Kontext sind.

Enumerationsbereich

Eine Enumeration stellt einen Kontext bereit, um einen Wertebereich zu beschreiben, der als benannte Konstanten dargestellt wird. Diese benannten Konstanten werden auch als Enumeratoren bezeichnet. In den ursprünglichen C- und C++ enum -Typen sind die nicht qualifizierten Enumerationen im gesamten Bereich sichtbar, in dem die enum Deklaration erfolgt. In bereichsbezogenen Enumerationen muss der Enumeratorname durch den enum Typnamen qualifiziert werden. Im folgenden Beispiel wird dieser grundlegende Unterschied zwischen den beiden Enumerationsarten veranschaulicht:

namespace CardGame_Scoped
{
    enum class Suit { Diamonds, Hearts, Clubs, Spades };

    void PlayCard(Suit suit)
    {
        if (suit == Suit::Clubs) // Enumerator must be qualified by enum type
        { /*...*/}
    }
}

namespace CardGame_NonScoped
{
    enum Suit { Diamonds, Hearts, Clubs, Spades };

    void PlayCard(Suit suit)
    {
        if (suit == Clubs) // Enumerator is visible without qualification
        { /*...*/
        }
    }
}

Jedem Namen in einer Enumeration wird ein integraler Wert zugewiesen, der seiner Position in der Reihenfolge der Werte in der Enumeration entspricht. Standardmäßig wird der erste Wert 0 zugewiesen, der nächste wert ist 1 usw. zugewiesen, Sie können jedoch explizit den Wert eines Enumerators festlegen, wie hier gezeigt:

enum Suit { Diamonds = 1, Hearts, Clubs, Spades };

Der Enumerator Diamonds wird dem Wert 1zugewiesen. Nachfolgende Aufzählungszeichen erhalten, wenn sie keinen expliziten Wert erhalten, den Wert des vorherigen Enumerators plus eins. Im vorherigen Beispiel Hearts wäre der Wert 2, Clubs hätte 3 usw.

Jeder Enumerator wird als Konstante behandelt und muss einen eindeutigen Namen innerhalb des Bereichs aufweisen, in dem die enum Enums definiert sind (für nicht bereichsbezogene Enumerationen) oder innerhalb der enum selbst (für bereichsbezogene Enumerationen). Die Werte, die den Namen zugewiesen werden, müssen nicht eindeutig sein. Betrachten Sie z. B. diese Deklaration einer nicht bereichsierten Enumeration Suit:

enum Suit { Diamonds = 5, Hearts, Clubs = 4, Spades };

Die Werte von Diamonds, Hearts, Clubs, und Spades sind 5, 6, 4 und 5, bzw. 5. Beachten Sie, dass 5 mehrmals verwendet wird; es ist zulässig, obwohl es möglicherweise nicht beabsichtigt ist. Diese Regeln sind für bereichsbezogene Enumerationen identisch.

Umwandlungsregeln

Unscoped enum constants can be implicitly converted to int, but an int is never implicitly convert to an enum value. Das folgende Beispiel zeigt, was passiert, wenn Sie versuchen, einen Wert zuzuweisen hand , der kein Suit:

int account_num = 135692;
Suit hand;
hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'

Eine Umwandlung ist erforderlich, um einen int bereichsbezogenen oder nicht bereichsbezogenen Enumerator zu konvertieren. Sie können jedoch einen nicht bereichsierten Enumerator in einen ganzzahligen Wert ohne Umwandlung höher stufen.

int account_num = Hearts; //OK if Hearts is in an unscoped enum

Die Verwendung impliziter Konvertierungen auf diese Weise kann zu unbeabsichtigten Nebenwirkungen führen. Zur Beseitigung von Programmierfehlern, die nicht erfassten Enumerationen zugeordnet sind, werden bereichsbezogene Enumerationswerte stark typiert. Bereichsenumeratoren müssen durch den Enumerationstypnamen (Bezeichner) qualifiziert werden und können nicht implizit konvertiert werden, wie im folgenden Beispiel gezeigt:

namespace ScopedEnumConversions
{
    enum class Suit { Diamonds, Hearts, Clubs, Spades };

    void AttemptConversions()
    {
        Suit hand;
        hand = Clubs; // error C2065: 'Clubs' : undeclared identifier
        hand = Suit::Clubs; //Correct.
        int account_num = 135692;
        hand = account_num; // error C2440: '=' : cannot convert from 'int' to 'Suit'
        hand = static_cast<Suit>(account_num); // OK, but probably a bug!!!

        account_num = Suit::Hearts; // error C2440: '=' : cannot convert from 'Suit' to 'int'
        account_num = static_cast<int>(Suit::Hearts); // OK
    }
}

Beachten Sie, dass die Zeile hand = account_num; weiterhin den Fehler verursacht, der mit nicht erfassten Enumerationen auftritt, wie weiter oben gezeigt. Es ist mit einer expliziten Umwandlung zulässig. Bei bereichsbezogenen Enumerationen ist die versuchte Konvertierung in der nächsten Anweisung jedoch nicht mehr zulässig, account_num = Suit::Hearts;ohne eine explizite Umwandlung.

Enumerationen ohne Enumerationen

Visual Studio 2017, Version 15.3 und höher (verfügbar mit /std:c++17 und höher): Durch Definieren einer Enumeration (normal oder bereichsmäßig) mit einem explizit zugrunde liegenden Typ und ohne Enumerationen können Sie einen neuen integralen Typ einführen, der keine implizite Konvertierung in einen anderen Typ aufweist. Wenn Sie diesen Typ anstelle des integrierten zugrunde liegenden Typs verwenden, können Sie das Potenzial für subtile Fehler beseitigen, die durch versehentliche implizite Konvertierungen verursacht werden.

enum class byte : unsigned char { };

Der neue Typ ist eine exakte Kopie des zugrunde liegenden Typs und hat daher dieselbe Aufrufkonvention, was bedeutet, dass er ohne Leistungseinbußen für ABIs verwendet werden kann. Es ist keine Umwandlung erforderlich, wenn Variablen des Typs mithilfe der Direct-List-Initialisierung initialisiert werden. Das folgende Beispiel zeigt, wie Sie Enumerationen ohne Enumerationen in verschiedenen Kontexten initialisieren:

enum class byte : unsigned char { };

enum class E : int { };
E e1{ 0 };
E e2 = E{ 0 };

struct X
{
    E e{ 0 };
    X() : e{ 0 } { }
};

E* p = new E{ 0 };

void f(E e) {};

int main()
{
    f(E{ 0 });
    byte i{ 42 };
    byte j = byte{ 42 };

    // unsigned char c = j; // C2440: 'initializing': cannot convert from 'byte' to 'unsigned char'
    return 0;
}

Siehe auch

C-Enumerationsdeklarationen
Schlüsselwörter