C++ Enumeration Declarations

An enumeration is a user-defined type that consists of a set of named constants known as enumerators.

For more information about CLR enums, see enum class.

enum [tag] [: type] {enum-list} [declarator];   // for definition of enumerated type
enum tag declarator;   // for declaration of variable of type tag

Parameters

  • tag
    The type name given to the enumeration.

  • type
    The underlying type of the enumeration identifiers. See Remarks.

  • enum-list
    List of the enumerators in the enumeration.

  • declarator
    Declarator list that specifies the names of the enumeration. For more information, see Overview of Declarators.

Remarks

An enumeration provides context to describe a range of values. The following example shows an enumeration that contains the four suits in a deck of cards.

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

Every name of the enumeration becomes an enumerator and is assigned a value that corresponds to its place in the order of the values in the enumeration. By default, the first value is assigned 0, the next one is assigned 1, and so on. You can set the value of an enumerator.

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

The enumerator Diamonds is assigned the value 1. This affects the values that are assigned to subsequent enumerators; Hearts is assigned the value 2, Clubs is 3, and so on.

In C, the enum keyword is required to declare an enumeration. In C++, the enum keyword can be omitted. For example:

Suit current;          // Legal in C++ only

A variable based on an enumeration can be assigned specific values.

Suit currentSuit = Hearts;

If you try to assign hand a value that is not a day of the week,

int  myAccountNumber = 012345678;
Suit hand;

hand = myAccountNumber;

the compiler flags this assignment as an error at compile time. Although technically both variables are integer numbers, a cast is required to convert an int to an enumeration. However, you can go the other way and promote an enumerator to an integer value without a cast.

myAccountNumber = hearts;

type is the underlying type of the identifiers. This can be any scalar type, for example, signed or unsigned versions of int, short, or long. bool or char is also allowed.

Enumerated types are valuable when an object can assume a known and reasonably limited set of values. Here is an example of the suits from a deck of cards:

// enumeration_declarations.cpp
// compile with: /c
class Card {
public:
   enum Suit {
      Diamonds,
      Hearts,
      Clubs,
      Spades
   };

   // Declare two constructors: a default constructor,
   //  and a constructor that sets the cardinal and
   //  suit value of the new card.
   Card();
   Card( int CardInit, Suit SuitInit );

   // Get and Set functions.
   int   GetCardinal();          // Get cardinal value of card.
   int   SetCardinal();          // Set cardinal value of card.
   Suit  GetSuit();              // Get suit of card.
   void  SetSuit(Suit new_suit); // Set suit of card.
   char *NameOf();               // Get string representation of card.

private:
   Suit  suit;
   int   cardinalValue;
};

// Define a postfix increment operator for Suit.
inline Card::Suit operator++( Card::Suit &rs, int ) {
   Card::Suit oldSuit = rs;
   rs = (Card::Suit)(rs + 1);
   return oldSuit;
}

The preceding class, Card, contains a nested enumerated type, Suit.

Because the type Suit is nested, the class name (Card) must be used explicitly in public references. In methods, the class name can be omitted.

The postfix increment operator for Card::Suit is defined because without a user-defined increment operator, curSuit cannot be incremented. For more information about user-defined operators, see Operator Overloading.

The following code creates a pack of cards.

Card *Deck[52];
int   j = 0;

for( Card::Suit curSuit = Card::Diamonds ; curSuit <= Card::Spades ; curSuit++ )
   for( int i = 1; i <= 13; ++i )
      Deck[j++] = new Card( i, curSuit );

Consider the following example with regard to the NameOf method.

#define SIZE_OF_CARD_NAMES 20
char* Card::NameOf() {   // Get the name of a card.
   static char szName[SIZE_OF_CARD_NAMES];
   static char *Numbers[] = { 
      "1", "2", "3", "4", "5", "6", "7", "8", "9",
      "10", "Jack", "Queen", "King"
   };
   static char *Suits[] = {
      "Diamonds", "Hearts", "Clubs", "Spades" 
   };

   if( GetCardinal() < 13)
      strcpy_s( szName, SIZE_OF_CARD_NAMES, Numbers[GetCardinal()] );

   strcat_s( szName, SIZE_OF_CARD_NAMES, " of " );

   switch( GetSuit() ) {
      // Diamonds, Hearts, Clubs, and Spades do not need explicit
      //  class qualifier.
      case Diamonds:
         strcat_s( szName, SIZE_OF_CARD_NAMES , "Diamonds" );
      break;
      case Hearts:
         strcat_s( szName, SIZE_OF_CARD_NAMES , "Hearts" );
      break;
      case Clubs:
         strcat_s( szName, SIZE_OF_CARD_NAMES , "Clubs" );
      break;
      case Spades:
         strcat_s( szName, SIZE_OF_CARD_NAMES , "Spades" );
      break;
   }
   return szName;
}

An enumerated type is an integral type. The identifiers introduced in the enum declaration can be used wherever constants appear. Typically, the value of the first identifier is 0 (Diamonds, in the preceding example), and the values increase by one for each succeeding identifier. Therefore, the value of Spades is 3.

Enumerators need not have unique values in an enumeration. The name of every enumerator is treated as a constant and must be unique within the scope where the enum is defined.

Any enumerator in the list, including the first one, can be initialized to a value other than its default value. If the declaration of Suit had been

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

then the values of Diamonds, Hearts, Clubs, and Spades would have been 5, 6, 4, and 5, respectively. Notice that 5 is used more than once.

The default values for these enumerators simplify implementation of the NameOf method.

#define SIZE_OF_CARD_NAMES 20
char* Card::NameOf() {   // Get the name of a card. 
   static char szName[SIZE_OF_CARD_NAMES];
   static char *Numbers[] = {
      "1", "2", "3", "4", "5", "6", "7", "8", "9",
      "10", "Jack", "Queen", "King"
   };
   static char *Suits[] = {
      "Diamonds", "Hearts", "Clubs", "Spades"
   };

   if( GetCardinal() < 13)
      strcpy_s( szName, SIZE_OF_CARD_NAMES, Numbers[GetCardinal()] );

   strcat_s( szName, SIZE_OF_CARD_NAMES, " of " );
   strcat_s( szName, SIZE_OF_CARD_NAMES, Suits[GetSuit()] );
   return szName;
}

The accessor functionGetSuit returns type Suit, an enumerated type. Because enumerated types are integral types, they can be used as arguments to the array subscript operator. For more information, see Subscript Operator: [].

See Also

Reference

C Enumeration Declarations

C++ Keywords

Enumerator Names

Definition of Enumerator Constants

Conversions and Enumerated Types

Change History

Date

History

Reason

October 2009

Revised examples of enumerators and enumeration.

Customer feedback.

December 2009

Corrected postfix increment operator for Suit.

Customer feedback.