Name: _____________________ Class: CET 375
SSN/ID:   _____________________ Section & Group: ____________
Overloading Operators and Extending Data Types (Enumerations)


You are to extend the data type Rock developed in Lab Exercise 4A by adding input/output operations. You will then use your Rock type in a program that reads a file of rock names, uses an array indexed by Rock to count occurrences of each rock, and then display the counts in a histogram (bar graph).

If you haven't already done so, please download the program source_lab04_geology.cpp to your home directory and rename it to geology.cpp.
Also, please download the file source_lab08_rockfile.txt to your home directory and rename it to rockfile.txt.

A Short Tutorial on Overloading Operators

  1. How can operators be implemented as functions in C++?
    In C++:
    the full name of the + operator is operator+
    the full name of the * operator is operator*
    etc.
    so,
    the full name of the << operator is operator<<, and
    the full name of the >> operator is operator>>
    Thus, we need to define a function of the form:
    	ReturnType operator<< (parameter_list) {
    }
    	
  2. What parameters does this function operator<<() need?

    For the expression 1/2, the signature of operator/ is (int, int).
    For the expression 1.0/2.0, the signature of operator/ is (double, double).

    For the expression cout << 123, the signature of operator<< is (ostream &, int).

    The first parameter is a reference parameter (which makes it an alias for the corresponding argument) because output changes the ostream argument (by inserting 123 into it).
    For the expression cout << 1.23, the signature of operator<< is (ostream &, double).

    So, to output a Rock value, we need the signature (ostream &, Rock); thus, our function becomes:

    	ReturnType operator<< (parameter_list) {
    }
    	
  3. What should be the function's return type and what should it return?

    Consider the output expression cout << 123; we know this returns the ostream cout. This expression is implemented as the function call:

        operator<<(cout, 123);
        
    Thus, if the corresponding function prototype has the form:
        ______________ operator<<(ostream & out, int value);
        
    operator<<() must return the ostream(cout) that is associated with the first parameter (out).

    This means that:

    → The function must return its first parameter (out).
    → The function's return type must be ostream & so that it returns a reference to (a synonym for) out instead of a copy of out. And since out is just an alias for cout (because it is a reference parameter), the function operator() will actually return the (modified) cout.
    Our output function for our new type Rock thus becomes:
    	ostream & operator<<(ostream & out, Rock rockVal) {
    	   // Statements to output to out the characters corresponding to rockVal
    
    	   return out;
    	}
    	
Adding an Output Operator to Type Rock

We still have I/O problems, and we will address the output problem first: Displaying a value of type Rock gives an integer (0, 1, 2, ..., 8) instead of the name of a rock. You are to remedy this by implementing an output operation for type Rock.

We could write a function Display() similar to the functions Next() and RockKind() and pass the Rock object to it. Instead, we will overload the output operator << for type Rock.

Nearly all of the C++ operators can be overloaded (see Table C.2 in Appendix C for those that cannot). In particular, we can overload the output (<<) and input (>>) operators with type-specific definitions. That is, when these operators are not defined for a new type like Rock, C++ allows the programmer to provide definitions of them for that type. Then, executing a statement like:

cout << rockVal << endl;
will display some on-screen representation of the Rock value of rockVal; for example, if rockVal has the value BASALT, the characters B, A, S, A, L, and T will appear on the screen.

Add an output operator << to our Rock type by overloading the function operator<<(). You need only add statements to the preceding function outline to output character strings corresponding to the rockVal:

For rockVal = BASALT:     out << "BASALT";
For rockVal = DOLOMITE:     out << "DOLOMITE";
. . .
For rockVal = ROCK_OVERFLOW:     out << "*****";
(A switch statement works nicely for this.)

Then, recompile, link, and execute the program geology.cpp as before, entering the numeric codes of rocks and observing the outputs produced.

Adding an Input Operator to Type Rock

After overloading the output operator <<, you should be able to overload the input operator >>. Design it so that entering any of the strings:

basalt
or
BASALT
or
Basalt
or . . . in response to:
cin >> sample;
will assign BASALT to sample

Notes:

Be sure to test that your input operator works correctly. If you use geology.cpp to test it, replace the "patch":
int temp; cin >> temp;  sample = Rock(temp);
added (in the lab exercise) in the input loop with the original statement:
cin >> sample;
Application

The file rockfile.txt contains a random collection of names of rocks. Write a program that:

  1. Declares an integer array count whose indices are of type Rock and all of whose elements are initialized to 0.
  2. Reads the rock names from the file rockfile.txt and, for each rock, increments the appropriate element of count by 1; for example, if the rock is Basalt, then count[BASALT] should be incremented by 1.
  3. Display the elements of count as a histogram (bar graph) something like the following:
        BASALT    :XXXXXXXXXXXXXXX (15)
        DOLOMITE  :XXXXX (5)
        GRANITE   :XXXXXXXXXXXX (12)
        LIMESTONE :XXXXXXXXXXXXXXXXXXXXXXXXXX (26)
        MARBLE    :XXXXXXXXXXXXXX (14)
        OSBSIDIAN :XXXXXXX (7)
        QUARTZITE : (0)
        SANDSTONE :XX (2)
        
    where the length each bar (the number of X's) and the number in parentheses indicates the number of times that rock was found in the file.

Hand In:

  1. Listings of rock.h and rock.cpp
  2. A listing of the driver program you used to test the library
  3. A demonstration tat your program and library compiled and linked correctly
  4. A sample run of the driver program that thoroughly exercises all of your Rock operations and demonstrates that they work correctly
  5. A listing of the rock-counting program in the Application
  6. A demonstration that your program and library compiled and linked correctly
  7. A sample run of the program
Category Points Possible Points Received
Header File (20)
   Opening Documentation 5 __________
   Function Prototypes and Specifications 10 __________
   Style/Readability 5 __________
Implementation File (30)
   Correctness of Function Definitions 20 __________
   Structure of Function Definitions 5 __________
   Style/Readability 5 __________
Testing (30)
   Driver Program 15 __________
   Adequate Testing of Library 15 __________
Application (70)
   Correctness (including following instructions) 50 __________
   Structure 10 __________
   Style and Documentation 10 __________


TOTAL

150

__________


Ricky J. Sethi <rickys at sethi.org>
Last modified: Mon May 5 02:26:51 PDT 2003