Table of contents
1.
Introduction
2.
Syntax of operator overloading
3.
Rules for operator overloading in C++
3.1.
1. Only Existing Operators Can Be Overloaded
3.2.
2. At Least One Operand Must Be of a User-Defined Type
3.3.
3. Maintain the Original Meaning of Operators
3.4.
4. Unary Operators Overloaded as Member Functions
3.5.
5. Binary Operators Overloaded as Member Functions
4.
Types of Operators That Can Be Overloaded in C++
4.1.
1. Arithmetic Operators
4.2.
2. Comparison Operators
4.3.
3. Assignment Operator (=)
4.4.
4. Unary Operators
4.5.
5. Subscript Operator ([])
4.6.
6. Stream Insertion (<<) and Extraction (>>)
4.7.
7. Function Call Operator (())
4.8.
8. Bitwise Operators
5.
Operator Overloading in Unary Operators
5.1.
Implementation
6.
Operator Overloading in binary Operators
6.1.
Implementation
7.
Difference between Operator Functions and Normal Functions
8.
Can We Overload All Operators in C++?
8.1.
Operators That Can Be Overloaded
8.1.1.
Example of Overloading the + Operator:
9.
Why Some Operators Cannot Be Overloaded?
10.
C++ Operators that can not be Overloaded
10.1.
Scope resolution operator(::)
10.2.
Ternary operator(?:)
10.3.
Member selector(.)
10.4.
Sizeof operator
10.5.
Member pointer selector(*)
11.
Frequently asked questions
11.1.
Why is it called operator overloading?
11.2.
What is operator overloading and its rules?
11.3.
What is meant by overloading?
12.
Conclusion
Last Updated: Jan 2, 2025
Medium

Operators Overloading in C++

Author Shivam Verma
3 upvotes
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Operator overloading provides us a flexible option for the creation of new definitions for most C++ operators. In C++, we can make an operator work for user-defined classes. In simple words, C++ has the ability to provide the operators with special meaning for a data type. This mechanism of giving such special meaning to an operator is known as operator overloading. Operator overloading is a compile-time polymorphism. The main advantage of using operator overloading is to perform different operations on the same operand.

Operators Overloading

Syntax of operator overloading

return_type class_name operator symbol(arg_list)
{
    function body // body of the function 
}

In the above syntax, 

  • The return_type is the return type of the function.
     
  • Next, the class_name is the name of the class.
     
  • The operator is a keyword. 
     
  • The symbol is preceded by the keyword operator, and the operator symbol is the function name. Operator functions can be member functions or friend functions.
     
  • arg_list is the arguments passed by the function.


Also see, Literals in C.Fibonacci Series in C++

Rules for operator overloading in C++

Operator overloading in C++ is a powerful feature that allows you to redefine the way operators work with user-defined types. While implementing operator overloading, it is crucial to follow specific rules to ensure proper functionality. Below are the key rules to remember:

1. Only Existing Operators Can Be Overloaded

You can overload only the operators that already exist in C++. You cannot create new operators.

2. At Least One Operand Must Be of a User-Defined Type

When overloading an operator, at least one of the operands must be a user-defined datatype. This ensures that the operator is specifically designed for the custom class. 

3. Maintain the Original Meaning of Operators

You should never change the basic functionality or meaning of an operator when overloading it. For example, the + operator should still perform addition, even when overloading it for a custom class.

4. Unary Operators Overloaded as Member Functions

If you overload unary operators using a member function, they should not take any explicit arguments. However, if overloaded via a friend function, they should take one argument.

5. Binary Operators Overloaded as Member Functions

For binary operators overloaded using a member function, they should take one explicit argument. On the other hand, if overloaded via a friend function, they will require two arguments.

Types of Operators That Can Be Overloaded in C++

Operator overloading in C++ allows you to define custom behavior for existing operators when working with user-defined types. Not all operators can be overloaded, but here are the key ones that can:

1. Arithmetic Operators

These include operators like +, -, *, /, and %, which can be overloaded to perform arithmetic operations on custom objects like complex numbers or matrices.

Example:

Complex operator + (const Complex& obj) {
    return Complex(real + obj.real, imag + obj.imag);
}

2. Comparison Operators

Operators like ==, !=, >, <, >=, and <= can be overloaded to compare objects of custom types.

Example:

bool operator == (const Complex& obj) {
    return (real == obj.real && imag == obj.imag);
}

3. Assignment Operator (=)

The assignment operator is overloaded to handle deep copying of objects, especially for classes with dynamic memory allocation.

Example:

Complex& operator = (const Complex& obj) {
    real = obj.real;
    imag = obj.imag;
    return *this;
}

4. Unary Operators

Unary operators like ++, --, and - can be overloaded to modify the state of an object.

Example:

Counter& operator++() {
    ++value;
    return *this;
}

5. Subscript Operator ([])

The [] operator can be overloaded to access elements in custom container classes.

Example:

int& operator[](int index) {
    return arr[index];
}

6. Stream Insertion (<<) and Extraction (>>)

Overloading << and >> allows you to define how objects are printed or read using streams.

Example:

friend std::ostream& operator<<(std::ostream& os, const Complex& obj) {
    os << obj.real << "+" << obj.imag << "i";
    return os;
}

7. Function Call Operator (())

This operator can be overloaded to make objects callable, turning them into function objects.

Example:

int operator() (int num) {
    return value + num;
}

8. Bitwise Operators

Bitwise operators like &, |, ^, <<, and >> can be overloaded for operations involving bit-level manipulation.

Example:

BitwiseExample operator&(const BitwiseExample& obj) {
    return BitwiseExample(value & obj.value);
}

Operator Overloading in Unary Operators

Unary operators operate on only one operand. The unary operator's examples are increment operator -- and decrement operator ++.

Implementation

#include<bits/stdc++.h>
using namespace std;
class A
{
    private:
    int x,y;
    public:
    A() {}
    void setdata(int a,int b)
    {
        x=a;
        y=b;
    }
    void operator ++() {
        x=++x;
        y=y+2;
    }
    void operator --()
    {
        x=--x;
        y=y-2;
    }
    void print()
    {
        cout<<x<<" "<<y<<endl;
    }
};
int main()
{
    A op;
    op.setdata(10,15);
    ++op;
    cout << "Incremented numbers are "<<endl;
    op.print();
    --op;
    cout << "Decremented numbers are "<<endl;
    op.print();
    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output 

Incremented numbers are 
11 17
Decremented numbers are 
10 15

Here, In the above code, when we use ++op, the void operator ++() is called. This increases the 'x' attribute for the object op by one and the 'y' attribute for the object op by 2. when we use --op, the void operator --() is called. This decreases the 'x' attribute for the object op by one and the 'y' attribute for the object op by 2.

Try and compile with online c++ compiler.

Operator Overloading in binary Operators

Binary operators operate on two operands. Let’s understand the operator overloading in the binary operators by the code.

Implementation

#include <bits/stdc++.h>
using namespace std;
class Complex
{
   private:
    int re;
    int im;
   public:
    Complex(){}
    void setdata(int x,int y)
    {
      re=x;
      im=y;
    }
    // Overload the + operator
    Complex operator+(const Complex& obj){
        Complex temp;
        temp.re=re+obj.re;
        temp.im=im+obj.im;
        return temp;
    }
    void print()
    {
        if (im<0)
            cout<<re<<im<<"i"<<endl;
        else
            cout<<re<<"+"<<im<<"i"<<endl;
    }
};
int main()
{
    Complex comp1,comp2,res;
    cout<<"The first complex number is"<<endl;
    comp1.setdata(10,5);
    comp1.print();
    cout<<"The second complex number is"<<endl;
    comp2.setdata(12,7);
    comp2.print();
   // comp1 calls the operator function
   // comp2 is passed as an argument to the function
    res=comp1+comp2;
    cout<<"The sum of the complex number is"<<endl;
    res.print();
    return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output 

The first complex number is
10+5i
The second complex number is
12+7i
The sum of the complex number is
22+12i

 

Check out this article - Compile Time Polymorphism

Difference between Operator Functions and Normal Functions

Operator functions and normal functions share similar characteristics, but they differ in specific usage and implementation. Operator functions are designed to redefine the behavior of operators for user-defined types, while normal functions handle general functionality.

  • Name: The name of an operator function always begins with the operator keyword followed by the operator symbol (e.g., operator+). Normal functions have user-defined names.
     
  • Usage: Operator functions are invoked implicitly when their associated operator is used in expressions, whereas normal functions are called explicitly by their names.
     
  • Purpose: Operator functions enable operator overloading, allowing operators like +, -, or == to work with objects. Normal functions are used for general-purpose operations.
     
#include <iostream>
using namespace std;
class Number {
private:
   int realPart, imaginaryPart;
public:
   Number(int real = 0, int imag = 0) {
       realPart = real;
       imaginaryPart = imag;
   }
   void display() {
       cout << realPart << " + i" << imaginaryPart << endl;
   }
   friend Number operator+(Number const& num1, Number const& num2);
};
Number operator+(Number const& num1, Number const& num2) {
   return Number(num1.realPart + num2.realPart, num1.imaginaryPart + num2.imaginaryPart);
}
int main() {
   Number n1(10, 5), n2(2, 4);
   Number n3 = n1 + n2;
   n3.display();
   return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output

12 + i9

Can We Overload All Operators in C++?

In C++, operator overloading allows you to define custom behaviors for operators when applied to user-defined objects. However, not all operators can be overloaded. Some operators are inherently tied to the language’s structure and are restricted from being overloaded to maintain clarity and prevent confusion.

Operators That Can Be Overloaded

You can overload most of the operators in C++, including arithmetic operators (+, -, *, /), comparison operators (==, !=, <, >), and logical operators (&&, ||). These operators can be redefined to work with your custom classes, making them behave like built-in types.

For example, you can overload the + operator to add two objects of a class, or the << operator to print objects using cout.

Example of Overloading the + Operator:

#include<iostream>
using namespace std;
class Vector {
public:
   int x, y;
   Vector(int a = 0, int b = 0) : x(a), y(b) {}
   Vector operator+(const Vector &v) {
       return Vector(x + v.x, y + v.y);
   }
   void display() {
       cout << "Vector(" << x << ", " << y << ")" << endl;
   }
};
int main() {
   Vector v1(3, 4), v2(1, 2);
   Vector v3 = v1 + v2;
   v3.display();
   return 0;
}
You can also try this code with Online C++ Compiler
Run Code

 

Output

Vector(4, 6)

Why Some Operators Cannot Be Overloaded?

C++ restricts overloading certain operators to preserve the language’s simplicity and integrity. Overloading these operators could lead to ambiguities and inconsistent behavior, which would make the language more difficult to understand and use. For example, overloading the scope resolution operator might interfere with the way the compiler resolves variable scopes.

C++ Operators that can not be Overloaded

Some C++ operators can't be overloaded as follows.

Scope resolution operator(::)

The scope resolution operator is used to define the scope of a function or variable. It is used to access global variables, functions, or class members from outside the class. Since the scope resolution operator helps determine the scope, it cannot be overloaded because its function is fundamentally linked to how the C++ compiler resolves variable and function names.

Ternary operator(?:)

The ternary operator is a conditional operator used to make decisions in a single line of code. It operates in the form of condition ? expr1 : expr2. Due to its role in evaluating conditional expressions directly, it cannot be overloaded because it operates at the level of fundamental language constructs rather than user-defined objects.

Member selector(.)

The member selector (dot) operator is used to access members (variables or methods) of an object. Since the dot operator is closely tied to the object’s structure and is directly related to the instance of a class, it cannot be overloaded. This ensures that member access remains straightforward and efficient.

Sizeof operator

The sizeof operator is used to find the size (in bytes) of a data type or object. Since it is evaluated at compile time and directly relates to the size of a type or expression, overloading it is not allowed. This prevents potential confusion or complexity, as the operator’s behavior is predefined by the language.

Member pointer selector(*)

The member pointer selector operator (*) is used to point to a class member. It allows accessing members of an object through a pointer. Overloading this operator would complicate the access to member pointers and would interfere with its essential behavior in C++.

Frequently asked questions

Why is it called operator overloading?

It's called operator overloading because operators like +, -, etc., can behave differently based on the context of operands, allowing custom behaviors in programming languages.

What is operator overloading and its rules?

Operator overloading allows operators to perform different computations based on the operands' types. Rules include maintaining operator arity and type compatibility for meaningful operations.

What is meant by overloading?

Overloading refers to defining multiple functions or methods with the same name but different parameters or types, enabling different behaviors based on how they are called or used.

Conclusion

We learned about the syntax and the rules of operator overloading in this blog. This blog also discussed the operator overloading in unary and binary operators with the help of the program.

Recommended Reading:

Four Pillars of OOPS

Live masterclass