Home/Blog/Programming/Various ways of overloading an operator in C++
Home/Blog/Programming/Various ways of overloading an operator in C++

Various ways of overloading an operator in C++

16 min read
Jan 09, 2024

Become a Software Engineer in Months, Not Years

From your first line of code, to your first day on the job — Educative has you covered. Join 2M+ developers learning in-demand programming skills.

A binary operator can have various calling combinations. Let’s say we want to create a Point class that has the facility of the following additions: Point + Point, Point + int, and int + Point. C++ allows an operator to be overloaded as a class member and as a non-member of the class. Different aspects should be considered when overloading the operators in C++.

Let’s dive right in!

We’ll cover:


Introduction#

In C++, we can overload an operator in different ways. We use a simple example of the Point class to represent a point in the Cartesian plane. It has only two data members of the int type to represent the value of xx and yy (in a two-dimensional surface). We also define a constructor that receives two parameters of the int type to initialize both data members. We have a method, show, to display the object’s current value. We keep extending the code to illustrate and explain the concepts as we move on, adding various forms of overloading the + operator for this class and any support elements.

Certainly, C++ knows how to perform the + operation on the data types defined by the language itself, i.e., all primitive data types. However, it does not know how to perform the + operation on a data type defined here (the user-defined or abstract data type). Therefore, we need to write the steps of that operation in the form of an overloaded version.

Some operators cannot be overloaded as non-members, e.g., assignment, subscript, and function call operators. Their caller (the first operand or the left-hand-side) cannot be anything other than an object of the same class.


Overloading based on calling#

The definition of the operator should have the functionality of adding the corresponding values of two axes of two points. It should also have the ability to add an integer value to both axes. Therefore, it has three possible combinations of operator calls.

Possibilities of overloaded versions for an operator
Possibilities of overloaded versions for an operator


Class and class#

The first possibility of calling the + operator that comes to mind is the ability to add two objects of the same class. In this case, we want to add the corresponding data members of both objects into a new object. If a, b, and c are of type int, then c = a + b; does not modify a and b. It stores their sum to c. Similarly, we need to protect the values of operands and return the sum to be stored in another object. If these three variables are the objects of type Point, then we need c.x = a.x + b.x; and c.y = a.y + b.y;.

An operator can be overloaded as a member of the class when the operands are objects of the same class.

Let’s see the complete code for this task.

#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point (int a, int b): x(a), y(b) {}
void show() const { cout << "(" << x << "," << y << ") ";}
Point operator+ (const Point &rhs) const {
return Point(x + rhs.x , y + rhs.y);
}
};
int main() {
Point p(1,2), q(3,5);
p.show();
q.show();
// The overloaded operator works for Point + Point
Point r = p + q;
r.show();
// The overloaded operator cannot work for the following
// Point s = p + 6;
// Point t = 7 + p;
return 0;
}

Focusing on the overloaded operator in the above code, the first operand (caller object) p is received as *this, and the second operand q is received as the parameter rhs.

  • Lines 10–12: We overload the + operator for the Point class. The operator+ function takes a constant reference to another Point object (rhs) and returns a new Point object whose x coordinate is the sum of the x coordinates of the two points, and the y coordinate is the sum of the y coordinates of the two points.

  • Lines 21–22: We use the overloaded + operator to add points p and q, creating a new Point object r. The coordinates of r are (1 + 3, 2 + 5) = (4, 7). The result is displayed using the show member function.

  • Lines 25–26: These lines are commented out to demonstrate that the overloaded + operator does not work for adding a Point object and an integer, or an integer and a Point object, due to the way the operator is defined within the class.

Data Structures Preliminaries (Refresher of Fundamentals in C++)

Cover
Data Structures Preliminaries (Refresher of Fundamentals in C++)

Dive into a comprehensive review of the fundamental elements of C++ through this course. Experience concise yet detailed explanations, coupled with hands-on exercises that delve into the core concepts of C++ fundamentals. Your journey begins with the exploration of fundamental programming concepts, such as the versatility of variables and their applications in strengthening control structures like conditions, loops, arrays and pointers. Next, you’ll cover structured programming, understanding its advantages and disadvantages, which seamlessly transitions you into object-oriented programming (OOP). Your focus will expand to encompass subjects like classes, object relationships and the implementation of operator overloading to equip user-defined data types. By the end of this course, you'll possess a solid grasp of the essential fundamentals, providing a robust foundation for success in subsequent courses, including the study of data structures and algorithms in C++.

30hrs
Beginner
151 Playgrounds
3 Quizzes


Class and integer#

We can invoke the + operator for c = a + b where a is the object of type Point and b is a value of type int. This call cannot invoke the above-defined version because we have defined it for Point + Point but not for Point + int. So we need to define a new version where we want to add the value of b to both data members of a and return the result as a new object of type Point.

An operator can be overloaded as a member of the class when the first operand is an object of the same class.

Let’s see the complete code for this task.

#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point (int a, int b): x(a), y(b) {}
void show() const { cout << "(" << x << "," << y << ") ";}
Point operator+ (const int &rhs) const {
return Point(x + rhs , y + rhs);
}
};
int main() {
Point p(1,2);
p.show();
// The overloaded operator works for Point + int
Point s = p + 6;
s.show();
// The overloaded operator cannot work for the following
// Point r = p + q;
// Point t = 7 + p;
return 0;
}

Focusing on the overloaded operator in the above code, the first operand (caller object) p is received as *this, and the second operand 6 is received as the parameter rhs.

  • Lines 10–12: We define the operator+ method. This is an overloaded operator method for addition (+). It takes a single argument, which is a constant reference to an integer (rhs for the right-hand side). It returns a new Point object where the x and y coordinates are increased by the value of rhs.

  • Lines 20–21: We use the overloaded + operator to add the integer value 6 to the p object, creating a new Point object s. Then, we call the show method for s to display its coordinates.

  • Lines 24–25: The code in these lines, marked as comments, attempts to use the overloaded + operator in situations where it’s not defined. The + operator can work for adding an integer to a Point object (p + 6), but it cannot work for adding two Point objects together (p + q) or adding a Point object to an integer (7 + p).


Integer and class#

The user of our class can also invoke c = a + b where a is of type int and b is an object of type Point. Again, this call cannot invoke both of the above-defined versions because we define it for Point + Point and Point + int, but not for int + Point. The sequence of data types also matters in case of function overloading in C++. So, we need to define a new version where we want to code the same functionality for a different sequence.

An operator must be overloaded as a non-member when the first operand is not an object of the class.

This version of the + operator cannot be overloaded as a member of the class because every member function receives the caller object as *this of the same class type. Therefore, we overload this version as a non-member. Let’s see the complete code for this task.

#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point (int a, int b): x(a), y(b) {}
void show() const { cout << "(" << x << "," << y << ") ";}
friend Point operator+ (const int &lhs, const Point &rhs);
};
Point operator+ (const int &lhs, const Point &rhs) {
return Point(lhs + rhs.x , lhs + rhs.y);
}
int main() {
Point p(1,2);
p.show();
// The overloaded operator works for int + Point
Point t = 7 + p;
t.show();
// The overloaded operator cannot work for the following
// Point r = p + q;
// Point s = p + 6;
return 0;
}

In the above code:

  • Line 10: We declare a friend function operator+ inside the Point class. This is an overloaded operator method for addition (+). It takes an integer (lhs for the left-hand side) and a constant reference to a Point object (rhs for the right-hand side) as arguments. Declaring it as a friend function allows it to access the private members of the Point class.

  • Lines 13–15: We define the operator+ function outside the class. It takes an integer lhs and a constant reference to a Point object rhs. Inside the function, it creates and returns a new Point object where the x coordinate is the sum of lhs and rhs.x, and the y coordinate is the sum of lhs and rhs.y.

  • Lines 22–23: We use the overloaded + operator to add the integer value 7 to the p object, creating a new Point object t. Then, we call the show method for t to display its coordinates.

  • Lines 26–27: The code in these lines, marked as comments, attempts to use the overloaded + operator in situations where it’s not defined. The + operator can work for adding an integer to a Point object (7 + p), but it cannot work for adding two Point objects together (p + q) or adding an integer to a Point object in this form (p + 6).

C++ Programming for Experienced Engineers

Cover
C++ Programming for Experienced Engineers

If you’re looking to sharpen up your C++ programming skills, then you’re in the right place. You will start with learning about dynamic memory allocation, how to create classes, and constructors. In the latter half of the course, inheritance, functions, I/O, exception handling, and more. Throughout the course, you will study over 90 carefully designed examples aimed to enhance your understanding of the C++ language. By the time you finish this course, you will be able to use more advanced functionality in your C++ programs.

11hrs
Intermediate
12 Challenges
2 Quizzes


The power of the type-cast constructor#

A type-cast constructor receives one parameter of any type (other than its own class) to create an object. We define a type-cast constructor in the Point class to convert an int into a Point. In the same way, we can define a type-cast constructor in Point to convert the object of any other class into Point.

The use of a type-cast constructor with single-member implementation as a member can work for Point + Point and Point + int, but not for int + Point. For implicit invocation of the type-cast constructor for the first operand, the function has to be defined as a non-member.

#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point (int a, int b): x(a), y(b) {}
Point (int v): x(v), y(v) {}
void show() const { cout << "(" << x << "," << y << ") ";}
Point operator+ (const Point &rhs) {
return Point(x + rhs.x , y + rhs.y);
}
};
int main() {
Point p(1,2), q(3,5);
p.show();
q.show();
// The overloaded operator works for both of the following
Point r = p + q;
r.show();
Point s = p + 6;
s.show();
// The overloaded operator cannot work for int + Point
// Point t = 7 + p;
return 0;
}

In the above code:

  • Line 8: We define another constructor that takes a single integer argument v. This constructor initializes both x and y with the value of v. This constructor acts as a type-cast constructor and allows for creating a Point object with a single integer value.

  • Lines 11–13: We define the operator+ method. This is an overloaded operator method for addition (+). It takes a single argument, which is a constant reference to another Point object (rhs for right-hand side). It returns a new Point object where the x coordinate is the sum of x of the current object and x of the rhs object, and the y coordinate is the sum of y of the current object and y of the rhs object.

  • Lines 22–23: We use the overloaded + operator to add the p and q objects together, creating a new Point object r. Then, we call the show method for r to display its coordinates.

  • Lines 25–26: We use the overloaded + operator to add an integer value 6 to the p object, creating a new Point object s. The integer value creates a new temporary object with the help of the type-cast constructor and calls the overloaded + operator receiving two Point objects. Then, we call the show method for the resulting object s to display its coordinates.

  • Line 29: The code in this line, marked as a comment, attempts to use the overloaded + operator in a situation where it’s not defined (int + Point). The + operator works for adding a Point object and another Point object (p + q) or adding a Point object and an integer (p + 6), but it cannot work for adding an integer and a Point object in this form (7 + p).

We don’t need to declare a non-member function as friend if we define getter and setter methods for the relevant attributes.


Overloading as a non-member#

All of the above versions of overloading an operator in C++ can be implemented as non-member functions. In this case, there are no *this implicitly available (unlike the member functions) implementations shown in previous sections.

We have to explicitly declare two parameters as per the sequence of operands in the expression used for the operator call. Let’s look at the non-member implementations for three combinations of the same operator.

We use cout in the overloaded operator functions to understand the calling sequence. However, it is not recommended otherwise.

#include <iostream>
using namespace std;
class Point {
int x, y;
public:
Point (int a, int b): x(a), y(b) {}
void show() const { cout << "(" << x << "," << y << ") " << endl;}
int get_x() const {return x;}
int get_y() const {return y;}
};
Point operator+ (const Point &lhs, const Point &rhs) {
cout << "P+P "; // The use of cout is not recommended here. This message is only to indicate its call for the reader.
return Point(lhs.get_x() + rhs.get_x() , lhs.get_y() + rhs.get_y());
}
Point operator+ (const Point &lhs, const int &rhs) {
cout << "P+i "; // The use of cout is not recommended here. This message is only to indicate its call for the reader.
return Point(lhs.get_x() + rhs , lhs.get_y() + rhs);
}
Point operator+ (const int &lhs, const Point &rhs) {
cout << "i+P "; // The use of cout is not recommended here. This message is only to indicate its call for the reader.
return Point(lhs + rhs.get_x() , lhs + rhs.get_y());
}
int main() {
Point p(1,2), q(3,5);
p.show();
q.show();
Point r = p + q; // Calls operator+ (Point)
r.show();
Point s = p + 6; // Calls operator+ (int)
s.show();
Point t = 7 + p; // Calls operator+ (int, Point)
t.show();
return 0;
}

In the above code, we implement the operator as a non-member function.

  • Line 8: In this code, we define the show method with a new line. It is a public member function of the Point class and is responsible for displaying the current Point object’s coordinates in the format “(x, y)” followed by a new line.

  • Lines 9–10: We define the get_x and get_y methods to eliminate the need for friend. They are public member functions of the Point class and return the values of x and y, respectively.

  • Lines 13–26: We define three overloaded operator+ functions. These functions allow addition operations between Point objects and integers. The first function (lines 13–16) performs Point + Point objects, the second (lines 18–21) performs Point + int, and the third (lines 23–26) performs int + Point. Each function also adds special messages on the screen: P+P, P+i, and i+P from the first, second, and third implementations, respectively. The result of these additions is a new Point object with updated coordinates.

  • Lines 33–34: We use the overloaded + operator to add the p and q objects together, creating a new Point object r. This call displays P+P. Then, we call the show method for r to display its coordinates.

  • Lines 36–37: We use the overloaded + operator to add an integer value 6 to the p object, creating a new Point object s. This call displays P+i. Then, we call the show method for s to display its coordinates.

  • Lines 39–40: We use the overloaded + operator to add the p object to the integer value 7, creating a new Point object t. This call displays i+P. Then, we call the show method for t to display its coordinates.

Become a C++ Programmer

Cover
Become a C++ Programmer

C++ is a popular language used to develop browsers, games, and operating systems. It's also an essential tool in the development of modern technology like IoT and self-driving cars. This Path will expand your knowledge of C++ with lessons built for professional developers. This Path will take you from basic to advanced concepts with hands-on practice. By the end, you'll have enough C++ experience to confidently solve real-world problems.

119hrs
Beginner
82 Challenges
152 Quizzes


Two distinct classes#

When both operands are objects but of two different classes, we should make it a member of the class of the first operand. Since the first operand is the caller, its type should be the same as *this. However, we can also implement it as a non-member for both classes. Let’s see the complete code for overloading it as two different non-member functions to be called on the basis of the sequence of operands.

#include <iostream>
using namespace std;
class Point; // It is required by the Dummy class
class Dummy {
int d;
public:
Dummy(int i):d(i){}
friend Point operator+ (const Point &lhs, const Dummy &rhs);
friend Point operator+ (const Dummy &lhs, const Point &rhs);
};
class Point {
int x, y;
public:
Point (int a, int b): x(a), y(b) {}
void show() const { cout << "(" << x << "," << y << ") ";}
friend Point operator+ (const Point &lhs, const Dummy &rhs);
friend Point operator+ (const Dummy &lhs, const Point &rhs);
};
Point operator+ (const Point &lhs, const Dummy &rhs) {
return Point(lhs.x + rhs.d , lhs.y + rhs.d);
}
Point operator+ (const Dummy &lhs, const Point &rhs) {
return Point(lhs.d + rhs.x , lhs.d + rhs.y);
}
int main() {
Point p(1,2);
Dummy u1(10), u2(20);
Point v = p + u1;
v.show();
Point w = u2 + p;
w.show();
return 0;
}

In the above code:

  • Line 4: The declaration of the Point class before the Dummy class is required for lines 9 and 10.

  • Lines 5–11: We define another class Dummy with a private integer data member d. It has a constructor that initializes d with the provided integer argument. The purpose of this class is only to demonstrate the addition of two different classes. Practically, it behaves as adding an integer to the Point object. Since the non-member implementations of the + operator use the private member d, both of them are declared as friend in this class (lines 9–10).

  • Lines 19–20: We declare both implementations of the + operator as friend of class Point so that they can access the private members x and y without being the members of the same class.

  • Lines 23–29: We define two operator+ functions that allow addition operations between the Point and Dummy objects.

  • Line 33: We create two Dummy objects, u1 and u2, and initialize them with values 10 and 20, respectively.

  • Line 35: We use the overloaded + operator to add the Dummy object u1 to the Point object p, creating a new Point object v.

  • Line 37: We use the overloaded + operator to add the Dummy object u2 to the Point object p, creating a new Point object w.


One overload for all calls#

Single non-member implementation of operator overloading can serve the purpose of all three combinations of operator calls. However, it requires a type-cast constructor to be defined in the class. It works by implicitly converting the type of non-class variable to an object. We demonstrate this calling sequence with the help of additional messages display.

Using a type-cast constructor with a single non-member implementation can work for all three combinations of operator calls.

The instantiation of p and q
The instantiation of p and q
1 of 7

The above diagram explains the involvement of the type-cast constructor in the operator call.

Let’s look at the complete code given below.

We use cout and show in the constructors to understand the calling sequence. However, it is not recommended otherwise.

#include <iostream>
using namespace std;
class Dummy {
int d;
public:
Dummy(int i):d(i){}
int get() const {return d;}
};
class Point {
int x, y;
public:
Point (int a, int b): x(a), y(b) {
cout<<" P(x,y)";
show();
}
Point (int v): x(v), y(v) {
cout<<" P(i)";
show();
}
Point (const Dummy & obj): x(obj.get()), y(obj.get()) {
cout<<" P(D)";
show();
}
void show() const {
cout << "(" << x << "," << y << ") ";
}
int get_x() const {return x;}
int get_y() const {return y;}
};
Point operator+ (const Point &lhs, const Point &rhs) {
return Point(lhs.get_x() + rhs.get_x() , lhs.get_y() + rhs.get_y());
}
int main() {
int i = 50;
Dummy d = 60;
Point p(1,2);
cout << endl;
Point q = p + d;
cout << endl;
Point r = p + i;
cout << endl;
Point s = i + p;
cout << endl;
Point t = d + p;
cout << endl;
return 0;
}

In the above code:

  • Lines 4–9: We define the Dummy class with a private integer data member d. It has a constructor that initializes d with the provided integer argument and a member function get to retrieve the value of d. This new method eliminates the need for a friend declaration.

  • Lines 11–31: We define the Point class with private integer data members x and y. It has multiple constructors: One that takes two integers (line 14), another that takes a single integer (line 18), and one that takes a Dummy object (line 22). The constructors initialize the Point object’s coordinates and display a message indicating the type of constructor used. The class also has member functions show, get_x, and get_y to display both coordinates, to retrieve the value of the x coordinate, and to retrieve the value of the y coordinate, respectively.

    The use of getter methods, get_x and get_y, eliminates the need for a friend declaration. It is a safer way of implementing through a non-member function.

  • Lines 33–35: We overload the + operator for adding Point objects. It takes two Point objects as parameters and returns a new Point object with coordinates being the sum of corresponding coordinates of the two input Point objects.

Inside int main():

  • Line 38: We declare an integer variable i and initialize it with the value 50.

  • Line 39: We declare a Dummy object d and initialize it with the value 60.

  • Lines 41–42: We create a Point object p using the constructor that takes two integers (1 and 2) and displays them from the parameterized constructor (line 14). It outputs P(x,y) to indicate a call to the constructor. We print a new line afterward.

  • Line 44: We use the overloaded + operator to perform Point + Dummy through p + d. We display the resulting Point object q from the constructor used for q. The P(D) in the output indicates that the type-cast constructor for Dummy to Point conversion is called.

  • Line 47: The overloaded + operator is used to perform Point + int through p + i. We display the resulting Point object r from the constructor used for r. The P(i) in the output indicates that the type-cast constructor for int to Point conversion is called.

  • Line 50: We use the overloaded + operator to perform int + Point through i + p. We display the resulting Point object s from the constructor used for s. The P(i) in the output indicates that the type-cast constructor for int to Point conversion is called.

  • Line 53: We use the overloaded + operator to perform Dummy + Point through d + p. We display the resulting Point object t from the constructor used for t. The P(D) in the output indicates that the type-cast constructor for Dummy to Point conversion is called.

Zero to Hero in C++

Cover
Become a C++ Programmer

C++ is a robust and flexible language commonly used for games, desktop, and embedded applications development. This Skill Path is perfect for beginners eager to learn C++ and embark on a programming journey. You’ll explore C++ fundamentals, starting with basic syntax and functionality to create programs, and then dive into more complex concepts like dynamic memory allocation in C++. The latter half focuses on C++ programming with a detailed overview of object-oriented programming (OOP), which includes classes in C++, data hiding in C++, encapsulation in C++, abstraction in C++, inheritance in C++, and polymorphism in C++. Hands-on practice with algorithms and data structures will empower you to write real-world programs confidently, paving your way as a C++ developer.

38hrs
Beginner
32 Challenges
46 Quizzes


Wrapping up and next steps#

Operators can be overloaded as non-members and members of the class. It depends on the caller object whether we can define an operator as a class member or not. If the caller object is not an object of the class, we cannot define it as a member function; otherwise, we can implement it in both ways. If we overload an operator as a non-member for both operands to be the objects of the class, then providing the type-cast constructor in the class can empower that operator to work for all combinations of operator calls.

Some operators cannot be overloaded as non-members, e.g., subscript and function call operators.

Keep exploring, keep coding, and happy learning!


To start learning these concepts and more, check out Educative’s Data Structures Preliminaries (Refresher of Fundamentals in C++) course.

Continue learning to code#


 
Join 2.5 million developers at
Explore the catalog

Free Resources