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.
To make = work properly for the intList class, we must:
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?
Other operators that can be overloaded this way are: (), [], - > ,+ = , - = , * = , / = , & = , | = .
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:
friend intList operator+ (intList& left, intList& right);
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:
Overloading of -, *, /, ^, &&, ||, &, |, ==, >, <, >=, <=, !=, and ^ can all be accomplished in the same way.
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.
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:
For the computer to know what ostream and istream mean, #include <iostream> must be included in the intList.h 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;
}
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:
int& operator[] (int index);
int& intList::operator[] (int index)
{
return theList [index];
}
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;
}