CSCI 2170 LAB 7
C++ Classes Continued

Objectives:
To introduce additional features of the C++ class
To introduce overloading of C++ functions
To introduce overloaded functions
To introduce overloaded operators
CREATE ANSWER SHEET for LAB 7

In this laboratory assignment we will consider the following:

A.  Review of C++ Class Construct
B.  Using C++ Constructors
C.  Overloaded Functions
D.  Overloading Constructors in a C++ Class
E.  Overloaded Operators

 

A. Review

In Lab 6, we introduced the C++ class construct which is used to define an object.  The general form of the class specification section could be set up as follows:

class SomeClass
{
public:
       //Data items and function prototypes are
       //included in this section to provide the public interface
       //of the object (the data and operations
       //which are needed to use the object effectively)
       .
       .
       .
private:
       //This section contains data items and function
       //prototypes which can only be accessed by members
       //of the class.
       .
       .
};

We also saw that the implementation section for the class contains member function definitions of the class.  Short functions can be completely defined  in the class specification.  However, it is usually considered better if the class specification is precisely that -- the specification of the class.  The actual implementation of the class should be contained in a separate implementation section.  We learned in Lab 4 to declare an instance of the class as follows:

SomeClass object1;
NOTE: For each of the following exercises, indicate answers on the answer sheet.

Exercise 1:
A. The public section of the class specification contains the data items and function prototypes that provide the ________________ of the object.
B. Given the following specification:

     class LoanClass
     {
          1:
               void printRate();
               float payoff();
               void schedule();
               void LoanSettings (char t, float r, int m);
          2:
               char type;
               float rate;
               int months;
               float simplePayment();
               float compoundPayment();
     };

the numbers 1 and 2 are place holders. What should they be replaced by if the main program cannot access the data member months?
       A. specification and implementation
       B. object and declaration
       C. public and private
       D. declaration and prototype

C. Given a variable loan of type LoanClass, write a call to the member function printRate().


D.P    (Any question ending in 'P' is a Posttest question. These questions must be done without help from your lab instructor or anyone else) The private section of the class definition contains the data items and function prototypes which can only be accessed by _________________ of the class.


E.P    (T/F) Given the following class definition:
class LoanClass
{
 public:
        void printRate();
        float payoff();
        void schedule();
        void LoanSettings(char t, float r, int m);
 private:
        char type;
        float rate;
        int months;
        float simplePayment();
        float compoundPayment();
};
the main function of the program can make a call to simplePayment() for any LoanClass instance.

B. Constructors

With that brief review, we will introduce some addititonal features of the C++ class.  Consider the Clock class which we discussed in Lab 6.  If we wished to declare a Clock object and then initialize the data members in the object, we would first have to declare the object:

Clock yourClock;
The Clock object, yourClock,  could now be initialized by calling the setClock() member function.  Initializing yourClock  to the time 10:15:00 am could be accomplished as follows:
yourClock.setClock (10,15,0,AM);

There is nothing wrong with this method of declaring and initializing an object.  However, there is a more convenient way to initialize the data members of an object when defining the object.  C++ includes special provisions for such initializations.  When a class is defined, a special member function called a constructor can be used.  A constructor is a member function that is automatically called when an object of that class is declared.  A constructor may be used to initialize the values of data members and to do any other initialization that may be needed.

For example, consider the ifstream class.  When we declare an input file stream as:

ifstream ins;
an instance of the ifstream class is created.  The statement
ins.open ("myfile.dat");
is a call to the member function "open" which connects the input stream ins to the file "myfile.dat".  The following shows an alternate way to declare an input stream and to open the stream at declaration time:
ifstream ins("myfile.dat");
This second form of declaration and initialization uses a "constructor" of the class ifstream.

Suppose we wish to declare an instance of a Clock and initialize the Clock to the time 10:15:00 am at declaration time.  If we had an appropriate constructor, we could type:

Clock yourClock (10,15,0,AM);

We now need to learn how to define a constructor (a special member function) to allow us to use the above statement.  A constructor is defined the same way as other member functions, except for two rules:

  1. A constructor must have the same name as the class.  For example, for the Clock class, any constructor for this class must be named Clock().  Similarly for the Book class, any constructor must be named Book().
  2. A constructor is a function which cannot return a value.  Thus no type, not even void, can be given at the start of the function prototype or in the function header.

Let us consider a modified version of the Clock class declaration:

class Clock
{
public:
     //function prototypes of member functions (methods)
     //class constructor which initializes the clock to
     //h hours, m minutes, s seconds and aOrP am or pm.
     Clock(int h, int m, int s, int aOrP);

     //Set the clock to the specified time
     void setClock (int h, int m, int s, int aOrP);

     //Display the time in standard notation
     void displayStandard();

     //Display the time in military notation
     void displayMilitary();

     //Increment the time by one second
     void incrementClock();
private:
     //declarations of data members that are private
     int hr,           //an hour in the range 1 - 12
         min,          //a minute in the range 0 - 59
         sec,          //a second in the range 0 - 59
         ampm;         //is the time  AM (0) or PM (1)
};

Note that the name of the constructor is Clock(), the same as the name of the class.  Also note that the prototype for the constructor Clock does not start with void or with any other type.  Finally note that the constructor is placed in the public section of the class specification.  Normally, you should make your constructors public member functions so all clients may access the constructor.

With the redefined Clock class, two objects of type Clock can be declared and initialized as follows:

Clock yourClock (10, 15, 0, AM);

Clock myClock (1, 30, 45, PM);
Assuming that the implementation of the constructor performs the initializing actions promised, the declaration above would declare yourClock to have the time 10:15:00 am and myClock to have the time 1:30:45 pm.

The implementation of a constructor is given in the same way as any other member function.  The implementation of the Clock constructor would appear as follows:

//Class constructor which initializes the clock to
//h hours, m minutes, s seconds and am or pm.
Clock::Clock(int h, int m, int s, int aOrP)
{
     //hr, min, sec, and ampm are declared in the private 
     //section of the class
     hr = h;
     min = m;
     sec = s;
     ampm = aOrP;
}

Since the class and the constructor function have the same name, the name Clock occurs twice in the function heading.  The Clock before the scope resolution operator :: is the name of the class and
Clock after the scope resolution operator is the name of the constructor function.  Note that there is no return type specified in the function heading.


Exercise 2:
A. A constructor must have the same name as the ___________.
B. What is the type of a constructor?

A. There is no type
B. void
C. Bool because it returns true or false based on whether or not the initialization was successful.
D. The type is dependent upon the actual class.

C. Given the following class specification, write the code necessary to declare and initialize an object "Loan" of LoanClass such that "Loan" is a simple loan ('S') with a .0675 rate and 36 months.

     class LoanClass
     {
          public:
              LoanClass(char t, float r, int m);
              void printRate();
              float payoff();
              void schedule();
          private:
              char type;
              float rate;
              int months;
              float simplePayment();
              float compoundPayment();
     };

Exercise 3:
Load the files storeClassa.h, storeClassa.cc, and inlab7a.cc to your account. These files contain the specification and implementation of a class containing information about a store. Examine each of the files carefully to make sure you understand the code. Add a function prototype to storeClassa.h for the default constructor. To inlab7a.cc, add a declaration for an object store1 of type StoreClass. Turn in a script containing a cat of storeClassa.h, a cat of inlab7a.cc, a compile, and three runs of the programs using ex3_data.0, ex3_data.1, and ex3_data.2 as data files containing store data. You will need to copy these data files to your account.
Exercise 4:
A.P    The constructor is normally a __________________.
A. public member function
B. private member function
C. public data member
D. private data member

B.P     A constructor is used to ____________________ an object when the object is declared.

Constructors will be considered again after we discuss a feature of C++ which allows a function to have multiple definitions.
 
 
 

C. Overloaded Functions

In the English language, a word may have more than one meaning.  We determine the meaning of a word by considering the context in which the word appears.  For example, the word string has two meanings -- an object possibly made from twine which might be used to tie around another object or (in computer science) just a sequence of characters.  We have no problem determining which meaning is intended when we consider the following sentences:

Tie the string around the package so it can be mailed.
A string would be used to represent a word in a dictionary.

Similarly, functions may have more than one meaning in C++.  When this is the case, we say we have an overloaded function.  Thus, the same function name may be defined more than once with different formal parameters.

In C++, we can overload functions and operators by providing multiple definitions for the function or operator. The compiler determines which definition is intended by the context in which the function or operator occurs.  Suppose we wished to have two meanings for a function called ave () which would average numbers and we provide the following definitions:

//Find the average of two integers
float ave (int a, int b)
{
     return float (a+b)/2.0;
}
and
//Find the average of an array of n integers
float ave (int a[], int n)
{
     int sum = 0;
     for (int i = 0; i < n; i++)
          sum += a[i];
     return float (sum) / n;
}
The main function might have the following statements
int a = 2, b = 3;
int x[5] = {10, 20, 30, 40, 50};
cout << "The average of 2 and 3 is " << ave (a, b)
     << endl;
cout << "The average of the integers 10, 20, 30, 40,"
     << " 50 is" << ave (x, 5) << endl;

As you can see the meaning of the function ave() is completely determined by the context (what arguments are sent to the function).  This property of functions with multiple meanings is called overloading.  Overloading is an example of polymorphism, a term derived from a Greek word meaning "many forms".  The use of the same function name to mean different things is called polymorphism.  We will see that polymorphism is very important in defining objects.


Exercise 5:
A. (T/F) The following is an example of the use of an overloaded function.

        int a = 10, b = 6;
        int x[4] = {5, 6, 7, 8};
        cout << sum(a, b) << endl;
        cout << sum(x, 4) << endl;
B. Which of the following determines which definition of an overloaded function is intended based on the context?
A. The user
B. The compiler
C. The linker
D. The processor

C. Which of the following represent situations where function overloading could be used?
A. The program must add 3 numbers. It must also add 3 arrays.
B. The program must multiply two arrays. It must also add two arrays.
C. A and B
D. None of the above

Exercise 6:
Load the files storeClassb.h, storeClassb.cc, and inlab7b.cc to your account. These files contain essentially the same definition for the store class as was used in Exercise 3. The implementation file contains overloaded implementations of the printStore() method. Add function prototypes to the storeClassb.h file for each of these overloaded methods. In inlab7b.cc, read the comments and add activations for each of these methods as described in the comments. Turn in a script containing a cat of storeClassb.h, inlab7b.cc, a compile, and a run. Note: For this program to compile and run, you should have copied the data file ex3_data.0 to your account.
Exercise 7:
A.P    Overloading is an example of ___________________, a term derived from a Greek work meaning "many forms".
B.P    (T/F) The meaning of a function that is overloaded is completely determined by the context (i.e., what statements are around the function call).


 
 
 

D.  Overloading Constructors in a C++ Class

A constructor is called automatically when an object is declared.  In Lab 6, the Clock class and the Date class did not include a constructor.  When a class does not include a constructor, the compiler automatically creates a default constructor for the class.  Thus when the statement

Date christmas;
was used, the compiler provided a default constructor.

Using constructors is an all or nothing situation.  If the class contains a constructor, then every time an object of that type is declared, C++ looks for an appropriate constructor definition in the class.  Thus the following declaration would be illegal for the modified Clock class:

Clock newClock;     //ILLEGAL declaration

The reason this statement is illegal is that since  the Clock class contains a constructor, the compiler will not create a default constructor.  Instead the Clock class is searched for a constructor which requires no arguments.  Since the class only has one constructor which requires four arguments, this is an illegal declaration.   To allow a statement such as the one above, a constructor must be added (an overloaded function) which requires no arguments.

A constructor with no arguments is called a default constructor because it applies in the default case when an object is declared without specifying any arguments.  Since it is likely that an object will be declared without giving any arguments, a default constructor should almost always be included with the class.  The default constructor for the Clock class might be:

Clock::Clock ()
{}

Notice that this default constructor does nothing.   All data values are left uninitialized.  In some cases, the default constructor would be used to initialize appropriate data members to default values.  If the overloaded constructor above were added to the Clock class and the statement:

Clock newClock;
appeared in a C++ program, it would be a legal statement and the default constructor would be called.  In summary, two points can be made about supplying default constructors:
  1. If a class defines no constructor at all, then a default constructor that does nothing is automatically supplied.
  2. If a class defines any constructor, then the default constructor is not automatically supplied.  If a default constructor is needed, an appropriate one must be given explicitly.

As a second example of using overloaded constructors in a class definition, suppose we wished to have a default constructor to set the time of a Clock object to 12:00 am so that any of the following declarations would work.


Clock myClock(10, 15, 0, PM);
Clock yourClock;

The default constructor would now be:


//Class constructor which initializes the clock to
//12:00 am.
Clock::Clock()
{
    hr = 12;
    min = 0;
    sec = 0;
    ampm = 0;
}

It should be noted that you cannot have two default constructors.


Exercise 8:
A.   A constructor with no arguments is called a __________________ constructor.

B.   (T/F) A class must explicitly define a constructor in order for objects of that type to be declared.

C.   Write the function heading for a default constructor for the "Book" class.
Exercise 9:
Load the files storeClassc.h, storeClassc.cc, and inlab7c.cc to your account. These files contain essentially the same definition for the store class as was used in Exercise 3. Add a new constructor to the class. The constructor should receive a string containing the name of the file with the store data. Add this constructor to the header file and to the implementation file. Note: This constructor can just call the method readFile() to read data from the file. Turn in a script containing a cat of storeClassc.h, storeClassc.cc, a compile, and a run.
Exercise 10:
A.P    (T/F) It is possible to have two default constructors in a class definition.

B.P    Define a default constructor for the "Book" class (as it appears in the implementation file) that leaves all data values uninitialized.


 
 
 

E.  Overloaded Operators

Not only can functions be overloaded but operators, such as ==, !=, +, etc., can also be overloaded.  In fact this feature has been used anytime the same operator is used for different types.  For example:

int num1, num2;
Clock clock1, clock2;

//assume that the integer num2 and the Clock clock2 have
//been initialized

//first use of the operator "=" between integer operands
num1 = num2;

//second use of the operator "=" between Clock operands
clock1 = clock2;

The operator "=" is used twice -- once between two integers and once between two Clock objects.  The operator is used to replace the integer num1 by the integer num2 in the first instance.  In the second instance, the hr, min, sec, and ampm data in clock1 is replaced by the hr, min, sec and ampm data of  clock2.

We might also wish to overload other operators such as !=, <, > so that we could do the following for example:

Clock yourClock, myClock;
.
.
.
if (yourClock != myClock)
     cout << "Your clock is wrong.\n";

We cannot use the operator != between two Clock objects without first defining what this would mean.  C++ does provide a default definition of the operator = but does not provide a definition for other operators.  When the operator = is used between two objects of a class, C++ copies the data member of the class to the right of the = to the class on the left.

C++ considers an operator to be a function, so an operator can be overloaded also.  Overloading an operator, such as !=, is very similar to overloading a function.  To overload the != operator, the following function prototype would be included in the Clock specification section.

bool operator != (Clock rhs);

As can be seen, an operator function named "operator op" overloads the operator op.  Thus the function operator !=( ) overloads the operator !=, the function operator < ( ) would overload the operator < and so on.  There are some restrictions:

The implementation of the function operator != for the Clock class follows below:

bool Clock::operator != (Clock rhs)
{
     bool notequal = false;

     //hr, min, sec, ampm are private data members of the lhs clock
     if ((hr != rhs.hr)||(min != rhs.min)||(sec != rhs.sec)||(ampm != rhs.ampm))
          notequal = true;
     return notequal;
}

Exercise 11:
A.   (T/F) C++ provides overloaded definitions for the = operator.
B.   (T/F) It is possible to change the meaning of the + operator for variables of type float.
C.   Write the function heading of an overloaded * operator that multiplies two objects of the myArray class (the usage would be lhs * rhs) and returns a value of type myArray.
Exercise 12:
Load the files storeClassd.h, storeClassd.cc, and inlab7d.cc to your account. These files contain essentially the same definition for the store class as was used in Exercise 3. Add an overloaded == method to the class. This overloaded operator should return true if the names of the stores are the same and false otherwise. Copy the data files ex12_data.0, ex12_data.1, and ex12_data.2 to your account. Turn in a script containing a cat of storeClassd.h, storeClassd.cc, a compile, and a run.
Exercise 13:
A.P    Write the function heading for the function operator == for the Clock class (the usage is lhs == rhs). Use rhs as the formal argument in the heading.
B.P    (T/F) We can overload the + operator to add three user defined matrices.


 
 
 
----- End of Lab 7 - C++ Classes Continued -----
Complete the Exercises on the Answer Sheet.
Turn in the Answer Sheet and the printouts required by the exercises.

 
 
 
Return to the top of this lab
Return to the link page for all 2170 labs