Intermediate · Operator overloading, inheritance and polymorphism · topic 17 of 42 · 30 min
Operator overloading
Explanation
Why overload operators?
For built-in types, a + b and a == b just work. For your own class, say Money, you would otherwise write add(a, b) and equals(a, b), which is clumsy. Operator overloading lets you define what +, -, ==, <, << and others mean for your type. The standard library uses it everywhere: std::string has + and ==, std::cout has <<, iterators have ++ and *.
A Money type
#include <iostream>
class Money {
public:
explicit Money(long long paise = 0) : paise_(paise) {}
long long paise() const { return paise_; }
Money& operator+=(const Money& other) { // member: changes this object
paise_ += other.paise_;
return *this;
}
private:
long long paise_;
};
Money operator+(Money a, const Money& b) { // non-member, built from +=
a += b;
return a;
}
bool operator==(const Money& a, const Money& b) { return a.paise() == b.paise(); }
bool operator<(const Money& a, const Money& b) { return a.paise() < b.paise(); }
std::ostream& operator<<(std::ostream& out, const Money& m) {
return out << "Rs " << m.paise() / 100 << '.' << (m.paise() % 100) / 10 << m.paise() % 10;
}
int main() {
Money tea(1500), samosa(2000);
Money bill = tea + samosa;
std::cout << bill << '\n'; // Rs 35.00
std::cout << (tea < samosa) << '\n'; // 1
}Member or non-member?
- Operators that change the object (+=, -=, ++, =, []) are usually members.
- Symmetric operators (+, -, ==, <) are usually non-members, so conversions work on both sides the same way.
- operator<< for printing must be a non-member, because the left side is std::ostream, not your class.
- = (assignment), [] (subscript), () (call) and -> must be members.
C++20: the spaceship operator
#include <compare>
struct Version {
int major, minor;
auto operator<=>(const Version&) const = default; // also generates ==
};
// Version{1, 2} < Version{1, 10} is true; ==, !=, <, <=, >, >= all workIncrement and subscript
class Counter {
public:
Counter& operator++() { ++n_; return *this; } // prefix: ++c
Counter operator++(int) { Counter old = *this; ++n_; return old; } // postfix: c++
int value() const { return n_; }
private:
int n_ = 0;
};
class Marks {
public:
int& operator[](std::size_t i) { return data_[i]; }
const int& operator[](std::size_t i) const { return data_[i]; }
private:
int data_[5] = {};
};Rules and good taste
- You cannot invent new operators (no **), change precedence, or overload operators for built-in types only (int + int).
- A few operators cannot be overloaded at all: ::, ., .* and ?:.
- Keep meanings unsurprising. Using + to delete a file would compile, but nobody could read your code.
- If you define ==, define != (C++20 generates != from == for you). If you define <, define the others, or just use <=>.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Operator overloading · 1/6
Operator overloading lets your own types use plus, equals, less-than and the output arrows.
Prefer a video by a teacher? Find free videos on “c++ operator overloading tutorial operator<< operator+ spaceship” on YouTube ↗
In real life: GPS distance and time in a delivery app
A food delivery app adds up travel times for each leg of a rider's route. A small Duration type with + and < lets the code read like the business rule: if (pickup + drive < promised) show "on time". The standard library's std::chrono::duration types work exactly this way.
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono_literals;
auto pickup = 8min;
auto drive = 17min;
auto promised = 30min;
auto total = pickup + drive; // operator+ on durations
std::cout << total.count() << " min, "
<< (total < promised ? "on time" : "late") << '\n'; // 25 min, on time
}Practice (0/4 done)
What is the name of the function that defines a + b for your type?
Why must operator<< for printing be a non-member function?
Which operator can NOT be overloaded?
Write a struct Fraction { long long num, den; } with operator+, operator== (compare after reducing with std::gcd from <numeric>), and operator<< that prints like 3/4. Test that 1/2 + 1/4 prints 3/4 and that 2/4 == 1/2.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Inheritance: building on an existing classOperator overloading, inheritance and polymorphism · same module
- Virtual functions and polymorphismOperator overloading, inheritance and polymorphism · same module
- Abstract classes, interfaces and good class designOperator overloading, inheritance and polymorphism · same module
- C++20 ranges, views and other C++20 essentialsModern C++: lambdas, C++17 and C++20 essentials
- OperatorsC Programming (from zero to systems) · Operators and control flow
- Methods: parameters, return values and overloadingJava Programming (Core to Spring Boot) · Control flow and methods
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Which operators usually are member functions?
Answer: +=, =, [] and ++
Operators that modify the object, plus =, [] and (), are members.
What does auto operator<=>(const T&) const = default; give you?
Answer: All six comparison operators, comparing members in order
Defaulted <=> generates <, <=, >, >= and also == / !=.
How is postfix c++ told apart from prefix ++c when overloading?
Answer: Postfix has a dummy int parameter
operator++(int) is postfix; operator++() is prefix.
Why avoid overloading &&?
Answer: The overloaded version always evaluates both sides, losing short-circuit behaviour
Readers expect && to stop early; overloads cannot do that.
What does const after a member function's brackets mean?Related
Answer: It promises not to change the object
A const member function can be called on const objects and cannot modify members.
What does the rule of three say?Related
Answer: If a class needs a custom destructor, copy constructor or copy assignment, it probably needs all three
These three manage the same resource, so they come as a set.
What does the | operator do between views?Related
Answer: Chains view steps into a pipeline
Range adaptors compose with the pipe operator.
When does the compiler choose which overload to call?Related
Answer: At compile time, from the argument types
Overload resolution happens while compiling, based on the arguments in each call.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “Operator overloading, inheritance and polymorphism” before its exam: Inheritance: building on an existing class, Virtual functions and polymorphism, Abstract classes, interfaces and good class design.
- Module 5 exam: Operators, inheritance and polymorphism · 13 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, The Standard Template Library (STL). 42 topics left in the course before the final exam.
← Previous: Copying objects: the rule of three, five and zero