7.13 THE ENUMERATION TYPE IN C


7.13 THE ENUMERATION TYPE IN C++

To recap the basic idea behind an enumeration, suppose we wish to declare variables of type weight and suppose that these variables will only take one of a small number of values. We can then define an enumeration in the following manner:

      enum weight {light, medium, heavy, very_heavy};               //(A) 

The symbolic constants light, medium, heavy, and very_heavy represent symbolically the small number of different values we wish for a variable of type weight to possess. Now we can declare a variable to be of type weight by[13]

     weight w;                                                       //(B)     w = heavy;     cout << w;                                                //(C) 

As the reader knows from his or her experience with C, while such enumerations can make the source code clearer to read, the compiler actually replaces the symbolic constants by integral values, known as the enumerators. The enumerators must be integer constants. Ordinarily, the enumerators will start at 0 for the first symbolic constant, 1 for the next, and so on. So the statement in line (C) above will actually display 2 on a terminal.

The following example shows the different ways in which an enumeration type can be used in C++: globally, inside a class definition, inside a function, and so on. The definition of the class X starts with a declaration of two enumeration types, one in line (A) for weight and the other in line (B) for simply declaring two symbolic constants d1 and d2 of particular integer values. After that we declare two data members for the class, x of type int and wx of type weight. This is followed by a constructor in line (C). The scope of the enumerations shown in lines (A) and (B) ends with the class definition. The class definition is followed by two more enumerations in global scope in lines (D) and (E).

 
//Enum.cc #include <iostream> using namespace std; class X { public: enum weight {light, medium, heavy, very_heavy}; //(A) enum {d1 = 3, d2 = 5}; //(B) int x; weight wx; X( int i, int j ) {x = i + d1; wx = (weight) (j + medium) ;} //(C) }; enum {c1=17, c2 =19}; //global //(D) enum height {tall, very_tall}; //global //(E) int main() { X obj1(100, 200); //(F) cout << obj1.x << " " // 103 //(G) << obj1.wx << endl; //201 //(H) //X obj2(100,200); //ERROR //(I) int y = c1; //(J) cout << y << endl; // 17 //(K) height h; //(L) h = tall; //(M) cout << h << endl; // 0 //(N) return 0; }

In main, we invoke X's constructor with two arguments, 100 and 200, in line (F). The interesting thing about the object thus constructed is that the value printed out for the data member wx is 201, as shown in line (H). But this value does not correspond to any of the enumerators for the small number of permissible symbolic constants declared for the weight type in line (A). In general, an enumeration type can acquire an integer value that may not be any of the enumerators listed in or implied by the enumeration definition.

The constructor invocation in the commented out line (I) results in a compile-time error since the symbolic constant light in not in scope in main(). As we mentioned before, the symbolic constants introduced via the two enumerations in lines (A) and (B) are not in scope outside the definition of the class.

On the other hand, the statements in lines (J) and (L) that involve the symbolic constants c1 and h are legal since these symbolic constants were introduced through the enumerations defined in global scope in lines (D) and (E).

We will now show how enumerations can prove useful in object-oriented programming. Let's say we want to define a class Student with data members for designating what department the student is enrolled in, and what the status of the student is (in the sense of a student being full-time, part-time, and so on). In other words, the Student class will have data members whose values will be symbolic. We can accomplish this by declaring the following enumerations:

     enum Status { FullTime,                   PartTime,                   Exchange,                   StatusUnknown };     enum School { Engineering,                   Mathematics,                   Physics,                   Arts,                   Chemistry,                   SchoolUnknown }; 

This would allow us to endow the class Student with data members of type Status and School. It would also allow us to declare a variable of type Status and School by statements like

     Status st = PartTime; 

But note that the compiler will replace the symbolic constant PartTime by some integer, as mentioned previously. So if at some point later we said

     cout << st; 

we will see some integer printed out on the screen (1 in this case). What we'd really like to see is the symbolic value of the variable st printed out. This can be accomplished by defining a label array at the same time an enumeration is created:

     enum Status { FullTime,                   PartTime,                   Exchange,                   StatusUnknown };     static const string statusLabels[] = { "full-time",                                            "part-time",                                            "exchange",                                            "unknown" }; 

Now if we say

     Status st = PartTime;     cout << statusLabels[ st ]; 

the output command will cause the symbol part-time to be printed out on the screen. If desired, we could have the string literals in the statusLabels array to correspond exactly to the identifiers used in the enumerations.

The following program shows the use of the enumeration types as data members of a class and how a declaration of an array of labels corresponding to the symbolic constants of an enumeration can be used for a user-friendly output.

 
//EnumWithLabelArray.cc #include <string> enum Status { FullTime, PartTime, Exchange, StatusUnknown }; static const string statusLabels[] = { "full-time", "part-time", "exchange", "unknown" }; enum School { Accounting, Business, Engineering, Mathematics, Physics, Arts, Chemistry, SchoolUnknown }; static const string SchoolLabels[] = { "Accounting", "Business", "Engineering", "Mathematics", "Physics", "Arts", "Chemistry", "unknown" }; class Student { string name; Status status; School school; public: Student( string nam, Status st, School sch) : name( nam ), status( st ), school( sch ) {} string getName() const { return name; } void print() const { cout << getName() << " is a " << statusLabels[ (int) status ] << " student in the school of " << SchoolLabels[ (int) school ] << endl; } }; int main() { Student amy( "Amy", FullTime, Arts ); amy.print(); retrun 0; }

This program produces the output:

    Amy is a full-time student in the department of Arts 

[13]Contrast this with C, where, with the enum definition of line (A), you would use the following syntax for the declaration in line (B):

          enum weight w; 

That's because weight is not a type name in C. However, in C we can use a typedef to make weight a type name by

           typedef enum {light, medium, heavy, very_heavy} weight; 

and then we can declare w to be of type weight by

           weight w; 




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net