8.2 Overloading Basic Operators


 

A simple example to introduce operator overloading is a safe array of integers. The array is to be safe in the sense that the subscripting operation will ensure that the subscript is within bounds. If the subscript is out of bounds, the program will terminate. The declaration of the safe array is defined as shown in the figure below.


Safe Array with Operator Overloading
class Array 
{
  private:
      int array[20];
  public:
         Array(int init = 0);
    int& operator[](int i);   // overloaded subscript operator
        ~Array();
};

In this case, the subscripting operator, referred to as "operator[]," is defined to take a single integer input argument. The subscripting operator returns a reference to the subscripted element of the array after checking that such an element exists in the array. This class is intended to be used as follows:

  Array array;

   array[0] = 1;
   array[1] = 1;
   for (int i = 2; i < 20; i++)         // compute first twenty Fibonnaci numbers
       array[i] = array[i-1] + array[i-2];

The compiler, upon encountering the expression "array[0]," will check to see if the class of array (in this case Array) contains a class-specific definition for the [] operator. Because the Array class contains such an overloaded operator method, the compiler will arrange for code to be generated that is the equivalent of

       array.operator[](0)

which matches the definition of the method given in the Array class. Similarly, the statement

      array[i] = array[i-1] + array[i-2];

would be treated as:

       array.operator[](i) = array.operator[](i-1) + array.operator[](i-2);

Since the overloaded subscript operator returns a reference (specifically an int&), it is legitimate to have the subscript operator appear in an expression on the left-hand side of the assignment operator.

Notice that aside from its declaration, the Array object looks and feels like a built-in array type. This similarity is also suggested by the following code which shows Arrays and built-in arrays being intermixed:

  Array safe;
   int   regular[20];

    // define contents of arrays safe and unsafe

    regular[10] = safe[10];
    safe[11]    = regular[11];
    safe[0]     = safe[0] + regular[0]

The built-in array type and the Array act the same, except that the Array will cause a clean and informative error message when a subscript out-of-bounds problem arises, while the built-in array will silently permit the erroneous access and the resulting corruption of data lying adjacent to the built-in array in memory.

The operator[] method would be implemented as shown in the next figure. Again, notice that there is nothing special about the operator[] method, except that its name must be exactly as written in the figure to communicate to the compiler that this method is, in fact, to be treated as an overloading of the built-in [] operator for objects of the Array class.


Implementing an Overloaded Operator
int& Array::operator[](int i) 
{
   assert(0 <= i && i < 20);
   return array[i];
}

  

Two safe arrays may be added or subtracted by overloading the addition (+) operator and the subtraction (-) operators. The interface of the Array class would then be changed as shown below.


Overloading Other Operators in the Safe Array
class Array
{  private:
      int array[20];
   public:
             Array(int v=0);
      int&   operator[](int i);        // subscript   operator
      Array operator+(Array& other);   // addition    operator
      Array operator-(Array& other);   // subtraction operator
            ~Array();
};

  
   

Notice that the addition and subtraction operators return a reference to an Array object that holds the result of their operations. The two Array objects being added are not changed: instead a new Array object is created and returned by reference.

The Array addition operator allows the following usages:

    Array a,b;         // initialized to 0
     Array one(1);      // initialized to 1

     // give values to arrays a and b

     Array c = a + b;
     Array d = a - b + one;

     

The first of these two assignment statements produces an array, each of whose elements is the sum of the corresponding elements in the two arrays a and b. The second assignment shows that the overloaded addition and substraction operators for the Array class may be used in more complicated expressions.

The compiler will, upon encountering the expression a + b determine if there is a class-specific overloading of the addition operator. Since a and b are objects of the Array class, and this class contains an operator+ method with matching argument types, the compiler will generate code that is the equivalent of

       a.operator+(b)

where the object on the left-hand side of the addition in the expression "a +"b (a) plays the role of the called object and the object on the right hand side (b) plays the role of the argument value. Similarly, the statement

       d = a - b + one

will be compiled into code that is equivalent to

       Array& anonymous = a.operator-(b);
        d = anonymous.operator+(one);

where "anonymous" is used to refer to the object created dynamically by the subtraction operator.

The use of the default assignment operator in the Array class is sufficient. The default assignment operator simply performs a bit-level copy from the source to the target object. In this case, assignments such as

       Array f, g;

        // assign values to g

        f = g;

will work as intended: the data in Array g will be copied to the data in Array f.

The implementation of the Array addition and subtraction operators is as illustrated below. Each operation allocates a new Array object that it will return by copy as its result. Notice that the assignment statement in each method uses a combination of built-in and overloaded subscripting operators. The term array[i] uses the built-in meaning for subscripting because "array" is an array of the base type int. The terms other[i] and result[i] use the meaning of subscripting defined in the Array class, because each of them are objects of the Array class.



Implementing the Array Addition Operator Overloadings
Array Array::operator+(Array& other) 
{  Array result;

   for(int i=0; i<20; i++)
     result[i] = array[i] + other[i];

   return result;
}


Array Array::operator-(Array& other) 
{  Array result;

   for(int i=0; i<20; i++)
     result[i] = array[i] - other[i];

   return result;

}



A member function that redefines an operator can itself be overloaded. The terminology for this can be confusing because the term operator overloading refers to methods that redefine the built-in operators while the term overloading refers to methods that have the same name but different signatures. To illustrate this difference, another + operator will be defined for the Array class. This new + operator will allow a value to be added to each element of the Array; its partial class definition and implementation is shown in the figure below.


Overloading the + Operator in the Array Class
class Array
{  private:
      int array[20];
   public:
     ...
     Array operator+(Array& other);   // addition operator
     Array operator+(int increment);  // add increment to all
     ...
};
// in implementation
Array Array::operator+(int increment) 
{ Array result;

   for(int i = 0; i< 20; i++) 
      result[i] = array[i] + increment;

   return result;
}

Using both of the overloaded addition operators together allows the following code to be written:

    Array one(1);            // all elements are 1
     Array two = one + 1;     // add 1 to each element 
     Array three = one + two; // pairwise addition of Arrays one and two

The first assignment statement uses the overloading of the + operator that has an int as its argument. This line is equivalent to the code

    Array two = one.operator+(1);

The second assignment statement uses the overloading of the plus operator that has an Array object as its argument. This line is equivalent to the code

   Array three = one.operator+(two);

Of course, other overloadings of the addition operator can be added as required by the needs of the application.

  1. Array Multiplication Operator: Extend the Array class to include an operator that allows each element of the array to be multiplied by a given constant. For example:

           Array  a;
    					

    Array& b = a*6; // multiple each element by 6

  2. Extend the Array class to include a test for an equality operator that returns 1 if all elements of the two Array objects are the same, and 0 otherwise. For example:

           Array  a;
    					

    Array b;

    // give values to a and b

    if ( a == b) {// uses equality operator

    // code for when they are equal

    }

  3. Extend the Array class to include a test for inequality by overloading the predefined operator "!=".
  4. Extend the Array class to include a test for "<" between two Array objects. One Array object is "<" another if each element of the first Array object is strictly less than the corresponding element of the second Array object.

  5. Extend the Array class to include another overloading of its equality operator. This additional overloading would be used to test whether each element in the array is equal to a given integer value. An example of the use of this operator is:

        Array a;
    					

    //...give values to a

    if (a == 0)

    { // all elements of a are zero

    }

  6. Define a class Association that maintains an association between up to 100 pairs of integer values. The first element of each pair is the subscript and the second element is the value. Association class should be usable as illustrated in this code:

       Assocation pairs;
    					

    pairs[10] = 20; // record the pair (10, 20)

    pairs[1000] = 0; // record the pair (1000, 0)

    ...

    int p = pairs[10]; // returns 20

    int q = pairs[1]; // returns 0 if no pair

  7. Define another class Association that maintains an association between up to 100 (string, integer) pairs. The character string element of each pair is the subscript and the integer element is the value. Association class should be usable as in this code:

       Assocation pairs;
    					

    pairs["oranges"] = 20; // record the pair ("oranges", 20)

    pairs["apples"] = 0; // record the pair ("apples" , 0)

    ...

    int p = pairs["oranges"]; // returns 20

    int q = pairs["pears"]; // returns 0 if no pair with this string

 




©1998 Prentice-Hall, Inc.
A Simon & Schuster Company
Upper Saddle River, New Jersey 07458

Legal Statement