CSCI 2170 LAB 17
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 17

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
F.  Accessors and Mutators
G.  Array of Objects

 

A. Review

In Lab 16, we introduced the C++ class construct that is used to define an object.  The general form of the class specification section (typically stored in a .h header file) usually resembles something like the following:

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

We also saw that the implementation section for the class contains implementations for methods of the class.  Short methods could be completely defined in the class specification; these are called inline functions. However, except for exceptional circumstances, we usually avoid inline functions. It is considered better if the class specification contains only the specification of the class and no code. The actual implementation of the class should be contained in a separate implementation file.

We learned in Lab 16 to declare (instantiate) 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 members and methods 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 for the access specifiers. What should they be replaced by if the client (main) program is to be denied direct access to 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 method printRate().


D. The private section of the class definition contains the data members and methods that can only be accessed by _________________ of the class.


E.    (T/F) Given the following class specification:
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 additional features of the C++ class.  Consider the Clock class that we discussed in Lab 16.  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" that connects the input file stream ins to the file "myfile.dat".  The following shows an alternate way to declare an input file 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 method) 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 Loan class, any constructor must be named Loan().
  2. A constructor is a function that cannot return a value.  Thus no type, not even void, can be given at the start of the method 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)
     //in the public interface
     
     //class constructor that initializes the clock to
     //h hours, m minutes, s seconds and meridian (am or pm).
     Clock(int h, int m, int s, atring mer);

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

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

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

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
     string meridian;  //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 methods 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 method.  The implementation of the Clock constructor would appear as follows:

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

Since the class and the constructor 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 the 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.

In our clock example, the constructor has parameters to allow the hours, minutes, seconds, and meridian to be set. A constructor does not have to have any parameters. If the constructor has no parameters, it is called the default constructor. Often a default constructor is provided to set the data members to default values. The implementation for a default constructor for the clock class might look like:

    //The default  constructor sets the time on the clock
    //to 12:00:00am
    Clock::Clock()
    {
        hr = 12;
        min = 0;
        sec = 0;
        meridian = "AM"
    }
		

To create an instance of the Clock class using the default constructor, the following statement might appear in a main program:

    Clock myClock;
				

Notice that there are no parenthesis after myClock to indicate that a function with no arguments is being called.   Just remember that this is how the default constructor is activated. 


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:
Copy these $CLA data files (that contain store data) ex3_data.0, ex3_data.1, and ex3_data.2 to your account.

Copy the files storeClassa.h, storeClassa.cpp, and inlab17a.cpp 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 (remember, the default constructor receives no parameters). This default constructor should set the number of tables and chairs to 0 and the store's name to the empty string.
  • To inlab17a.cpp, add a declaration for an object store1 of type StoreClass.
  • Using the script command, create the lab17ex3.log file containing a print out (pr -n -t -e4 ...) of storeClassa.h and inlab17a.cpp, a compile, and a run of the program.


Exercise 4:
A.    The constructor is normally a __________________.
A. public member function
B. private member function
C. public data member
D. private data member

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

Constructors will be considered again after we discuss a feature of C++ that 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 that 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 (i.e., function signature) in which the function or operator occurs.  Suppose we wished to have two meanings for a function called avg() that would average numbers and we provide the following definitions:

//Find the average of two integers
float avg(int a, int b)
{
     return float(a+b)/2.0;
}
and
//Find the average of an array of n integers
float avg(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 " << avg(a, b)
     << endl;
cout << "The average of the integers 10, 20, 30, 40,"
     << " 50 is" << avg(x, 5) << endl;

As you can see the meaning of the function avg() 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:
Copy the files storeClassb.h, storeClassb.cpp, and inlab17b.cpp 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 inlab17b.cpp, read the comments and add activations for each of these methods as described in the comments. Using the script command, create the lab17ex6.log file containing a print out (pr -n -t -e4 ...) of storeClassb.h, inlab17b.cpp, 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 (from doing Exercise 3).
Exercise 7:
A.    Overloading is an example of ___________________, a term derived from a Greek work meaning "many forms".
B.    (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 16, 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 and leaves the data members uninitialized.  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 that did not contain the default constructor but did contain a different constructor:

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 that requires no arguments.  Since the class only has one constructor that 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) that 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 that initializes the clock to
//12:00 am.
Clock::Clock()
{
    hr = 12;
    min = 0;
    sec = 0;
    meridian = "AM";
}

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:
Copy the files storeClassc.h, storeClassc.cpp, and inlab17c.cpp 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. Using the script command, create the lab17ex9.log file containing a print out (pr -n -t -e4 ...) of storeClassc.h, storeClassc.cpp, a compile, and a run.

Exercise 10:
A.    (T/F) It is possible to have two default constructors in a class definition.

B.    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 meridian data in clock1 is replaced by the hr, min, sec and meridian 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 members of the class on 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, meridian are private data members of the lhs clock
     if ((hr != rhs.hr)||(min != rhs.min)||(sec != rhs.sec)||(meridian != rhs.meridian))
          notequal = true;
     return notequal;

} // end operator!=

Now if this overloaded operator were used to compare two instances of the clock class as below, myClock would be passed to the method above as an actual argument to the method. The object yourClock would be passed the message to compare itself with the argument to the right of the !=.

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

Exercise 11:
A.   (T/F) The C++ compiler automatically 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:
Copy the files storeClassd.h, storeClassd.cpp, and inlab17d.cpp 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.
Using the script command, create the lab17ex12.log file containing a print out (pr -n -t -e4 ...) of storeClassd.h, storeClassd.cpp, a compile, and a run.
Exercise 13:
A.    Write the heading of the function operator == for the Clock class (the usage is lhs == rhs).
B.    (T/F) We can overload the + operator to add three user defined matrices.


F.  Accessors and Mutators

Suppose we have a Book class defined as follows:

class Book
{
private:
	string title;       //the title of the book
	string author;      //the author of the book
	string ISBN;        //the ISBN number for the book
public:
    //the default constructor
    Book();
    
    //an overloaded constructor receiving all data members as arguments
    Book(string title, string author, string ISBN);
    
    //gets (accessors) and sets (mutators) to allow a client to
    //have access to each data member and to allow the client to
    //modify each data member.
    void setAuthor(string a);
    string getAuthor();
    void setTitle(string t);
    string getTitle();
    void setISBN(string i);
    string getISBN();
    
    //prints all of the data members of a book
    void print();
};
    

We have introduced two new types of methods in the book class above. The first is a accessor (aka getter) method. An accessor method allows the client access to an individual data member. The second is a mutator method (aka setter) method. A mutator allows the client to change a data member within reason. The Book class has ultimate control over what is placed into a data member. For example, in the mutator for the ISBN number, the Book class might check to see if the ISBN number is a valid number before assigning it to the data member.


Exercise 14:
A. Write the function prototype for a mutator for the Clock class that would set the hours in a clock object to the value of the parameter passed to the method.
B. Write the function implementation for the mutator defined in A. The mutator should contain code to determine whether the value of the parameter is an acceptable value. Otherwise, set the clock's hour to 12.
C. Write the function prototype for an accessor for the clock Class that would return the data member for hours to the calling program.


G.  Array of Objects

A client must often work with an array of objects.  For example suppose that a client is working with an array of books as follows:

Book arrayOfBooks[10];
    

When this array of books is created, the default constructor is activated for all 10 Book objects that are in the array. Thus the class must have a default constructor or the compiler must provide one.

If the client wished to read the array of books, it might be read using the code below:

string author, title, ISBN;

//read the data for 10 books
for (int i = 0; i < 10; i++)
{
	cout << "Please enter the author, title, and ISBN for book " << i  << endl;
	
	//read the author, title, and ISBN -- these might contain spaces so use getline
	getline(cout, author);
	getline(cout, title);
	getline(cout, ISBN);
	
	//put the author, title, and ISBN into the ith book object
	arrayOfBooks[i].setAuthor(author);
	arrayOfBooks[i].setTitle(title);
	arrayOfBooks[i].setISBN(ISBN);
}
	 
    

Notice in the code above that using an array of objects is similar to using an array of structs. The index in the array appears first so that the compiler can determine which object is to be used. Next the method that is being used with that object appears. If we wanted to set the title of the 0th book in the array to "The Firm" then we would use the notation

arrayOfBooks[0].setTitle("The Firm");


Exercise 15:
Write code that might be placed in a client to print all of the books in the array, arrayOfBooks.  

 
----- End of Lab 17 - C++ Classes Continued -----
Complete the Exercises on the Answer Sheet.

Submit the final Lab 17 Answer Sheet (AnswerSheet17.pdf) using the GUS web site with AssignmentID lab17ans.

Submit the required log files by using the command

$ handin lab17log lab17ex3.log lab17ex6.log lab17ex12.log

 
 
Return to the top of this lab