SECTION 3 - ENUMERATED TYPES/TYPEDEF

Introduction

-ITRW, data does not always fall into nicely pre-defined categories (int, float, etc.)

-C++ provides many ways to construct new data types

-Note that a data type not only defines what kind of data is used, but also what operations can be performed on that data

-We'll now explore two ways: enumerated types and typedef

Enumerated types

-We use types every day:

cars - BMW, Mercedes, Toyota, etc
Programming languages - C++, C, Pascal, BASIC, FORTRAN, COBOL
Furniture - tables, chairs, sofas, footstool, etc

-Suppose we have a problem for which there is no pre-defined data type:

-A data object named Hue, which can have 7 values: red, orange, yellow, green, blue, indigo and violet
-we could define Hue as type int, and assign numbers for colors (1-7), but that makes for unreadable code, and forces programmer to remember which color is which number - a definite problem for long-term maintenance
-instead, we can define an enumeration to construct a completely new data type

--An enumeration requires that you name the type, and explicitly list all the values (enumerators) of this new type:

enum Color {Red, Orange, Yellow, Green, Blue, Indigo, Violet};

//enum is C++ keyword to denote enumerate type
//Color is the name of the new type (analogous to char, int, etc.)
//enumerators are enclosed in {}'s, and separated by commas
Color
Hue; //Hue is now a variable of type Color,
//the values it can hold are Red, Orange, etc. (NOT #'s!!)

-This creates a data type of Color, and specifies the values variables of type Color can have

-And then declares a variable of type Color, called Hue

-The compiler assigns internal values of 0-# for each item in the enumerated list

-This enables the use of relational operators

-You can specify the numbers for compiler to use, inside list

-Enumerators must be valid identifiers: start with letter, contain letters, digits, underscore

-can only use an enumerator in one type - can't use it in more than one list!

-must use exact enumerator value ('Red' is not the same as 'red'!)

-examples:

enum Boolean {True = 1, False = 0};

Boolean

Flag;

Flag = True;

---

enum Captains {Kirk, Picard, Janeway, Sisko};

Captains

Capt1, Capt2;

Capt1 = Kirk;

Capt2 = Picard;

if (Capt1 < Capt2) //TRUE! (0 < 1)

cout << "I told you so!\n";

else

cout << "You gotta be kidding!]n";

--

enum Colors {Red, White, Blue};

Colors

Hue;

enum DarkColors {Black, Brown, Blue}; //ERROR! Blue used 2x

extended example:

enum Day {DayUnderflow = -1, //too-low error

Sunday, Monday, Tuesday, //0-2

Wednesday, Thursday, Friday, //3-5

Saturday, //6

NumDays, //7

DayOverflow=7}; //too-high error (also 7)

// under/overflow values help prevent "falling off list"

Day

Today, Tomorrow, Yesterday;

Today = Tuedsay;

//we'd like to be able to do this:

Tomorrow = Next(Today);

//so we need to write a function of type Day!!

--

/*This function returns the Day that follows its argument.

Receives: a Day, DayVal

Returns: the successor of DayVal (or overflow error)

Output: Error message if DayVal is invalid

*/

Day Next(Day DayVal)

{

const char

ErrMsg[] = "Invalid day passed to Next()\n";

switch(DayVal)

{

case Sunday : return Monday;

case Monday : return Tuesday;

case Tuesday : return Wednesday;

case Wednesday : return Thursday;

case Thursday : return Friday;

case Friday : return Saturday;

case Saturday : return Sunday;

default : cerr << ErrMsg; return DayOverflow;

}

}//end of function

-Note that this function is of type DAY, since it must return a value of that type!

I/O with enumerated type values

-"Houston, we have a problem!" VC++ won't allow you to use <<, >> with enumerated types!

-What if we want to do this:

for (Day d=Sunday; d<=Saturday; d=Next(d))

cout << d << endl;

-IT WON'T COMPILE!

-What we need to do is overload the input/output operators!

-we've seen overloaded operators before, now we'll learn how to do it ourselves!

-To overload an operator, follow these 4 steps:

  1. Name the operand to overload -
    -use the provided notation: operator<< (no space)
  2. specify the (new) parameter types the operator is to work with
    -still want to use cout, which is of type ostream (and is modified)

-want to use a variable of type Day (not modified)

operator<<(ostream& Out, Day Dayval)

  1. specify the type of value returned by the operator
    -it is of type ostream
    ostream& operator<<(ostream& Out, Day Dayval)
  2. specify the actions the operator is to perform with the parameters
    -see below for complete function

/*------------------------------------------------------------------

This function displays a Day value.

Receive: Out, an ostream reference

DayVal, a Day value

Output: the character string corresponding to DayVal onto Out

Return: ostream reference Out

-------------------------------------------------------------------*/

ostream& operator<< (ostream& Out, Day DayVal)

{

const char

ErrorMsg[] = "\n*** <<: invalid Day value received!\n";

switch (DayVal)

{

case Sunday: Out << "Sunday";

break;

case Monday: Out << "Monday";

break;

case Tuesday: Out << "Tuesday";

break;

case Wednesday: Out << "Wednesday";

break;

case Thursday: Out << "Thursday";

break;

case Friday: Out << "Friday";

break;

case Saturday: Out << "Saturday";

break;

case DayOverflow: Out << "Day Overflow";

break;

case DayUnderflow: Out << "Day Underflow";

break;

default:

cerr << ErrorMsg;

}

return Out;

}

-NOW, we can print variables of type Day, using the << operator, as normal

-Can do something similar for overloading the >> operator:

/*-----------------------------------------------------------------

This function inputs a Day value.

Receive: In, an istream reference

DayVal, a Day reference

Input: A character string, from In

Output: An error message, if there is no Day value that

corresponds to the input string.

Return: If there is a Day value corresponding to the string,

return that Day value via parameter DayVal

istream In

------------------------------------------------------------------*/

#include <ctype.h> //for case conversion functions

#include "Strings.h" // class Strings

istream& operator>> (istream& In, Day& DayVal)

{

char Str[10]; // the input string

const char  ErrorMsg[] = "\n*** >>: invalid Day value received!\n";

In >> Str; // 1. Input the string

for (int i = 0; i < Str.Length(); i++) // 2. Convert it

if (isupper(Str[i])) // to lowercase

Str[i] = tolower(Str[i]);

if (!strcmp(Str , "sunday")) // 3. Set DayVal to the

DayVal = Sunday; // value corresponding

else if (!strcmp(Str , "monday")) // to the string Str

DayVal = Monday;

else if (!strcmp(Str , "tuesday"))

DayVal = Tuesday;

else if (!strcmp(Str , "wednesday"))

DayVal = Wednesday;

else if (!strcmp(Str , "thursday"))

DayVal = Thursday;

else if (!strcmp(Str , "friday"))

DayVal = Friday;

else if (!strcmp(Str , "saturday"))

DayVal = Saturday;

else

{

DayVal = DayOverflow; // Return error value

cerr << ErrorMsg; // Display error msg

}

return In; // 4. return In

}

-NOW we can use >> to read into variables of type Day, just as normal

--

Obviously, enumerated type definitions and operations on those objects should be in a library!

-for example, we would place the definition of Day, along with prototypes for the operator overload functions, the Next() function, a possible Previous() function (?), etc. into the header file, with the function definitions in the library implementation file

A warning (from online VC help):

Postincrement and postdecrement, when used on enumerated types, yield integral values. Therefore, the following code is illegal:

enum Days {

Sunday = 1,

Monday,

Tuesday,

Wednesday,

Thursday,

Friday,

Saturday

};

void main()

{

Days Today = Tuesday;

Days SaveToday;

SaveToday = Today++; // error

}

The intent of this code is to save today's day and then move to tomorrow. However, the result is that the expression Today++ yields an int - an error when assigned to an object of the enumerated type Days.

DESPITE EXAMPLES IN THE BOOK TO THE CONTRARY! MUST OVERLOAD THE ++ OPERATOR TO WORK W/YOUR ENUMERATED TYPE or CREATE THE EQUIVALENT OF THE NEXT() FUNCTION

--

The 'typedef' statement

-Another mechanism for declaring data types is the typedef statement

-It actually makes a synonym for an existing type (whether pre-defined or enumerated)

-e.g., if we preferred to use the word 'real' instead of double, we could:

typedef double real;

-After this statement, we could use the word 'real' in any place we would have previously used 'double' and it would work! (constants, parameters, function types, etc)

-Note the difference between declaring a variable and making a typedef:

double real; //a double variable named real

typedef double real;//real is a synonym for double

-We use typedef to enhance readabilty (for future maintenance)