Deklaracje modułów wyliczających języka C++

Wyliczenie, które jest zdefiniowanym przez użytkownika typem, składającym się z zestawy integralnych stałych, zwanych wyliczeniami.

[!UWAGA]

Ten artykuł omawia typ enum języka C++ zgodnego ze standardem ISO oraz objęty zakresem (lub jednoznacznie zdefiniowany) typ enum class wprowadzony w języku C++11.Aby uzyskać informacje o typach public enum class lub private enum class w C++/CLI i C++/CX, zobacz Wylicz klasy.

// unscoped enum:
enum [identifier] [: type]

{enum-list}; 

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

Parametry

  • identifier
    Nazwa typu nadana enumeracji.

  • type
    Typ podstawowy modułów wyliczających; wszystkie moduły wyliczające mają ten sam typ podstawowy.Może być dowolnego typu całkowitoliczbowego.

  • enum-list
    Rozdzielana przecinkami lista modułów wyliczających w wyliczeniu.Każdy moduł wyliczający lub nazwa zmiennej w zakresie musi być unikatowa.Jednakże wartości mogą być zduplikowane.W typie wyliczeniowym nieobjętym zakresem rolę zakresu pełni otaczający zakres; w typie wyliczeniowym objętym zakresem rolę zakresu pełni sam obiekt enum-list.

  • class
    Przy użyciu słowa kluczowego w deklaracji, określamy zakresu jest typu wyliczeniowego, a identifier musi zostać podane.Można również użyć struct słowa kluczowego zamiast właściwości class, ponieważ są one semantycznie równoważne w tym kontekście.

Uwagi

Wyliczenie tworzy kontekst do opisania zakresu wartości, które są reprezentowane jako nazwane stałe, i są również nazywane modułami wyliczającymi.W oryginalnych typach wyliczeniowych C i C++, niekwalifikowane moduły wyliczające są widoczne w całym zakresie, w którym deklarowane jest wyliczenie.W typach wyliczeniowych nazwa modułu wyliczającego musi być kwalifikowana przez nazwę typu wyliczenia.Poniższy przykład pokazuje tę podstawową różnicę między dwoma rodzajami wyliczeń:

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
        { /*...*/
        }
    }
}

Każdej nazwie w wyliczeniu jest przypisywana wartość całkowita, która odpowiada jej miejscu w kolejności wartości w wyliczeniu.Domyślnie pierwszej wartości jest przypisane 0, następnej 1 i tak dalej, ale wartość modułu wyliczającego można ustawić jawnie, jak pokazano poniżej:

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

Modułowi wyliczającemu Diamonds jest przypisywana wartość 1.Kolejne enumeratory, jeśli nie posiadają wartości jawnej, otrzymują wartość poprzedniego enumeratora plus jeden.W poprzednim przykładzie obiekt Hearts miałby wartość 2, Clubs mógłby być 3 i tak dalej.

Każdy moduł wyliczający jest traktowany jako stała i musi mieć unikatową nazwę w zakresie, gdzie zdefiniowane jest enum (dla wyliczeń poza zakresem), lub w zakresie samego wyliczenia (dla wyliczeń objętych zakresem).Wartości nadane nazwom nie muszą być unikatowe.Na przykład, jeśli deklaracja wyliczenia poza zakresem Suit jest taka:

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

Następnie wartości Diamonds, Hearts, Clubs oraz Spades wyniosą odpowiednio 5, 6, 4 i 5.Należy zauważyć, że wartość 5 jest używana więcej niż jeden raz; jest to dozwolone, mimo że mogło nie być zamierzane.Te zasady są takie same dla wyliczeń w zakresie.

Reguły rzutowania

Stałe wyliczeń nieobjętych zakresem można niejawnie przekonwertować na int, ale int nigdy nie jest niejawnie konwertowany na wartość wyliczenia.W poniższym przykładzie pokazano, co się stanie, jeśli użytkownik próbuje przypisać hand wartości, która nie jest Suit:

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

Rzutowanie jest wymagane do konwertowania obiektu int na moduł wyliczający z zakresem lub bez zakresu.Możesz jednak podwyższyć poziom modułu wyliczającego nieobjętego zakresem do wartości będącej liczbą całkowitą bez rzutowania.

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

Korzystanie z niejawnych konwersji w ten sposób może doprowadzać do niezamierzonych skutków ubocznych.Aby wyeliminować błędy programowania związane z wyliczeniami nieobjętymi zakresem, wartości wyliczeń w zakresie mają jednoznacznie określone typy.Numeratorów zakresu musi być kwalifikowana przez nazwę typu wyliczeniowego (identyfikator) i nie można niejawnie przekonwertować, jak pokazano w następującym przykładzie:

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
}

Należy zauważyć, że wiersz hand = account_num; nadal powoduje błąd występujący dla typów wyliczeniowych nieobjętych zakresem, jak pokazano wcześniej.Jest to dozwolone z jawnym rzutowaniem.Jednakże przy typach wyliczeniowych w zakresie próba konwersji w następnej instrukcji account_num = Suit::Hearts; nie jest już dozwolona bez jawnego rzutowania.

Zobacz też

Informacje

Deklaracje modułów wyliczających języka C

Słowa kluczowe języka C++