More on Handling Basic Data Types - Enumerated Data Types
(Page 9 of 13 )
You’ll sometimes be faced with the need for variables that have a limited set of possible values that can be usefully referred to by name—the days of the week, for example, or the months of the year. There’s a specific facility, called an enumeration, in C++ to handle this situation. When you define an enumeration, you’re really creating a new type, so it’s also referred to as an enumerated data type. Let’s create an example using one of the ideas I just mentioned—a variable that can assume values corresponding to days of the week. You can define this as follows:
enum Weekday { Monday, Tuesday, Wednesday, Thursday,
Friday, Saturday, Sunday };
This declares an enumerated data type called Weekday, and variables of this type can only have values from the set that appears between the braces, Monday through Sunday. If you try to set a variable of type Weekday to a value that isn’t one of the values specified, it will cause an error. The symbolic names that are listed between the braces are called enumerators.
In fact, each of the names of the days will be automatically defined as representing a fixed integer value. The first name in the list, Monday, will have the value 0, Tuesday will be 1, and so on through to Sunday with the value 6. You can declare today as an instance of the enumeration type Weekday with the statement
Weekday today = Tuesday;
You use the Weekday type just like any of the basic types you’ve seen. This declaration for today also initializes the variable with the value Tuesday. If you output the value of today, the value 1 will be displayed.
By default, the value of each successive enumerator in the declaration of an enumeration is one larger than the value of the previous one, and the values begin at 0. If you would prefer the implicit numbering to start at a different value, a declaration like this one will make the enumerators equivalent to 1 through 7:
enum Weekday { Monday = 1, Tuesday, Wednesday, Thursday,
Friday, Saturday, Sunday };
The enumerators don’t need to have unique values. You could define Monday and Mon as both having the value 1, for example, with this statement:
enum Weekday { Monday = 1, Mon = 1, Tuesday, Wednesday,
Thursday, Friday, Saturday, Sunday };
This allows the possibility of using either Mon or Monday as the value for the first day of the week. A variable, yesterday, that you’ve declared as type Weekday could then be set with this statement:
yesterday = Mon;
You can also define the value of an enumerator in terms of a previous enumerator in the list. Throwing everything you’ve seen so far into a single example, you could declare the type Weekday as follows:
enum Weekday { Monday, Mon = Monday,
Tuesday = Monday + 2, Tues = Tuesday,
Wednesday = Tuesday + 2, Wed = Wednesday,
Thursday = Wednesday + 2, Thurs = Thursday,
Friday = Thursday + 2, Fri = Friday,
Saturday = Friday + 2, Sat = Saturday,
Sunday = Saturday + 2, Sun = Sunday
};
Now, variables of type Weekday can have values from Monday to Sunday and from Mon to Sun, and the matching pairs of enumerators correspond to the integer values 0, 2, 4, 6, 8, 10, and 12.
If you’d like, you can assign explicit values to all the enumerators. For example, you could define this enumeration:
enum Punctuation { Comma = ',', Exclamation = '!',
Question='?' };
Here, you’ve defined the possible values for variables of type Punctuation as the numerical equivalents of the appropriate symbols. If you look in the ASCII table in Appendix A, you’ll see that the symbols are 44, 33, and 63, respectively, in decimal, which demonstrates that the values you assign don’t have to be in ascending order. If you don’t specify all of them explicitly, values will continue to be assigned by incrementing by 1 from the last specified value, as in the second Weekday example.
The values that you specify for enumerators must be compile-time constants— that is, constant expressions that the compiler can evaluate. Such expressions can only include literals, enumerators that have been defined previously, and variables that you’ve declared as const. You can’t use non-const variables, even if you’ve initialized them.
Anonymous Enumerations By declaring variables at the same time as you define the enumeration, you can omit the enumeration type, provided that you don’t need to declare other variables of this type later on, for example:
enum { Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday, Sunday } yesterday, today, tomorrow;
Here, you declare three variables that can assume values from Monday to Sunday. Because the enumeration type isn’t specified, you can’t refer to it. You can’t declare other variables for this enumeration at all, because doing so would require you to name the enumeration type, which is simply not possible.
A common use of anonymous enumeration types is as an alternative way of defining integer constants, for example:
enum { feetPerYard = 3, inchesPerFoot = 12, yardsPerMile =
1760 };
This enumeration contains three enumerators with explicit values assigned. Although you’ve declared no variables of this enumerated data type, you can still use the enumerators in arithmetic expressions. You could write this statement:
std::cout << std::endl << "Feet in 5 miles = " << 5 *
feetPerYard * yardsPerMile;
The enumerators are converted to type int automatically. It may look as if little (if anything) is to be gained by using an enumeration to define integer constants, but you’ll see when you learn about classes that it provides a very useful way of including a constant within a class. For now, let’s look a little more closely at the conversion of enumerated data types.
Casting Between Integer and Enumeration Types In addition to the enumerators themselves, you can use a variable of an enumeration type in a mixed arithmetic expression. An enumerated data type will be cast automatically to the appropriate type, but the reverse isn’t true; there’s no automatic conversion from an integer type to an enumeration type. If you’ve declared the variable today to be of type Weekday that you defined previously, you can write
today = Tuesday; // Assign an enumerator value
int day_value = today + 1; // Calculate with an
enumerator type
The value of today is Tuesday, which corresponds to 1, so day_value will be set to 2. Although the enumerator Wednesday corresponds to the value 2, the following statement will not compile:
today = day_value; // Error – no conversion!
However, you can achieve the objective of this statement by putting in an explicit cast:
today = static_cast<Weekday>(day_value); // OK
With an explicit cast, the integer value you’re casting must be within the range of the enumerators, or the result is undefined. This doesn’t mean that it must correspond to the value of an enumerator—just that it must be equal to or greater than the lowest enumerator, and less than or equal to the highest enumerator. For example, you could define an enumeration, Height, and declare a variable of that type with this statement:
enum Height { Bottom, Top = 20 } position;
The enumerator Bottom corresponds to the value 0, and Top corresponds to the value 20. The range is therefore from 0 to 20, so you could assign a value to the variable position with this statement:
position = static_cast<Height> (10);
The value assigned to position doesn’t correspond to either of the enumerators, but it’s nonetheless a legal value because it falls within the range of the minimum and maximum values of the enumerators. For a variable of the Punctuation type that you saw earlier, you could legally cast any integer from 33 to 63 to that type and store it, although in this instance it’s difficult to see what purpose it would serve.
This article is excerpted from Beginning ANSI C++ The Complete Language by Ivor Horton (Apress, 2004; ISBN 1590592271). Check it out at your favorite bookstore today. Buy this book now. |
Next: Try It Out: Enumerated Data Types >>
More C++ Articles
More By Apress Publishing