Operator Overloading

Same operator, different operation

Restrictions

Operator Functions as Friends

For example,
// Overloaded output operator
ostream &operator<<(ostream &output, const Date &d)
{
   static char *monthName[13] = {"", "January",
      "February", "March", "April", "May", "June",
      "July", "August", "September", "October",
      "November", "December"};

   output << monthName[d.month] << ' '
          << d.day << ", " << d.year;

   return output;   // enables concatenation
}

Overloading Unary Operators

// Preincrement operator overloaded as a member function.
Date Date::operator++()
{
   helpIncrement();
   return *this;  // value return; not a reference return
}

// Postincrement operator overloaded as a member function.
// Note that the dummy integer parameter does not have a
// parameter name.
Date Date::operator++(int)
{
   Date temp = *this;
   helpIncrement();

   // return non-incremented, saved, temporary object
   return temp;   // value return; not a reference return
}

Note: A unary operator can be overloaded as

  1. a non-static member function with no arguments
         class String {
         public:
            bool operator!() const;
            ...
         };
    
    or
    
  2. a non-member function with one argument.
         class String {
         public:
            friend bool operator!( const String & );
            ...
         };
    

Overloading Binary Operators

// Add a specific number of days to a date
const Date &Date::operator+=(int additionalDays)
{
   for (int i = 1; i <= additionalDays; i++)
      helpIncrement();

   return *this;    // enables concatenation
}

Case Study: An Array Class

#include <iostream.h>
#include "array1.h"

main()
{
   Array integers1(7), integers2;

   cin >> integers1 >> integers2;

   // use overloaded inequality (!=) operator
   cout << "Evaluating: integers1 != integers2" << endl;
   if (integers1 != integers2)
      cout << "They are not equal" << endl;

   // test copy constructor
   // create array integers3 using integers1 as an initializer
   Array integers3(integers1);

   // use overloaded assignment (=) operator
   integers1 = integers2;

   // use overloaded equality (==) operator
   cout << "Evaluating: integers1 == integers2" << endl;
   if (integers1 == integers2)
      cout << "They are equal" << endl << endl;

   // use overloaded subscript operator to create rvalue
   cout << "integers1[5] is " << integers1[5] << endl;

   // use overloaded subscript operator to create lvalue
   integers1[5] = 1000;
   cout << "integers1: " << integers1 << endl;

   // attempt to use out of range subscript
   cout << "Attempt to assign 1000 to integers1[15]" << endl;
   integers1[15] = 1000;  // ERROR: out of range

   return 0;
}
implementation for class Array

Case Study: A String Class

#include <iostream.h>
#include "string1.h"

main()
{
   String s1("happy"), s2(" birthday"), s3;

   // test overloaded equality and relational operators
   cout << "s2 == s1 yields " << (s2 == s1) << endl
        << "s2 <= s1 yields " << (s2 <= s1) << endl << endl;

   // test overloaded String empty (!) operator
   cout << "Testing !s3:" << endl;
   if (!s3) {
      cout << "s3 is empty; assigning s1 to s3;" << endl;
      s3 = s1;              // test overloaded assignment
   }

   // test overloaded String concatenation operator
   cout << "s1 += s2 yields s1 = ";
   s1 += s2;                // test overloaded concatenation
   cout << s1 << endl << endl;

   // test conversion constructor
   cout << "s1 += \" to you\" yields" << endl;
   s1 += " to you";         // test conversion constructor
   cout << "s1 = " << s1 << endl << endl;

   // test overloaded function call operator () for substring
   cout << "The substring of s1 starting at" << endl
        << "location 0 for 14 characters, s1(0, 14), is: "
        << s1(0, 14) << endl << endl;

   // test substring "to-end-of-String" option
   cout << "The substring of s1 starting at" << endl
        << "location 15, s1(15, 0), is: "
        << s1(15, 0) << endl << endl;  // 0 is "to end of string"

   // test copy constructor
   String *s4Ptr = new String(s1);  
   cout << "*s4Ptr = " << *s4Ptr << endl << endl;

   // test assignment (=) operator with self-assignment
   cout << "assigning *s4Ptr to *s4Ptr" << endl;
   *s4Ptr = *s4Ptr;          // test overloaded assignment
   cout << "*s4Ptr = " << *s4Ptr << endl;

   // test destructor
   delete s4Ptr;     

   // test using subscript operator to create lvalue
   s1[0] = 'H';      
   s1[6] = 'B';
   cout << endl << "s1 after s1[0] = 'H' and s1[6] = 'B' is: "
        << s1 << endl << endl;

   // test subscript out of range
   cout << "Attempt to assign 'd' to s1[30] yields:" << endl;
   s1[30] = 'd';     // ERROR: subscript out of range

   return 0;
}
implementation for class String

Case Study: A Date Class

#include <iostream.h>
#include "date1.h"

main()
{
   Date d1, d2(12, 27, 1992), d3(0, 99, 8045);

   cout << "d2 += 7 is " << (d2 += 7) << endl << endl;

   d3.setDate(2, 28, 1992);
   cout << "  d3 is " << d3 << endl;
   cout << "++d3 is " << ++d3 << endl << endl;

   Date d4(3, 18, 1969);

   cout << "Testing the preincrement operator:" << endl
	<< "  d4 is " << d4 << endl;
   cout << "++d4 is " << ++d4 << endl;
   cout << "  d4 is " << d4 << endl << endl;

   cout << "Testing the postincrement operator:" << endl
	<< "  d4 is " << d4 << endl;
   cout << "d4++ is " << d4++ << endl;
   cout << "  d4 is " << d4 << endl;

   return 0;
}
implementation for class Date

Copy Constructor

Copy constructors are invoked whenever a copy of an object is needed such as
  1. in call-by-value
  2. when initializing an object to be a copy of another object of the same class
    	Date date1=date2;
    
  3. when returning an object from a called function
    	return someObject;
    
Note that, in the copy constructor
   String( const String & );
the argument must use call-by-reference.

Notes: