Object-Oriented Programming
Operator Overloading
Defining custom behavior for C++ operators on user-defined types
Interview: C++ specific — overloading operators for custom types, member vs non-member, C++20 spaceship operator
Operator Overloading
C++ allows redefining the behavior of built-in operators for user-defined types. Operator overloading makes custom types as natural to use as built-in types — enabling v1 + v2 for vectors, cout << obj for output, and m[i][j] for matrices. The overloaded operator must have at least one user-defined type as an operand — you cannot redefine int + int.
Member vs Non-Member
Member operators: the left operand is the object (this). Use for operators where the left operand is your type: assignment, subscript, call, arrow, increment/decrement. Non-member operators: both operands are explicit parameters. Use for symmetric binary operators (so implicit conversions apply to both sides equally) and stream operators where the left operand is not your type.
Operators That Cannot Be Overloaded
The following cannot be overloaded: :: (scope resolution), . (member access), .* (member pointer access), ?: (ternary), sizeof, typeid.
C++20 Spaceship Operator
The <=> three-way comparison operator in C++20 returns std::strong_ordering, std::weak_ordering, or std::partial_ordering. Defaulting it (auto operator<=>() const = default) auto-generates all six comparison operators. This eliminates all the boilerplate comparison code.
Interview Corner
Q: Why should operator+ return by value and operator+= return by reference?
A: operator+= modifies the left operand in place and should return *this by reference to enable chaining (a += b += c). operator+ creates a new value (can't be the left operand since it doesn't exist yet) so it returns by value. Best practice: implement operator+ in terms of operator+=: T operator+(T lhs, const T& rhs) { return lhs += rhs; }
Q: What is the difference between prefix and postfix operator++?
A: Prefix operator++(): increments and returns *this by reference — O(1), no copy. Postfix operator++(int): the dummy int parameter distinguishes it; must save the old value, increment, then return the old value by value — O(n) copy for iterators. Always prefer prefix increment in loops for non-trivial iterators.
Common Pitfalls
- Changing operator semantics: Overloading operators to do unexpected things (e.g., + doing subtraction) makes code confusing. Operators should preserve expected semantics.
- Returning this from binary operators:
operator+should return a new value, not this (which is the left operand). - Missing const on non-mutating operators: Comparison, subscript (const overload), and arithmetic operators that don't modify the object should be
constmember functions.
Best Practices
- Implement compound assignment first (
+=), then implement the binary operator in terms of it: simpler and avoids code duplication. - Use C++20 defaulted
operator<=>()for value types — it generates all comparisons correctly and efficiently. - Prefer non-member operators for symmetric binary operations to allow implicit conversions on both operands.