Advanced⏱️ 9 min📘 Topic 23 of 32

🎼 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 + b shouldn'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.