Operator Overloading
Contents
5.1. Operator Overloading#
We have studied function overloading, where we can define multiple functions with the same name but different parameter lists. Depending on the arguments used in a function call, the appropriate function is selected.
Similarly, C++ allows us to overload operators, such as +
, =
, ==
and <<
. This means that we can define how operators such as +
behave when they are used with objects of user-defined types (i.e., classes). This is known as operator overloading.
Why Overload Operators?
Operator overloading can make code more intuitive and easier to read. For example, consider a Complex
class that represents complex numbers with real and imaginary values. By overloading the +
operator, we can add two Complex
objects using the familiar +
syntax.
We will explore how to overload various operators within the context of the Complex
class defined as follows:
Starting Point: The Complex
Class
class Complex {
private:
double real;
double img;
public:
Complex() {
real = 0; img = 0;
}
Complex(double r, double i) {
real = r; img = i;
}
};
5.1.1. Overloading the +
Operator#
We want to add two Complex
objects using the +
operator as we show in the following code snippet:
1Complex x(3.0, 4.0);
2Complex y(5.0, 6.0);
3Complex z;
4
5z = x + y; // We want to add two Complex objects using the + operator
Currently, the +
operator can add two integers or doubles, e.g. 2.0 + i
, where i
is an integer. Additionally, those who implemented the string
class in C++ implemented the +
operator to enable two strings to be “added” and produce a new string object with two strings concatenated, e.g. string s = "Hello" + " world"
.
Similarly, we need to implement or overload the +
operator to add two Complex
objects, i.e. we need to define what x + y
means when x
and y
are Complex
objects.
Step 1: Understand the function header
In the expression x + y;
, the left-hand side of the +
operator is the object of class Complex
. This means we can interpret the x + y
to be equivalent to x.operator+(y)
. The function name is operator+
. It should be a member function of Complex
class, since we invoke operator+
on x
. The object y
is passed as an argument to this member function.

Fig. 5.1 x + y
is interpreted as x.operator+(y)
. The left-hand side of the +
operator is the object x
, on which operator+
of the Complex
class is invoked. The right-hand side of the +
operator is the object y
, which is passed as an argument to the operator+
member function.#
To implement the operator+
member function, we need to consider the following:
Input Argument Type: The
operator+
member function should take one parameter of typeComplex
, which is the object on the right-hand side of the+
operator. Since the left-hand side object is the one on which the member function is invoked, it does not need to be passed as a parameter.Return Type: The
operator+
member function should return a newly createdComplex
object that represents the sum of the twoComplex
objects.Public or Private: The
operator+
member function should be declared as apublic
member function of theComplex
class to allow it to be accessed from outside the class.
Step 2: Implement the operator+
Member Function
We can implement the operator+
member function as follows:

Fig. 5.2 We create a new Complex
object temp
to store the sum of the two Complex
objects. We add the real and imaginary parts separately and return the temp
object.#
We pass the Complex
object y
as a parameter to the operator+
member function and name it rhs
, short for right-hand side.
We can access the real
and img
data members of the left-hand side object x
(the object on which operator+
is invoked) directly using real
and img
since we are inside a member function of the Complex
class. We access the real
and img
data members of the right-hand side object rhs
using the dot operator, e.g. rhs.real
and rhs.img
.
Inside the function, we create a new Complex
object temp
to store the sum of the two Complex
objects. We set the real of temp
to the sum of the real
of y
(rhs.real
) and the real of the left-hand side object x
, which is just real
since operator+
is invoked on x
. We do the same for the imaginary part.
Finally, we return the temp
object. The return type of operator+
is Complex
, which matches the type of the object we are returning.
Return by value
operator+
returns a Complex
object by value. This means that a copy of the temp
object is returned to the caller. Returning by value is important because the scope of temp
will end by the end of the function and it will be destroyed. We want to return a newly created Complex
object that is a copy of temp
object at the time of return to by used in the caller function, e.g. main
function.
Step 3: Optimizations on the operator+
Member Function
We can make three main optimizations to the operator+
member function:
Pass the parameter by reference: Passing the
Complex
objectrhs
by value creates a copy ofrhs
just for theoperator+
function. This can be memory inefficient especially ifComplex
has many data members. Instead, we can pass it by reference to avoid making a copy of the object when the function is called. This means we change the parameter type fromComplex rhs
toComplex& rhs
.Pass
rhs
as aconst
: We can ensure that the function does not modify therhs
object. This is important becauserhs
is the right-hand side object of the+
operator, and we do not want to change its value when performing addition. To do this, we can declare the parameter as aconst
reference, i.e.const Complex& rhs
.Make the function
const
: We can declare theoperator+
member function as aconst
member function to indicate that it does not modify the state of the left-hand side object. This is done by adding theconst
keyword after the function parameter list, i.e.Complex operator+(const Complex& rhs) const
.

5.1.2. Overloading the ==
Operator#
Before getting to the operator=
or assignment operator, another common operator to overload is the equality operator ==
. We can use this operator to compare two Complex
objects for equality. For example, we want to be able to write the following code:
#include <iostream> using namespace std;
class Complex { private: double real; double img; public: Complex() { real = 0; img = 0; } Complex(double r, double i) { real = r; img = i; } // Overload the + operator Complex operator+(Complex rhs) { Complex temp; temp.real = real + rhs.real; // Add the real parts temp.img = img + rhs.img; return temp; } // Overload the == operator bool operator==(const Complex& rhs) const { return (real == rhs.real) && (img == rhs.img); } }; int main(void) { Complex x(3.0, 4.0); Complex y(3.0, 4.0); if (x == y) { cout << "x is equal to y" << endl; } else { cout << "x is not equal to y" << endl; } return 0; }
We can overload the ==
operator to compare two Complex
objects for equality. The ==
operator should return true
if both the real and imaginary parts of the two Complex
objects are equal, and false
otherwise.
In line 24, we write the function header for the operator==
member function. The left-hand side object is the one on which the member function is invoked, and the right-hand side object is passed as a const
reference parameter. The return type of the function is bool
, which indicates whether the two Complex
objects are equal or not.
The function is declared as a const
member function since it does not modify the state of the left-hand side object. It also receives the right-hand side object as a const
reference to avoid making a copy and to ensure that it is not modified.
In line 25, we compare the real
and img
data members of the left-hand side object and the right-hand side object rhs.real
and rhs.img
using the ==
operator for double
values. If both parts are equal, we return true
; otherwise, we return false
.
We use the overloaded ==
operator in line 32 to compare the two Complex
objects x
and y
. Since both objects have the same real and imaginary parts, the output will be x is equal to y
.
5.1.3. Overloading the =
Operator#
In the previous example, we used two operators: +
and =
in z = x + y;
, where z
, x
and y
are Complex
objects. We successfully overloaded the +
operator to add two Complex
objects. This returns a a new Complex
object (let’s call it temp
). Then, the assignment operator =
is used to assign the value of temp
to the object z
.
It’s time to overload the assignment operator =
: operator=
. The good news is C++ provides a default assignment operator operator=
for classes. It performs a member-wise assignment of data members from the right-hand side object to the left-hand side object. This means the data members of temp
are copied to the corresponding data members of z
.
Let’s implement the default assignment operator for the Complex
class to understand how it works.
Step 1: Understand the function header
In the expression z = temp;
,
We can interpret the
z = temp
to be equivalent toz.operator=(temp)
.The function name is
operator=
.It should be a member function of
Complex
class, since we invokeoperator=
onz
.The object
temp
is passed as an argument to this member function of typeComplex
.
The function name and parameter type are written as follows:
<<return-type>> operator=(Complex rhs);
In C/C++, the assignment operator =
must return something that allows for chained assignments, e.g. z = y = x;
. This statement is evaluated right to left, i.e. y = x
x
is assigned to y
, then in z = y
y
is assigned to z
. In C/C++ standard, we should return from operator=
the original left-hand side object after the assignment. Therefore, the assignment operator =
must return a reference to the left-hand side object to allow for this chaining, which is of Complex
class type. We add the &
symbol to indicate that we are returning a reference.

Fig. 5.3 In chained assignments like z = y = x;
, the expression y = x
is evaluated first, and the result, which is the original y
, is then assigned to z
. To enable this chaining, the assignment operator =
must return a reference to the left-hand side object, or the object on which we invoked the operator=
member function.#
Putting it all together, the function header for the assignment operator =
is as follows:
Complex& operator=(Complex rhs);
Step 2: Implement the operator=
Member Function
We can implement the operator=
member function by setting the data members of the left-hand side object to the corresponding data members of the right-hand side object rhs
, i.e. real = rhs.real
and img = rhs.img
.
How can we get the reference to the left-hand side object? One way is to use the this
pointer. The this
pointer points to the object on which the member function is invoked. Therefore, in z.operator=(temp)
, this
points to the object z
. We can dereference the this
pointer using *this
to get the left-hand side object itself. this
is of type Complex*
, so *this
is of type Complex
. To return a reference to the left-hand side object, we use return *this;
.
We can visualize each object and the this
pointer as follows:

Fig. 5.4 The this
pointer points to the object on which we invoke the function on, e.g. object z
. We can dereference the this
pointer using *this
to get the left-hand side object itself.#
Below is the complete implementation of the operator=
member function:

Fig. 5.5 We copy the real
and img
data members from the right-hand side object rhs
to the left-hand side object using the dot operator. Finally, we return a reference to the left-hand side object using *this
.#
In the image above, we optimize the operator=
member function by passing the right-hand side object rhs
as a const
reference to avoid making a copy and to ensure that it is not modified.
We didn’t make the operator=
member function a const
member function because it modifies the state of the left-hand side object.