Operator Overloading in C++

Operator Overloading in C++

What is Operator Overloading?

There are two types of overloading possible in C++ i.e. Operator Overloading and Function Overloading. Operator Overloading enables us to make the standard operators, like +, -, * etc, to work with the objects of our own data types or classes. We can write a function which redefines a particular operator so that it performs a specific operation when it is used with the object of a class.

Operator overloading does not allow to make new operators or change the precedence of the operator. Almost all the operators in C++ can be overloaded, however here are some operators which can not be overloaded. For example

OperatorDescription
::The scope resolution operator
: ?The conditional operator
sizeofThe sizeof operator
.The direct member selection operator
.*The de-reference pointer to class member operator

There is no specific reason of not allowing the above operators to be overloaded. For example, Bjarne Stroustrup explains himself:

There is no fundamental reason to disallow overloading of ?:. I just didn’t see the need to introduce the special case of overloading a ternary operator.
Bjarne Stroustrup

Example of Operator Overloading

C++ allows you to overload operators. For example we can redefine the

>

operator so that, when it is used with the object of a class

ShoeBox

, it would return true if the first ShoeBox had the greater volume than the second ShoeBox object.

class ShoeBox
 public: . . .
 bool operator>(ShoeBox& aBox) const;
 //rest of the class definition
};

Here operator

>

id overloaded for

ShoeBox

. Now, below is the code that shows how we can compare two

ShoeBox

objects.

if (box1 > box2)
    cout << endl << "ShoeBox1 is greater than ShoeBox2";

And here is the code which actually implements the overloading process.

bool ShoeBox::operator>(const ShoeBox& aBox) const
{
 return this -> CalcVolume() > aBox.CalcVolume();
}

There are two things to understand here.

  1. We have given the reference parameter to the function to avoid unnecessary copying
  2. As the function does not alter any this so we can declare it as const.

This is not the  most efficient code however once you’ve succeed in implementing overloaded operators you can then concentrate on making things efficient.

Arithmetic Operators

Arithmetic operators include +=, -=, *=, /=, %= and their binary cousins +, -, *, / and % the Modulus Operator. The easiest way to implement these operators is to implement the arithmetic assignment operators as member functions, and then to implement the binary operators using the arithmetic assignment functions.

Binary Operators

Here we assume that all arithmetic assignment operators have been implemented, and discuss how to implement the binary arithmetic operators. We’ll use + as an example, assuming we’re implementing addition for a class BigInt, but the example applies to all the binary arithmetic operators for any class.

 BigInt operator + (const BigInt & lhs, const BigInt & rhs)
    // postcondition: returns lhs + rhs
    {
    BigInt copy(lhs);
    copy += rhs;
    return copy;
    }

The code here is straightfoward. A copy of the parameter lhs (left-hand-side) is made and the sum accumulated in this copy which is then returned. Assuming that += is implemented properly it’s possible to shorten the body of the function:

 BigInt operator + (const BigInt & lhs, const BigInt & rhs)
    // postcondition: returns lhs + rhs
    {
    BigInt copy(lhs);
    return copy += rhs;
    }

Arithmetic Assignment Operators

Again we’ll use operator += for a class BigInt as an examplar of the syntax and semantics for overloading arithmetic assignment operators.

   const BigInt& BigInt::operator += (const BigInt & rhs)
   // postcondition: rhs has been added to *this,
   //                *this returned

Using this prototype the code below compiles:

BigInt a = Factorial(25); BigInt b = Factorial(30); a += b; BigInt c = (b += b);

Note that operator += returns a value (a constant reference) that is assigned to c. This isn’t typical, but it’s legal C++ for the built-in arithmetic operators, so it should be legal for overloaded arithmetic operators.

Overloaded operators should have the same semantics as their built-in counterparts.

Return Value

A reference is returned since there is no reason to make a copy. A const reference is returned so that the returned value is not an lvalue, i.e., so that it cannot be assigned to:

   BigInt a = Factorial(25);
   BigInt b = Factorial(30);

   (a += b) = b;              // this is NOT legal C++ !!!

The exssion (a += b) is not an lvalue since the value returned is a const BigInt&; the const modifier is the essential piece of venting the return value from being an lvalue.

The exssion returned from an overloaded arithmetic operator should be *this, the value of the object being operated on:

   const BigInt& BigInt::operator += (const BigInt & rhs)
   // postcondition: rhs has been added to *this,
   //                *this returned
   {
        // code here

        return *this;
   }

Special Cases

Sometimes, often for efficiency (but make it right before making it fast), arithmetic operators are overloaded more than once for a given class. For example, the class BigInt has the following overloaded member functions and free functions.

    // member functions

    const BigInt & operator *= (const BigInt &);
    const BigInt & operator *= (int num);

    // free functions

    BigInt operator *(const BigInt & lhs, const BigInt & rhs);
    BigInt operator *(const BigInt & lhs, int num);
    BigInt operator *(int num, const BigInt & rhs);

Here it’s possible to evaluate b * 5 for a BigInt b variable, without converting the 5 to an anonymous variable. This may be done for efficiency or because the specialized versions of operator += and operator + are used in implementing the non-specialized versions. Note that for symmetry operator + is overloaded twice for adding BigInt and int values.

Relational Operators

Implementing the boolean relational operators <, >, <=, >=, ==, and != requires a technique similar to how binary arithmetic operators are implemented. This is because we want to be able to write the code below (all three comparison expressions involving <):

   BigInt x;
   // code giving x a value

   if (x < y)   // do something

   if (x < 128) // do something

   if (1024 < x) // do something

For reasons similar to those outlined above, the creation of anonymous variables for either left- or right-hand sides of a relational expression (e.g., involving < or ==) requires that these operators
not be member functions.

Although relational operators can be implemented as friend functions, there is an easy method for implementing them that is similar to the method using arithmetic assignment operators such as += to implement the corresponding relational operator, in this case +, that avoids declaring any friend functions.

For example, consider a class Date for representing calendar dates, e.g., January 23, 1999. Determining if two dates are equal, or if one comes before another, can be done simply if == and < (and the other relational operators) are overloaded for Date objects. The approach I use is illustrated by the partial declaration of the Date class showing as follows:

Note that constructors and other member functions are elided.

   class Date
   {
      public:

        // operators: arithmetic and relational (partial list)

        const Date& operator +=(long dx);   // add dx, e.g., jan 1 + 31 = feb 1
        const Date& operator -=(long dx);   // subtract dx, e.g., jan 1 - 1 = dec 31

        bool equal(const Date & rhs) const; // returns true iff == rhs
        bool less(const Date & rhs) const;  // returns true iff < rhs

      private:

   };

Here the functions equal and less are used to determine if one Date is equal to or less than another, respectively. These functions are implemented in order to facilitate overloading the relational operators although these functions can be useful in debuggers. The code below shows equal in use.

    Date a(1,1,1998), b(12,31, 1997);
    if (a.equal(b+1)) // just checking

Using functions equal and less is how relational functions are used in Java, so using this approach in C++ also eases a transition to Java. Once the functions are implemented, implementing the overloaded relational operators is straightforward. Again, for the class Date we have:

bool operator == (const Date & lhs, const Date & rhs)
{
    return lhs.equal(rhs);
}

bool operator != (const Date & lhs, const Date & rhs)
{
    return ! (lhs == rhs);
}

bool operator < (const Date & lhs, const Date & rhs)
{
    return lhs.less(rhs);
}

bool operator >  (const Date & lhs, const Date & rhs)
{
    return rhs < lhs;
}

bool operator <= (const Date & lhs, const Date & rhs)
{
    return ! (lhs > rhs);
}

bool operator >= (const Date & lhs, const Date & rhs)
{
    return rhs < = lhs;
}

In these examples only == and < use the member functions equal and less directly, the other overloaded operators are implemented in terms of == and <. However, it’s clearly possible to use equal and less only for implementing all the overloaded operators.

When using the STL (Standard Template Library) the header file is typically included. Templated function declarations in this file implement all relational operators in terms of < and == so typically only these operators are overloaded for classes that are used in environments in which STL is available. For example, part of the SGI implementation of the header file function.h is shown below:

template <class T>
inline bool operator!=(const T& x, const T& y) {
    return !(x == y);
}

template <class T>
inline bool operator>(const T& x, const T& y) {
    return y < x;
}

What this means is that if you use STL, you typically will overload only operator < and operator ==; by including the header file , you’ll include templated functions that will implement the other relational operators in terms of < and ==.

M. Saqib: Saqib is Master-level Senior Software Engineer with over 14 years of experience in designing and developing large-scale software and web applications. He has more than eight years experience of leading software development teams. Saqib provides consultancy to develop software systems and web services for Fortune 500 companies. He has hands-on experience in C/C++ Java, JavaScript, PHP and .NET Technologies. Saqib owns and write contents on mycplus.com since 2004.
Related Post