DMarlon Studio

Lesson 5 · 5 of 20

Operator overloading · C++

Give your C++ classes their own operators (+, *, +=, ==, < and <<) with a Money type that stores cents, so sums never lose a penny.

C++ · Operator overloading in DMarlon Studio: the example's code and its output in the terminal

Money keeps the amount in cents inside a long, because a double cannot represent values like 0.10 exactly. The constructor is `explicit`: it stops a stray number from silently turning into Money. euros() is a `static` method: you call it on the class, Money::euros(1.80), without an object, and it rounds to cents.

Overloading an operator means writing a function named operator+, operator* and so on. Then coffee * 2 + croissant reads like ordinary arithmetic: the compiler turns it into coffee.operator*(2).operator+(croissant). The arithmetic operators are const and return a new value; +=, on the other hand, changes the object itself and returns *this by reference, just like the standard library types do.

== and < return bool, so amounts can be compared, and thanks to < the type already works with std::sort or std::max. std::boolalpha makes cout print true and false instead of 1 and 0.

operator<< cannot be a member, because the stream goes on its left (std::cout << order). It is declared `friend` inside the class: a free function that is allowed to read cents_. It prints the euros, a dot and the cents as two digits (setw(2) and setfill('0'), which it then puts back) and returns the stream so more << can follow.

Code · main.cpp

#include <iomanip>#include <iostream>// Money kept in cents, so sums never suffer rounding errors.class Money {    long cents_;public:    explicit Money(long cents = 0) : cents_(cents) {}    static Money euros(double e) { return Money(static_cast<long>(e * 100 + 0.5)); }    // Arithmetic operators return a new value; += changes this one.    Money operator+(const Money& o) const { return Money(cents_ + o.cents_); }    Money operator*(int qty) const { return Money(cents_ * qty); }    Money& operator+=(const Money& o) { cents_ += o.cents_; return *this; }    bool operator==(const Money& o) const { return cents_ == o.cents_; }    bool operator<(const Money& o) const { return cents_ < o.cents_; }    // << is a free function (the stream goes on the left); friend lets it see cents_.    friend std::ostream& operator<<(std::ostream& os, const Money& m) {        return os << m.cents_ / 100 << '.' << std::setw(2) << std::setfill('0')                  << m.cents_ % 100 << std::setfill(' ') << " EUR";    }};int main() {    Money coffee = Money::euros(1.80), croissant = Money::euros(2.25);    Money order = coffee * 2 + croissant;    std::cout << "Order: " << order << "\n";    Money till;    for (int i = 0; i < 3; ++i) till += order;    std::cout << "Till after 3 orders: " << till << "\n";    std::cout << std::boolalpha;    std::cout << "Coffee < croissant? " << (coffee < croissant) << "\n";    std::cout << "Two coffees == 3.60? " << (coffee * 2 == Money::euros(3.60)) << "\n";}

Output · c++ -std=c++17 main.cpp -o main && ./main

Order: 5.85 EUR
Till after 3 orders: 17.55 EUR
Coffee < croissant? true
Two coffees == 3.60? true

Key points

  • operator+, operator==, operator<<… are functions with a special name.
  • Arithmetic operators return a new value; compound ones such as += return *this.
  • explicit prevents implicit conversions from the constructor's argument type.
  • operator<< is a free function (often a friend) that returns the stream.
  • Store money as whole numbers of cents, not as double.

Exercise

Add operator- and use it to work out the change when a customer pays for the order with a 10-euro note. Check that the result is 4.15 EUR.