DMarlon Studio

Lección 5 · 5 de 20

Sobrecarga de operadores · C++

Dé a sus clases de C++ operadores propios (+, *, +=, ==, < y <<) con un tipo Money que guarda céntimos para no perder ni un euro al sumar.

C++ · Sobrecarga de operadores en DMarlon Studio: el código del ejemplo y su salida en la terminal

Money guarda el dinero en céntimos dentro de un long, porque un double no representa exactamente valores como 0,10. El constructor es `explicit`: impide que un número suelto se convierta en Money sin querer. euros() es un método `static`: se llama sobre la clase, Money::euros(1.80), sin necesitar un objeto, y redondea a céntimos.

Sobrecargar un operador es escribir una función llamada operator+, operator*, etc. Así coffee * 2 + croissant se lee como una cuenta normal: el compilador la convierte en coffee.operator*(2).operator+(croissant). Los operadores aritméticos son const y devuelven un valor nuevo; +=, en cambio, cambia el propio objeto y devuelve *this por referencia, como hacen los tipos de la biblioteca estándar.

== y < devuelven bool, de modo que los importes se pueden comparar, y gracias a < el tipo ya sirve para std::sort o std::max. std::boolalpha hace que cout escriba true y false en vez de 1 y 0.

operator<< no puede ser miembro, porque a su izquierda va el flujo (std::cout << order). Se declara `friend` dentro de la clase: es una función libre, pero con permiso para leer cents_. Escribe los euros, un punto y los céntimos con dos cifras (setw(2) y setfill('0'), que luego se deja como estaba) y devuelve el flujo para poder encadenar más <<.

Código · 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";}

Salida · 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

Para recordar

  • operator+, operator==, operator<<… son funciones con un nombre especial.
  • Los operadores aritméticos devuelven un valor nuevo; los compuestos, como +=, devuelven *this.
  • explicit evita conversiones implícitas desde el tipo del constructor.
  • operator<< es una función libre (a menudo friend) que devuelve el flujo.
  • Guarde el dinero en enteros (céntimos), no en double.

Ejercicio

Añada operator- y úselo para calcular el cambio cuando un cliente paga el pedido con un billete de 10 euros. Compruebe que el resultado es 4.15 EUR.