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