🎼 Operator Overloading in C++ — Custom Behavior for + - == << and More
Master C++ operator overloading. Define how +, -, ==, <<, [], () work for your custom classes — with examples for Vector, string streams, comparisons and interview Q&A.
Operator overloading lets you define what built-in operators (+, ==, <<, etc.) mean for your custom types. Used right, it makes your types feel native.
📜 Member function vs free function
Many operators can be defined either way:
class Vec2 {
public:
double x, y;
// member function
Vec2 operator+(const Vec2& o) const {
return {x + o.x, y + o.y};
}
};
// free function (preferred when LHS isn't your class)
std::ostream& operator<<(std::ostream& os, const Vec2& v) {
return os << '(' << v.x << ',' << v.y << ')';
}🎯 Commonly overloaded operators
- Arithmetic:
+ - * / - Comparison:
== != < >(C++20:<=>spaceship) - Stream:
<< >>(for printing/reading) - Subscript:
[](for container-like classes) - Function call:
()(functors / callable objects) - Assignment:
=(rule of three!)
❌ Cannot overload
::, ., .*, ?:, sizeof, typeid.
💡 Guidelines
- Only overload when it makes the code more natural — not less.
- Preserve expected semantics:
a + bshouldn't print to stdout. - If you overload
==, also overload!=(or use C++20's<=>).
💻 Code Examples
Vector addition
struct Vec2 {
double x, y;
Vec2 operator+(const Vec2& o) const { return {x + o.x, y + o.y}; }
bool operator==(const Vec2& o) const { return x == o.x && y == o.y; }
};
Vec2 a{1, 2}, b{3, 4};
Vec2 c = a + b;
std::cout << c.x << ',' << c.y;Output:
4,6
Stream output
std::ostream& operator<<(std::ostream& os, const Vec2& v) {
return os << '(' << v.x << ',' << v.y << ')';
}
Vec2 p{5, 7};
std::cout << p;Output:
(5,7)
Functor — callable struct
struct Multiplier {
int factor;
int operator()(int x) const { return x * factor; }
};
Multiplier doubler{2};
std::cout << doubler(7);Output:
14
⚠️ Common Mistakes
- Overloading operators for cleverness — `mat << vec` to MULTIPLY (most readers will think it prints).
- Forgetting that `operator==` and `!=` come as a pair (pre-C++20).
- Defining `<<` as a member function — must be a free function (LHS is `ostream`, not your class).
- Modifying the object in a `const` operator — compiler will reject.
🎯 Interview Questions
Real questions asked at top product and service-based companies.
Q1.What is operator overloading?Intermediate
Defining how built-in operators (+ - == << []) behave for your custom class. Lets your types feel native: `vec1 + vec2`, `cout << myObject`.
Q2.When should an operator be a member function vs a free function?Intermediate
Member: when the LHS IS your class and you want easy access to private members (assignment, subscript, function call). Free: when you want symmetry (`5 + vec` AND `vec + 5`), or when LHS isn't your class (`ostream << myType`).
Q3.Which operators can you NOT overload?Intermediate
:: (scope), . (member access), .* (pointer to member), ?: (ternary), sizeof, typeid. Also, you can't invent new operators.
Q4.What is the spaceship operator (<=>)?Advanced
C++20's three-way comparison: `a <=> b` returns less, equal, or greater. Define one of these and the compiler auto-generates `<`, `<=`, `>`, `>=`, `==`, `!=`. Eliminates boilerplate.
Q5.What's a functor?Advanced
A class with `operator()` overloaded — it can be CALLED like a function. Can hold state. STL uses functors heavily (`std::sort` with custom comparator, `std::function`).
🧠 Quick Summary
- Operator overloading makes custom types feel native.
- Member function for asymmetric ops (assign, subscript).
- Free function for symmetric/stream ops.
- Preserve expected semantics — don't surprise readers.
- C++20's spaceship operator auto-generates comparisons.
- Functor = class with operator() — callable with state.