Operator in C++ like +, -, *, / can operate in data-types like int, float, double, etc as predefined operational meanings. But these operators can't operate in user-defined data-types like objects. Such way of extending the operational functionality of certain operators in C++ is called operator overloading.
Syntax:
return-type(operator)(symbol of operator) (arguments)
{
// body of code
}
Following is the list of independent overloadable operators:
Operator Name | Operator Symbol |
---|---|
Addition | + |
Subtraction | - |
Multiplication | * |
Division | / |
Modulus (remainder) | % |
Increment | ++ |
Decrement | -- |
Assignment | = |
Equality | == |
Inequality | != |
Greater than | > |
Less than | < |
Greater than or equal to | >= |
Less than or equal to | <= |
Logical NOT | ! |
Logical AND | && |
Logical OR | || |
Bitwise NOT | ~ |
Bitwise AND | & |
Bitwise OR | | |
Bitwise XOR | ^ |
Bitwise Left Shift | << |
Bitwise Right Shift | >> |
Function call | () |
Array subscript | [] |
Member selection | . |
Member pointer selection | -> |
Comma | , |
There are two types of operator overloading in C++:
1. Overloading Unary Operators:
Unary operators operate on a single operand. They can be overloaded as member functions or non-member functions. When overloading unary operators as member functions, no additional argument is required. Here's an example of pre-increment and post-increment operators as unary operators:
#include <iostream>
using namespace std;
class Counter
{
private:
int count;
public:
Counter(int initialCount = 0)
{
count = initialCount;
}
// Pre-increment operator (++counter)
Counter& operator++()
{
count++;
return *this;
}
// Post-increment operator (counter++)
Counter operator++(int)
{
Counter temp(count);
count++;
return temp;
}
int getCount()
{
return count;
}
};
int main()
{
Counter c1(5);
// Pre-increment
++c1;
cout << "Pre-increment: " << c1.getCount() << endl; // Output: 6
// Post-increment
Counter c2 = c1++;
cout << "Post-increment: " << c1.getCount() << endl; // Output: 7
cout << "Post-increment (returned value): " << c2.getCount() << endl; // Output: 6
return 0;
}
The pre-increment operator (`++c1`) is overloaded as a member function of the `Counter` class. It increments the `count` member variable directly and returns a reference to the updated object. This allows us to increment the counter and obtain the updated value in a single statement.
The post-increment operator (`c1++`) is also overloaded as a member function. However, it takes an additional dummy integer parameter (int) to differentiate it from the pre-increment operator. Inside the post-increment operator, a temporary `Counter` object (`temp`) is created with the current `count` value. Then, the `count` member variable is incremented. Finally, the temporary object is returned by value, representing the counter value before the increment operation.
2. Overloading Binary Operators:
Binary operators operate on two operands. They can be overloaded as member functions or non-member functions.
Overloading as Member Function:
When overloading binary operators as member functions, the left operand must be class object, and the right operand is provided as a parameter. Here's an example of overloading the addition (`+`) operator:
class Point
{
private:
int x, y;
public:
Point(int xVal, int yVal)
{
x = xVal;
y = yVal;
}
Point operator+(const Point& other)
{
return Point(x + other.x, y + other.y);
}
};
int main()
{
Point p1(2, 3);
Point p2(4, 5);
Point p3 = p1 + p2;
// p3.x is 6, p3.y is 8
return 0;
}
In the example above, the addition operator is overloaded as a member function of the `Point` class. It performs element-wise addition of the `x` and `y` coordinates of two `Point` objects and returns a new `Point` object.
Overloading as Non-member Function:
Member functions cannot be defined, if left operand of operation is not class object for example: (2 + object). Therefore, non-member functions can be used for such operations. Non-member cannot be defined inside the class. They cannot access the private data members of a class.
Here's an example of binary overloading using a non-member function:
#include <iostream>
using namespace std;
class MyClass
{
private:
int value;
public:
MyClass(int val)
{
value = val;
}
int getValue()
{
return value;
}
};
MyClass operator*(const int num, const MyClass& obj)
{
int product = num * obj.getValue();
return MyClass(product);
}
int main()
{
MyClass obj1(5);
MyClass result = 2 * obj1;
cout << "Result: " << result.getValue() << endl; // Output: 15
return 0;
}
You can also achieve the same functionality as a friend function:
#include <iostream>
using namespace std;
class MyClass
{
private:
int value;
public:
MyClass(int val)
{
value = val;
}
friend MyClass operator+(const MyClass& obj1, const MyClass& obj2);
};
MyClass operator+(const MyClass& obj1, const MyClass& obj2)
{
int sum = obj1.value + obj2.value;
return MyClass(sum);
}
int main()
{
MyClass obj1(10);
MyClass obj2(20);
MyClass result = obj1 + obj2;
cout << "Result: " << result.value << endl; // Output: 30
return 0;
}