1  Operator Overloading (Section 8.1 in Savitch)

1.1  What is operator overloading?

The compiler knows how to do this:

	int a, b, c;
	
	a = 3;
	b = 5;
	c = a + b;
	
	cin >> a;
	
	cout << a;

However the compiler does not know how do perform these operations for classes that we define.

Remember the intList class, basically a list of int values, with the following class definition:

class intList
   {
   public:
      intList ();                               //Default constructor
      intList (int aList [], int howMany);     
      intList (intList&);                       //Copy constructor
      
      ~intList ();                              //Destructor
      
      void   inputNumbers ();
      void   print        ();
      double average      ();
      
   private:
      int *theList;                //Pointer to point to a dynamic array.     
      int size;                    //Size of the dynamic array.
   };

With the intList class, the following code will not work:

int main ()
   {
   intList list1, list2, list3;
   
   cin >> list1;           //Computer doesn't know how to cin to intLists
   
   cout << list1 << endl;  //Computer doesn't know how to cout from intLists
   
   list2 = list1;          //Computer can't properly assign one intList to
                           //   another
   
   list3 = list1 + list2;  //Computer doesn't know how to add intLists, that 
                           //   is append one list on the end of another
   
   return 0;
   }

Operator overloading is about teaching the computer to do these things.

1.2  Overloading = and other unary operators

To make = work properly for the intList class, we must:

  1. Add the function prototype, intList& operator= (intList&); to the public section of the class definition.
  2. Add the following code to the functions for the class:

    		intList& intList::operator= (intList& aList)
    		   {
    		   delete []theList;
    		   
    		   size = aList.size;         //Copy over the size of aList
    		   
    		   theList = new int [size];  //Reallocate theList to the size of aList
    		   
    		   for (int n = 0; n < size; n++)         //Copy over the numbers
    		      theList [n] = aList.theList [n];
    		   
    		   return *this;              //Return the local object for chaining
    		   }
    		

What goes on here?

Now in main, the line list1 = list2; will work fine.

Other operators that can be overloaded this way are: (), [], - > ,+ = , - = , * = , / = , & = , | = .

1.3  You do it

  1. Overload the += operator so that list1 = list2; appends list2 to the bottom of list1.

1.4  Overloading + and other binary operators

First we need the idea of a friend function.

If function Fn is declared to be a friend of class Z, then Fn will have automatic access to all the private data and functions of class Z.

A friend function must be declared in the class definition before the public and private members of the class.

To arrange for adding intLists, in the sense of appending one list to another:

  1. Add to the class definition before the public

    			friend intList operator+ (intList& left, intList& right);
    		

  2. Add to the list of functions in the class:

    			intList operator+ (intList& left, intList& right)
    			   {
    			   //First make a long list out of the contents of left and right.
    			   //  This involves allocating some memory for the purpose.
    			   
    			   int *array;
    			   
    			   array = new int [left.size + right.size];
    			   
    			   for (int n = 0; n < left.size; n++)
    			      array [n] = left.theList [n];
    			      
    			   for (int n = left.size; n < left.size + right.size; n++)
    			      array [n] = right.theList [n - left.size];
    			      
    			   //Then make a new intList from the long list.
    			   
    			   intList temp (array, left.size + right.size);
    			   
    			   //Clean up by returning the memory.
    			   
    			   delete []array;
    			   
    			   //Return the new intList as the sum of left and right.
    			   
    			   return temp;
    			   }
    		

Note:

  1. intList:: is not present in the definition of this function because the function is not a member of the intList class, or any other class for that matter.
  2. Usually left.size, right.size, left.theList, and right.theList would be inaccessible to a function that is not a member of the intList class. However, this function does have access to all of these because it has been declared a friend of the class.

Overloading of -, *, /, ^, &&, ||, &, |, ==, >, <, >=, <=, !=, and ^ can all be accomplished in the same way.

1.5  Overloading << and >> for input and output

cout << x; works just find if x is an int, but the computer doesn't know what to do if x is an intList. To make << and >> work for objects, these symbols must be overloaded with operator functions.

Again this must be done using friend functions. Here I overload << and >> for the intList class.

  1. Add friend prototypes to the intList class definition:

    			ostream& operator<< (ostream&, intList&);
    			istream& operator>> (istream&, intList&);
    		

    cout is an example of an ostream object. cin is an example of an istream object.

    So the way ostream& operator<< (ostream&, intList&); will work is the following:

    1. We give the operator<< function an ostream object (like cout) and an intList object as arguments.
    2. We accumulate the printing in the ostream object in the body of the function.
    3. Then we return the ostream object again so that ``chaining'' will work. cout << x << "George" << endl; is chaining.

    For the computer to know what ostream and istream mean, #include <iostream> must be included in the intList.h file.

  2. Add these functions to the intList.cpp file:

    			ostream& operator<< (ostream& out, intList& aList)
    			   {
    			   for (int n = 0; n < aList.size; n++)
    			      out << aList.theList [n] << endl;
    			   
    			   return out;
    			   }
    			
    			istream& operator>> (istream& in, intList& aList)
    			   {
    			   in >> aList.size;
    			   
    			   delete []aList.theList;
    			   
    			   aList.theList = new int [aList.size];
    			   
    			   for (int n = 0; n < aList.size; n++)
    			      in >> aList.theList [n];
    			   
    			   return in;
    			   }
    		

1.6  Overloading []

If list1 is an instance of the intList class, then it would be nice if the computer understood list1 [3] to be the number 3 int in list1. To make the computer understand, we must overload [] as an operator. Here is what works:

  1. Add in the public section of the class definition the following:

    			int& operator[] (int index);
    		

  2. Add to the functions file for the class:

    			int& intList::operator[] (int index)
    			   {
    			   return theList [index];
    			   }
    		

1.7  Putting it all together

Now here is the class definition file for the intList class:

#ifndef INTLIST_H
#define INTLIST_H

#include <iostream>

class intList
   {
   friend intList  operator+  (intList&, intList&);
   friend ostream& operator<< (ostream&, intList&);
   friend istream& operator>> (istream&, intList&);
   
   public:
      intList ();                               //Default constructor
      intList (int aList [], int howMany);     
      intList (intList&);                       //Copy constructor
      
      ~intList ();                              //Destructor
      
      intList& operator= (intList&);
      int&     operator[](int);
      
      void   inputNumbers ();
      void   print        ();
      double average      ();
      
   private:
      int *theList;                //Pointer to point to a dynamic array.     
      int size;                    //Size of the dynamic array.
   };

#endif

And here is the intList.cpp file with the function definitions:

#include <iostream>
#include <iomanip>

#include "intList.h"

const int MAXSIZE = 10000;

intList::intList ()          //Default constructor
   {
   size    = 0;
   theList = NULL;
   }
   
intList::intList (int aList [],    //Incoming list of numbers
                  int howMany)     //How many numbers are incoming
   {
   size = howMany;                 //Copy over the list size
   
   theList = new int [size];       //Create a dynamic array of the right 
                                   //   size.   theList points to the 0 
                                   //   slot of the array.
   
   for (int n = 0; n < size; n++)  //Copy the numbers over to the dynamic 
      theList [n] = aList [n];     //   array.
   }

intList::intList (intList& aList)        //The argument is an object of the 
                                         //  same type, to be copied.
   {
   size = aList.size;                    //Copy over the size of the list.
         
   theList = new int [size];            //Make an array of the proper size.
   
   for (int n = 0; n < size; n++)       //Copy over the numbers.
      theList [n] = aList.theList [n];
   }

intList::~intList ()         //Destructor
   {
   delete []theList;
   }

void intList::inputNumbers ()
   {
   cout << "Enter numbers.  Enter -1 to stop." << endl << endl;
   
   //Enter the numbers into a temporary array first.
   
   int size = 0;
   
   int tempList [MAXSIZE];
   
   cin >> tempList [size];
   
   while  (tempList [size] != -1)
      {
      size++;
      
      cin >> tempList [size];
      }
      
   //Then create a dynamic array of just the right size.
   
   theList = new int [size];
   
   //And copy the numbers into the dynamic array.
   
   for (int n = 0; n < size; n++)
      theList [n] = tempList [n];
   }
   
void intList::print ()
   {
   for (int n = 0; n < size; n++)
      cout << setw (10) << theList [n] << endl;
   }
   
double intList::average ()
   {
   int sum = 0;
   
   for (int n = 0; n < size; n++)
      sum += theList [n];
      
   return double (sum) / double (size);
   }
   
intList& intList::operator= (intList& aList)
  {
  delete []theList;
		   
  size = aList.size;         //Copy over the size of aList
		   
  theList = new int [size];  //Reallocate theList to the size of aList
		   
  for (int n = 0; n < size; n++)         //Copy over the numbers
	 theList [n] = aList.theList [n];
		   
  return *this;              //Return the local object for chaining
  }

int& intList::operator[] (int index)
   {
   return theList [index];
   }

intList operator+ (intList& left, intList& right)
   {
   //First make a long list out of the contents of left and right.
   //  This involves allocating some memory for the purpose.
			   
   int *array;
			   
   array = new int [left.size + right.size];
			   
   for (int n = 0; n < left.size; n++)
      array [n] = left.theList [n];
			      
   for (int n = left.size; n < left.size + right.size; n++)
      array [n] = right.theList [n - left.size];
			      
   //Then make a new intList from the long list.
			   
   intList temp (array, left.size + right.size);
			   
   //Clean up by returning the memory.
			   
   delete []array;
			   
   //Return the new intList as the sum of left and right.
			   
   return temp;
   }
   
ostream& operator<< (ostream& out, intList& aList)
   {
   //Print the entries in the list into the out object.
   
   for (int n = 0; n < aList.size; n++)
      out << aList.theList [n] << endl;
			   
   //Then return the out object to enable chaining.
    
   return out;
   }
			
istream& operator>> (istream& in, intList& aList)
   {
   //First pick up how many numbers will go in aList.
   
   in >> aList.size;
   
   //Then dump the memory already allocated  and reallocate memory.
   
   delete []aList.theList;
   
   aList.theList = new int [aList.size];
   
   //Finally, read in the numbers from in.
   
   for (int n = 0; n < aList.size; n++)
      in >> aList.theList [n];
			   
   //Then return in to enable chaining.
   
   return in;
   }

Now a main program might be:

#include <iostream>

#include "intList.h"

int main ()
   {
   int array [10] = {1,3,2,5,7,0,9,6,4,8};
   
   intList list1 (array, 10), list2, list3;
   
   cin >> list2;
   
   list3 = list1 + list2;
   
   cout << list3;
   
   cout << list1 << endl << endl << list2 << endl;
   
   cout << list3 [2] << endl;
   
   return 0;
   }


File translated from TEX by TTH, version 2.25.
On 7 Oct 2002, 18:18.