An enumeration is a distinct integral type that defines named constants. Enumerations are declared using the enum keyword.
Syntax
enum-name :
identifier
enum-specifier :
enum identifieropt { enum-listopt }
enum-list :
enumerator
enum-list , enumerator
enumerator :
identifier
identifier = constant-expression
Enumerated types are valuable when an object can assume a known and reasonably limited set of values. Consider the example of the suits from a deck of cards:
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 )
{
return rs = (Card::Suit)(rs + 1);
}
The preceding example defines a class, Card
, that contains a nested enumerated type, Suit
. To create a pack of cards in a program, use code such as:
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 );
In the preceding example, the type Suit
is nested; therefore, the class name (Card
) must be used explicitly in public references. In member functions, however, the class name can be omitted.
In the first segment of code, the postfix increment operator for Card::Suit
is defined. Without a user-defined increment operator, curSuit
could not be incremented. For more information about user-defined operators, see Overloaded Operators in Chapter 12.
Consider the code for the NameOf
member function (a better implementation is presented later):
char* Card::NameOf() // Get the name of a card.
{
static char szName[20];
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( szName, Numbers[GetCardinal()] );
strcat( szName, " of " );
switch( GetSuit() )
{
// Diamonds, Hearts, Clubs, and Spades do not need explicit
// class qualifier.
case Diamonds: strcat( szName, "Diamonds" ); break;
case Hearts: strcat( szName, "Hearts" ); break;
case Clubs: strcat( szName, "Clubs" ); break;
case Spades: strcat( szName, "Spades" ); break;
}
return szName;
}
An enumerated type is an integral type. The identifiers introduced with the enum declaration can be used wherever constants appear. Normally, the first identifier’s value is 0 (Diamonds
, in the preceding example), and the values increase by one for each succeeding identifier. Therefore, the value of Spades
is 3.
Any enumerator in the list, including the first one, can be initialized to a value other than its default value. Suppose the declaration of Suit
had been the following:
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. Note that 5 is used more than once.
The default values for these enumerators simplify implementation of the NameOf
function:
char* Card::NameOf() // Get the name of a card.
{
static char szName[20];
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( szName, Numbers[GetCardinal()] );
strcat( szName, " of " );
strcat( szName, Suits[GetSuit()] );
return szName;
}
The accessor function GetSuit
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 in Chapter 4.)