Notes
Operator Overloading
What is Operator Overloading?
Operator overloading allows us to redefine the behavior of operators (+, -, *, =, etc.) for
user-defined types (classes).
This makes operations on objects more intuitive and readable.
Why Overload Operators?
▪ Allows natural operations on objects (e.g., p1 + p2 instead of [Link](p2)).
▪ Makes object-oriented programming (OOP) cleaner.
▪ Improves code readability and maintainability.
Operator Overloading
Rules for Operator Overloading
▪ Only existing operators can be overloaded.
▪ Precedence and associativity of operators do not change.
▪ Some operators must be member functions (=, (), [], ->).
▪ Other operators can be member functions or global functions.
▪ Cannot overload ::, .*, sizeof, typeid, etc.
Operator Overloading
Syntax for Operator Overloading
Operators can be overloaded:
1. As a member function (operates on this object).
2. As a global function (operates on objects passed as arguments).
Operator Overloading
General Syntax (Member Function)
class ClassName {
public:
ReturnType operator OpSymbol (const ClassName& obj) {
// Define operation
}
};
General Syntax (Global Function)
ReturnType operator OpSymbol (const ClassName& obj1, const ClassName& obj2) {
// Define operation
}
Overloading Operators in a Simple Point Class
class Point {
private: // Overloading - operator (global function)
int x, y; // Global function for – operator
public: Point operator - (const Point& p1, const Point& p2) {
// Constructor return Point([Link]() - [Link](), [Link]() - [Link]());
Point(int a = 0, int b = 0) : x(a), y(b) {} }
// Overloading + operator (member function) int main() {
Point p1(3, 4), p2(1, 2);
Point operator + (const Point& p) const {
return Point(x + p.x, y + p.y); Point p3 = p1 + p2; // Uses member function
} Point p4 = p1 - p2; // Uses global function
void display() const { cout << "p1: "; [Link]();
cout << "(" << x << ", " << y << ")" << endl; cout << "p2: "; [Link]();
} cout << "p1 + p2: "; [Link]();
cout << "p1 - p2: "; [Link]();
// Getter functions for accessing private members
int getX() const { return x; } return 0;
int getY() const { return y; } }
};
Point operator+(const Point& p) const {
return Point(x + p.x, y + p.y);
}
Point operator+(const Point& p) const {
Point temp;
temp.x = x + p.x;
temp.y = y + p.y;
return temp;
}
Point operator+(const Point& p) const {
return Point(this->x + p.x, this->y + p.y);
}
Point operator+(const Point& p) const {
return Point((x > 0 ? x + p.x : x), (y > 0 ? y + p.y : y));
}
Overloading ++ and -- (Pre/Post Increment)
// Pre-increment (++p) // Post-increment (p++)
Point& operator ++ () { Point operator ++ (int) {
x++; y++; Point temp = *this;
return *this; x++; y++;
} return temp;
}
Overloading == (Equality Comparison)
bool operator == (const Point& p) const {
return (x == p.x && y == p.y);
}
Overloading << and >> (I/O Stream Operators)
ostream& operator<<(ostream& out, const Point& p) {
out << "(" << [Link]() << ", " << [Link]() << ")";
return out;
}
istream& operator>>(istream& in, Point& p) {
int a, b;
in >> a >> b;
p = Point(a, b);
return in;
}
Practice Questions
1. Overload the * operator for scalar multiplication (p * 2).
2. Overload the / operator for division by a scalar.
3. Implement a Complex class with overloaded +, -, and * operators.
4. Overload the [] operator for accessing Point coordinates (p[0] for x, p[1] for y).
5. Overload == and != to compare two Point objects.
Operator Purpose
+ Adds two objects (p1 + p2)
- Subtracts two objects (p1 - p2)
* Multiplies object with scalar (p1 * 2)
/ Divides object by scalar (p1 / 2)
[] Accesses elements (p[0], p[1])
== Checks equality (p1 == p2)
!= Checks inequality (p1 != p2)
1. Overloading * Operator for Scalar Multiplication (p * 2)
class Point {
private:
int x, y; int main() {
Point p1(3, 4);
public: Point p2 = p1 * 2; // Multiply point by 2
Point(int a = 0, int b = 0) : x(a), y(b) {}
cout << "p1: "; [Link]();
// Overloading * operator for scalar multiplication cout << "p1 * 2: "; [Link]();
Point operator*(int scalar) const {
return Point(x * scalar, y * scalar); return 0;
} }
void display() const {
cout << "(" << x << ", " << y << ")" << endl;
}
};
p1: (3, 4)
p1 * 2: (6, 8)
2. Overloading / Operator for Division by a Scalar (p / 2)
class Point {
private:
int x, y;
int main() {
public:
Point p1(10, 20);
Point(int a = 0, int b = 0) : x(a), y(b) {}
Point p2 = p1 / 2; // Divide point by 2
// Overloading / operator for scalar division
cout << "p1: "; [Link]();
Point operator/(int scalar) const {
cout << "p1 / 2: "; [Link]();
if (scalar == 0) {
cout << "Error: Division by zero!" << endl;
return 0;
return *this;
}
}
return Point(x / scalar, y / scalar);
}
void display() const {
cout << "(" << x << ", " << y << ")" << endl;
} p1: (10, 20)
}; p1 / 2: (5, 10)
3. Implementing a Complex Class with Overloaded +, -, and * Operators
class Complex {
private:
double real, imag;
public: int main() {
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
Complex c1(3, 4), c2(1, 2);
// Overloading + operator
Complex operator+(const Complex& c) const { Complex sum = c1 + c2;
return Complex(real + [Link], imag + [Link]); Complex diff = c1 - c2;
} Complex prod = c1 * c2;
// Overloading - operator cout << "c1: "; [Link]();
Complex operator-(const Complex& c) const { cout << "c2: "; [Link]();
return Complex(real - [Link], imag - [Link]);
cout << "c1 + c2: "; [Link]();
}
cout << "c1 - c2: "; [Link]();
// Overloading * operator cout << "c1 * c2: "; [Link]();
Complex operator*(const Complex& c) const {
return Complex(real * [Link] - imag * [Link], real * [Link] + imag * [Link]); return 0;
} } c1: 3 + 4i
void display() const { c2: 1 + 2i
cout << real << " + " << imag << "i" << endl; c1 + c2: 4 + 6i
} c1 - c2: 2 + 2i
}; c1 * c2: -5 + 10i
4. Overloading [] Operator for Accessing Point Coordinates (p[0] for x, p[1] for y)
class Point {
private:
int x, y;
public: int main() {
Point(int a = 0, int b = 0) : x(a), y(b) {} Point p1(5, 10);
cout << "p1[0]: " << p1[0] << endl;
// Overloading [] operator cout << "p1[1]: " << p1[1] << endl;
int operator[](int index) const { cout << "p1[2]: " << p1[2] << endl; // Invalid index
if (index == 0) return x;
if (index == 1) return y; return 0;
cout << "Error: Invalid index!" << endl; }
return -1;
}
void display() const {
cout << "(" << x << ", " << y << ")" << endl;
} p1[0]: 5
}; p1[1]: 10
Error: Invalid index!
p1[2]: -1
5. Overloading == and != to Compare Two Point Objects
class Point {
private:
int x, y;
public:
Point(int a = 0, int b = 0) : x(a), y(b) {}
int main() {
// Overloading == operator
Point p1(3, 4), p2(3, 4), p3(5, 6);
bool operator==(const Point& p) const {
return (x == p.x && y == p.y);
cout << "p1 == p2: " << (p1 == p2) << endl; // True (1)
}
cout << "p1 == p3: " << (p1 == p3) << endl; // False (0)
cout << "p1 != p3: " << (p1 != p3) << endl; // True (1)
// Overloading != operator
bool operator!=(const Point& p) const {
return 0;
return !(*this == p); // Uses the overloaded ==
}
}
void display() const {
cout << "(" << x << ", " << y << ")" << endl; p1 == p2: 1
} p1 == p3: 0
}; p1 != p3: 1
1. Operators That Can Be Overloaded
Operator Description
Operator Description
+= Addition assignment
+ Addition
-= Subtraction assignment
- Subtraction
*= Multiplication assignment
* Multiplication
/= Division assignment
/ Division
%= Modulus assignment
% Modulus
<< Output stream (cout <<)
++ Increment (pre/post)
>> Input stream (cin >>)
-- Decrement (pre/post)
& Address-of (not recommended to overload)
== Equality check
^ Bitwise XOR
!= Inequality check
&= Bitwise AND assignment
> Greater than
^= Bitwise XOR assignment
< Less than
~ Bitwise NOT
>= Greater than or equal to
&& Logical AND
<= Less than or equal to
! Logical NOT
= Assignment
, Comma operator
-> Member access (rarely overloaded)
->* Pointer to member
() Function call operator
[] Subscript operator
2. Operators That Cannot Be Overloaded
Operator Description
. Member access ([Link])
.* Pointer-to-member selection
:: Scope resolution (ClassName::member)
sizeof Size operator (sizeof(type))
typeid Runtime type identification
alignof Alignment requirement
new and delete Memory allocation/deallocation (can be overloaded globally but not per class)
class Point {
private:
double x;
double y;
public:
Point(double xVal = 0.0 , double yVal = 0.0) : x(xVal), y(yVal) {}
// Getter for x
double getX() const {
return x;
}
// Setter for x
void setX(double newX) {
x = newX;
}
// Getter for y
double getY() const {
return y;
}
// Setter for y
void setY(double newY) {
y = newY;
}
// Display
void display() {
cout << "Point(" << x << ", " << y << ")" <<endl;
}
};
// Overload + operator for Point + Point int main() {
Point operator+(const Point& p1, const Point& p2) { Point P1(2.0, 3.0);
Point p; Point P2(1.0, 4.0);
[Link]([Link]() + [Link]());
[Link]([Link]() + [Link]()); // P1 + P2
return p; Point result1 = P1 + P2;
} cout << "P1 + P2 = ";
[Link]();
// Overload + operator for Point + scalar
Point operator+(const Point& p, const double scalar) { // P1 + 5.0
Point r; Point result2 = P1 + 5.0;
[Link]([Link]() + scalar); cout << "P1 + 5.0 = ";
[Link]([Link]() + scalar); [Link]();
return r;
} // 5.0 + P1
Point result3 = 5.0 + P1;
// Overload + operator for scalar + Point cout << "5.0 + P1 = ";
Point operator+(const double scalar, const Point& p) { [Link]();
Point r;
[Link](scalar + [Link]()); return 0;
[Link](scalar + [Link]()); }
return r;
}
// Overload + operator for Point + Point int main() {
Point operator+(const Point& p2) { Point P1(2.0, 3.0);
Point p; Point P2(1.0, 4.0);
p.x = (this->x + p2.x);
p.y = (this->y + p2.y); // P1 + P2
return p; Point result1 = P1 + P2;
} cout << "P1 + P2 = ";
[Link]();
// Overload + operator for Point + scalar
Point operator+(const double scalar) { // P1 + 5.0
Point r; Point result2 = P1 + 5.0;
r.x = (this->x + scalar); cout << "P1 + 5.0 = ";
r.y = (this->x + scalar); [Link]();
return r;
} // 5.0 + P1
}; Point result3 = 5.0 + P1;
cout << "5.0 + P1 = ";
// Overload + operator for scalar + Point [Link]();
Point operator+(const double scalar, const Point& p) {
Point r; return 0;
[Link](scalar + [Link]()); }
[Link](scalar + [Link]());
return r;
}
// Overload pre-increment operator (++Point) int main() {
Point& operator++() { Point P1(2.0, 3.0);
x++; cout << "Original Point: ";
[Link]();
y++;
return *this; // Pre-increment operator (++Point)
} ++P1;
// Overload post-increment operator (Point++) cout << "After Pre-increment: ";
Point operator++(int) { [Link]();
Point temp(*this);
x++; // Post-increment operator (Point++)
Point result1 = P1++;
y++; cout << "After Post-increment: ";
return temp; [Link]();
} cout << "Result of Post-increment: ";
// Overload pre-decrement operator (--Point) [Link]();
Point& operator--() {
x--; // Pre-decrement operator (--Point)
y--; --P1;
cout << "After Pre-decrement: ";
return *this; [Link]();
}
// Overload post-decrement operator (Point--) // Post-decrement operator (Point--)
Point operator--(int) { Point result2 = P1--;
Point temp(*this); cout << "After Post-decrement: ";
x--; [Link]();
y--; cout << "Result of Post-decrement: ";
[Link]();
return temp;
} return 0;
}; }
// Overload unary + operator to return the point itself int main() {
Point operator+() const { Point P1(2.0, 3.0);
return *this;
// Display the original point
}
cout << "Original Point: ";
[Link]();
// Overload unary - operator to negate the point
Point operator-() const { // Use unary + operator
x = -x; Point result1 = +P1;
y = -y; cout << "Unary + Result: ";
return *this; [Link]();
}
// Use unary - operator
Point result2 = -P1;
// Overload unary ! operator to reverse the point's sign cout << "Unary - Result: ";
Point operator!() const { [Link]();
x = !x;
y = !y; // Use unary ! operator
return *this; Point result3 = !P1;
} cout << "Unary ! Result: ";
}; [Link]();
return 0;
}
int main() {
Point P1(2.0, 3.0);
Point P2(2.0, 3.0);
Point P3(4.0, 5.0);
// Overload == operator to compare two Point objects for equality
if (P1 == P2)
{
bool operator==(const Point& other) const {
cout<<"P1 and P2 are equal"<<endl;
bool areEqual = (x == other.x) && (y == other.y); }
return areEqual; else
} {
cout<<"P1 and P2 are not equal"<<endl;
// Overload != operator to compare two Point objects for inequality }
bool operator!=(const Point& other) const { if (P1 != P3)
{
bool areNotEqual = !(*this == other);
cout<<"P1 and P3 are not equal"<<endl;
return areNotEqual; }
} else
}; {
cout<<"P1 and P3 are equal"<<endl;
}
return 0;
}
// Overload << operator for easy printing of Point objects int main() {
friend ostream& operator<<(ostream& os, const Point& point) { Point P1(2.0, 3.0);
os << "Point(" << point.x << ", " << point.y << ")"; Point P2(0.0, 0.0);
return os;
} // Output P1
cout << "P1: " << P1 <<endl;
// Overload >> operator to read Point objects from the input stream
friend istream& operator>>(istream& is, Point& point) { // Input P2 from the user
is >> point.x >> point.y; cout << "Enter coordinates for P2 (x y): ";
return is; cin >> P2;
}
// Output P2
// Overload the copy assignment operator (=) for Point objects cout << "P2: " << P2 <<endl;
Point& operator=(const Point& other) {
if (this != &other) { // Assign P1 to P2 using the copy assignment operator
x = other.x; P2 = P1;
y = other.y;
} // Output P2 (now contains the same values as P1)
return *this; cout << "P2: " << P2 << endl;
} return 0;
}; }
In the context of the Point class, we've covered many of the commonly overloaded operators, including:
Arithmetic operators (+, -, *, /) for addition, subtraction, multiplication, and division.
Comparison operators (== and !=) for equality and inequality.
Output stream operator (<<) for printing Point objects.
Input stream operator (>>) for reading Point objects from the input.
Copy assignment operator (=) for copying one Point object to another.
Unary operators (+, -, !, ++, --) for various operations.
Extra, try yourself as home tasks:
+= and -= operators: You can overload these operators to perform addition and subtraction assignment.
*, /, %, etc., for more advanced arithmetic operations: Depending on your use case, you might need to provide
custom behaviors for these operators.
Relational operators (<, >, <=, >=): If you need custom behavior when comparing Point objects, you can overload
these operators.
[] operator: If your class represents a container or has array-like behavior, you can overload the subscript operator for
element access.
() operator: If your class is callable like a function, you can overload the function call operator.