Article by Ayman Alheraki on January 11 2026 10:34 AM
Operator overloading is a powerful feature in C++ that allows programmers to define new behaviors for traditional operators like +, -, *, and == when used with their custom objects. In object-oriented programming (OOP), this is a fundamental concept that increases the scalability of code and makes it more natural and intuitive when dealing with complex data types.
For instance, if you have an object representing a complex number, by default, you can't use the + operator to add two complex number objects. This is where operator overloading comes in, allowing you to define the behavior of addition for your objects.
Operator overloading is important because it:
Improves code readability.
Allows for writing logical and easily understood expressions.
Makes it easier to handle objects as if they were primitive types.
In C++, the following operators can be overloaded:
Arithmetic operators: +, -, *, /, %, ++, --.
Comparison operators: ==, !=, <, >, <=, >=.
Logical operators: &&, ||, !.
Input/output operators: <<, >>.
Assignment operators: =, +=, -=, *=, /=, etc.
Some operators cannot be overloaded, such as the dot operator (.) and the scope resolution operator (::).
Operator overloading is defined using the keyword operator followed by the operator you want to overload. You can define the overload either as a member function of the class or as a friend function if it requires access to private or protected members.
Step 1: Defining the Complex Class
using namespace std;
class Complex {private: float real; float imag;
public: // Constructor Complex(float r = 0.0, float i = 0.0) : real(r), imag(i) {}
// Overloading the + operator Complex operator + (const Complex& obj) { Complex temp; temp.real = real + obj.real; temp.imag = imag + obj.imag; return temp; }
// Display function to print complex number void display() { cout << real << " + " << imag << "i" << endl; }};Explanation:
Here, we define a class named Complex that represents a complex number.
The class contains two float variables: real and imag to represent the real and imaginary parts of the complex number.
The + operator is overloaded to take another Complex object and add the real and imaginary parts.
The function returns a new Complex object containing the result.
Step 2: Using the Overloaded Operator
int main() { Complex c1(3.4, 2.3); Complex c2(1.2, 3.7);
Complex c3 = c1 + c2; // Using overloaded + operator
cout << "Result of addition: "; c3.display(); // Output: 4.6 + 6.0i
return 0;}Explanation:
In the main function, we create two Complex objects c1 and c2 and then add them using the overloaded + operator.
The operator + function is called, and a new Complex object representing the result is returned. The result is then displayed using the display function.
The + operator is used to add two objects. The following example shows how to overload the + operator to add two Complex objects:
class Complex {private: float real, imag;public: Complex(float r = 0.0, float i = 0.0) : real(r), imag(i) {}
// Overload + operator to add two Complex objects Complex operator + (const Complex& obj) { return Complex(real + obj.real, imag + obj.imag); }};The - operator works similarly to addition, subtracting the real and imaginary parts of two objects:
Complex operator - (const Complex& obj) { return Complex(real - obj.real, imag - obj.imag);}Here we multiply two complex numbers using the following rule:
(a + bi) * (c + di) = (ac - bd) + (ad + bc)icppCopy codeComplex operator * (const Complex& obj) { return Complex((real * obj.real) - (imag * obj.imag), (real * obj.imag) + (imag * obj.real));}To divide two complex numbers, we use the following mathematical formula:
(a + bi) / (c + di) = [(a*c + b*d) / (c^2 + d^2)] + [(b*c - a*d) / (c^2 + d^2)]icppCopy codeComplex operator / (const Complex& obj) { float denominator = obj.real * obj.real + obj.imag * obj.imag; return Complex((real * obj.real + imag * obj.imag) / denominator, (imag * obj.real - real * obj.imag) / denominator);}The modulus operator % usually cannot be overloaded for complex types but can be overloaded for custom classes dealing with integers only. For example:
class Integer {private: int value;public: Integer(int v = 0) : value(v) {}
Integer operator % (const Integer& obj) { return Integer(value % obj.value); }};The ++ operator can be overloaded in two ways: prefix and postfix increment.
Prefix Increment
omplex& operator ++ () { ++real; ++imag; return *this; }Postfix Increment It is defined using a dummy argument to indicate the postfix form:
Complex operator ++ (int) { Complex temp = *this; real++; imag++; return temp; }It behaves the same way as the ++ operator but decreases the value:
Complex& operator -- () { --real; --imag; return *this; }This operator is used to check whether two objects are equal:
bool operator == (const Complex& obj) { return (real == obj.real && imag == obj.imag);}This can be overloaded using the direct opposite of the equality operator:
bool operator != (const Complex& obj) { return !(*this == obj);}It can be overloaded to compare based on a specific criterion. For complex numbers, we may compare their magnitudes:
bool operator < (const Complex& obj) { return (real * real + imag * imag) < (obj.real * obj.real + obj.imag * obj.imag);}Other comparison operators can be defined based on appropriate arithmetic operations:
bool operator <= (const Complex& obj) { return !(*this > obj);}
bool operator > (const Complex& obj) { return (real * real + imag * imag) > (obj.real * obj.real + obj.imag * obj.imag);}
bool operator >= (const Complex& obj) { return !(*this < obj);}We can overload it to check logical conditions for two objects:
bool operator && (const Complex& obj) { return (real != 0 && imag != 0) && (obj.real != 0 && obj.imag != 0);}bool operator || (const Complex& obj) { return (real != 0 || imag != 0) || (obj.real != 0 || obj.imag != 0);}bool operator ! () { return real == 0 && imag == 0;}This operator is overloaded to allow cout to print objects of the Complex type:
friend ostream& operator << (ostream& out, const Complex& obj) { out << obj.real << " + " << obj.imag << "i"; return out;}This is overloaded to allow direct input of values into objects using cin:
friend istream& operator >> (istream& in, Complex& obj) { cout << "Enter real part: "; in >> obj.real; cout << "Enter imaginary part: "; in >> obj.imag; return in;}This allows copying values from one object to another:
Complex& operator = (const Complex& obj) { if (this != &obj) { real = obj.real; imag = obj.imag; } return *this;}This can be overloaded to access values within the object based on an index:
float& operator [] (int index) { if (index == 0) return real; if (index == 1) return imag; throw out_of_range("Index out of range");}It can be overloaded to convert an object into a primitive value. For example, if we want to access the value directly:
Complex& operator *() { return *this;}It is used to access members of an object via a pointer:
Complex* operator ->() { return this;}The feature of operator overloading in C++ provides great flexibility, allowing you to work with objects naturally as if they were primitive types. This helps make the code clearer, easier to understand, and more maintainable.