Operator Overloading in C++
Operator overloading lets you define what built-in operators like +, ==, or << mean for your own types. Once you teach a Vector2D how to add, you can write a + b instead of a.add(b). Used well, it makes your types feel like first-class citizens of the language. Used carelessly, it surprises readers — so the golden rule is make operators do the obvious thing.
Let us overload a few.
Overloading + as a member function
A binary operator written as a member takes the left operand as this and the right operand as a parameter.
#include <iostream>
class Vector2D {
public:
double x = 0, y = 0;
Vector2D(double x_, double y_) : x(x_), y(y_) {}
// a + b -> a.operator+(b)
Vector2D operator+(const Vector2D& other) const {
return Vector2D{x + other.x, y + other.y};
}
};
int main() {
Vector2D a{1, 2}, b{3, 4};
Vector2D c = a + b; // uses operator+
std::cout << c.x << ", " << c.y << "\n"; // 4, 6
}
Overloading << for printing (a friend function)
To print with std::cout << v, the left operand is the stream, not your object — so this operator must be a free function. Declaring it a friend lets it read private members.
#include <iostream>
class Vector2D {
double x, y;
public:
Vector2D(double x_, double y_) : x(x_), y(y_) {}
// grant the operator access to private x, y
friend std::ostream& operator<<(std::ostream& os, const Vector2D& v) {
os << "(" << v.x << ", " << v.y << ")";
return os; // return the stream so calls can chain
}
};
int main() {
Vector2D v{4, 6};
std::cout << "v = " << v << "\n"; // v = (4, 6)
}
Returning the stream by reference is what lets you chain std::cout << a << b.
Want to learn this properly?
Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.
Browse coursesOverloading comparison operators
Equality is one of the most common overloads. In modern C++ you can let the compiler generate it.
#include <iostream>
struct Point {
int x, y;
// C++20: compiler generates ==, != automatically
bool operator==(const Point&) const = default;
};
int main() {
Point p{1, 2}, q{1, 2};
std::cout << std::boolalpha << (p == q) << "\n"; // true
}
For ordering, auto operator<=>(const Point&) const = default; (the C++20 "spaceship" operator) generates <, <=, >, and >= in one line. Letting the compiler generate these means they stay correct even when you add or reorder members later — a hand-written comparison that forgets a new field is a classic, silent bug.
Compound assignment and chaining
A common pattern is to implement the compound form (+=) as a member that returns *this, then define + in terms of it. This keeps the logic in one place and makes both operators consistent.
class Money {
long paise = 0;
public:
Money& operator+=(const Money& rhs) {
paise += rhs.paise;
return *this; // return self so a += b += c works
}
friend Money operator+(Money lhs, const Money& rhs) {
lhs += rhs; // reuse += ; lhs is a copy we can modify
return lhs;
}
};
Taking lhs by value and returning it is the idiomatic way to write a binary + on top of +=.
Design rules
- Keep meaning intuitive.
+should combine,==should compare. Never overload+to mean subtraction. - Members for operators that modify the left operand (
+=,++); free/friend functions for symmetric ones (+,==,<<). - Return by value for arithmetic, by reference for assignment (
operator=returns*this). - Prefer compiler-generated comparisons (
= default) — they are correct and complete.
Common mistakes
- Overloading operators with surprising meaning. If
a * bdoes something unexpected, every reader is fooled. Match built-in intuition. - Forgetting to return the stream from
<<. Withoutreturn os;, chained output stops compiling. - Making
operator<<a member. The left operand is the stream, so it must be a non-member (often afriend). - Returning a reference to a local. Arithmetic operators create a new result; return it by value, not as a dangling reference.
FAQ
Which operators can I overload?
Most of them — arithmetic, comparison, subscript [], call (), stream <</>>, and more. A few like ::, ., and ?: cannot be overloaded.
Should I always overload operators for my classes? Only when an operator has an obvious, conventional meaning for your type (numbers, points, money). If the meaning is not instantly clear, a named function is friendlier.
Keep learning
- Compare this with the related mechanism in Function Overloading in C++.
- See where
friendand access control fit in Encapsulation & Abstraction in C++. - Browse the full series on the C++ OOP hub.
Write expressive, idiomatic C++ with mentor feedback — join the waitlist for our C++ Programming course in Jalgaon.
Want to learn this properly?
Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.
Browse coursesFounder, Infoplanet
Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.
Related guides
Classes & Objects in C++
Understand C++ classes and objects — defining a class, creating objects, member functions, and access control with public and private members.
Constructors & Destructors in C++
Understand C++ constructors and destructors — how objects are initialised and cleaned up, including parameterised, copy constructors, and initializer lists.
Encapsulation & Abstraction in C++
Understand encapsulation and abstraction in C++ — hiding internal data, exposing controlled interfaces, and why both make code safer and easier to change.
