Sobrecarga de operadores aritméticos
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 41 de 104.
Los operadores aritméticos como +, -, * y / se sobrecargan comúnmente para que las clases personalizadas se comporten como tipos numéricos integrados. Estos operadores suelen devolver un nuevo objeto en lugar de modificar los operandos.
Aquí tienes una clase Fraction con operadores aritméticos:
class Fraction {
int numerator, denominator;
public:
Fraction(int n, int d) : numerator(n), denominator(d) {}
Fraction operator+(const Fraction& other) const {
return Fraction(
numerator * other.denominator + other.numerator * denominator,
denominator * other.denominator
);
}
Fraction operator*(const Fraction& other) const {
return Fraction(numerator * other.numerator,
denominator * other.denominator);
}
};Observe que ambos operadores están marcados como const ya que no modifican ninguno de los operandos. Crean y devuelven una nueva Fraction con el resultado.
Para los operadores de asignación compuesta como +=, el patrón difiere. Estos modifican el operando izquierdo y devuelven una referencia al mismo:
Fraction& operator+=(const Fraction& other) {
numerator = numerator * other.denominator + other.numerator * denominator;
denominator = denominator * other.denominator;
return *this;
}Una práctica común es implementar el operador básico en términos de la asignación compuesta, reduciendo la duplicación de código:
Fraction operator+(const Fraction& other) const {
Fraction result = *this; // Copiar este objeto
result += other; // Usar la asignación compuesta
return result;
}Este enfoque garantiza que ambos operadores se mantengan consistentes y facilita el mantenimiento.
Desafío
FácilVamos a construir una clase Money que maneje cálculos de moneda utilizando la sobrecarga de operadores aritméticos. Implementarás múltiples operadores aritméticos que te permitirán trabajar con valores monetarios de forma tan natural como lo harías con números normales.
Crearás dos archivos para organizar tu código:
Money.h: Define una claseMoneyque almacene una cantidad en centavos (como unint) para evitar problemas de precisión de punto flotante. Tu clase debe admitir:- Un constructor que reciba dólares y centavos como enteros separados
- Un getter
getDollars()que devuelva la parte de los dólares - Un getter
getCents()que devuelva la parte de los centavos (0-99) - Operadores
+y-sobrecargados que devuelvan un nuevo objetoMoney - Operadores de asignación compuesta
+=y-=sobrecargados que modifiquen el objeto actual y devuelvan una referencia a él - Un método
display()que imprima el dinero en el formato$X.YY(siempre dos dígitos para los centavos)
Implementa los operadores básicos (
+y-) en términos de los operadores de asignación compuesta para reducir la duplicación de código, como se muestra en la lección. Todos los operadores aritméticos deben marcarse comoconstcuando sea apropiado.main.cpp: Lee cuatro enteros de la entrada que representan dos cantidades de dinero (dollars1, cents1, dollars2, cents2 en líneas separadas). Crea dos objetosMoney, luego demuestra todos tus operadores:- Imprime
"Amount 1: "seguido de la primera cantidad mostrada - Imprime
"Amount 2: "seguido de la segunda cantidad mostrada - Suma las dos cantidades e imprime
"Sum: "seguido del resultado - Resta la segunda de la primera e imprime
"Difference: "seguido del resultado - Usa
+=para sumar la segunda cantidad a la primera, luego imprime"After +=: "seguido de la primera cantidad modificada
- Imprime
Para el método display(), utiliza std::setw(2) y std::setfill('0') de <iomanip> para asegurar que los centavos siempre muestren dos dígitos (por ejemplo, $5.07 no $5.7).
Convierte las cadenas de entrada a enteros usando std::stoi(). No olvides los protectores de inclusión (header guards) en tu archivo de cabecera.
Hoja de referencia
Los operadores aritméticos como +, -, * y / pueden sobrecargarse para que las clases personalizadas se comporten como tipos numéricos integrados. Estos operadores suelen devolver un nuevo objeto en lugar de modificar los operandos.
Los operadores aritméticos básicos deben marcarse como const ya que no modifican ninguno de los operandos:
Fraction operator+(const Fraction& other) const {
return Fraction(
numerator * other.denominator + other.numerator * denominator,
denominator * other.denominator
);
}Los operadores de asignación compuesta como += y -= modifican el operando de la izquierda y devuelven una referencia a él:
Fraction& operator+=(const Fraction& other) {
numerator = numerator * other.denominator + other.numerator * denominator;
denominator = denominator * other.denominator;
return *this;
}Una práctica común es implementar los operadores básicos en términos de los operadores de asignación compuesta para reducir la duplicación de código:
Fraction operator+(const Fraction& other) const {
Fraction result = *this; // Copiar este objeto
result += other; // Usar asignación compuesta
return result;
}Pruébalo tú mismo
#include <iostream>
#include <string>
#include "Money.h"
using namespace std;
int main() {
// Leer la entrada para dos cantidades de dinero
string line;
getline(cin, line);
int dollars1 = stoi(line);
getline(cin, line);
int cents1 = stoi(line);
getline(cin, line);
int dollars2 = stoi(line);
getline(cin, line);
int cents2 = stoi(line);
// TODO: Crear dos objetos Money con los valores de entrada
// TODO: Imprimir "Amount 1: " seguido de la primera cantidad mostrada
// TODO: Imprimir "Amount 2: " seguido de la segunda cantidad mostrada
// TODO: Sumar las dos cantidades e imprimir "Sum: " seguido del resultado
// TODO: Restar la segunda de la primera e imprimir "Difference: " seguido del resultado
// TODO: Usar += para sumar la segunda cantidad a la primera, luego imprimir "After +=: " seguido de la primera cantidad modificada
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosConstrucción y compilación en C++Archivos de cabecera y archivos fuenteNamespaces y alcanceIntroducción a OOP en C++Clases vs ObjetosEl puntero 'this'Métodos (Funciones miembro)Atributos (Miembros de datos)Conceptos básicos de Ctors y DtorsResumen - Calculadora simple4Propiedades de clase
Miembros de instancia vs. estáticosGetters y SettersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases amigasResumen - Gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de Ctor y DtorSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualResumen - Jerarquía de empleados2Gestión de memoria
Memoria Stack vs HeapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Resumen - Gestor de arrays dinámicos5Encapsulamiento
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultamiento de informaciónStruct vs ClassClases anidadas e internasResumen - Sistema de registros de estudiantes8Polimorfismo
Polimorfismo: Compilación vs. Tiempo de ejecuciónSobrecarga de funcionesFunciones virtuales revisadasFunciones virtuales purasClases abstractasDiseño de interfaces en C++Dynamic Casting y RTTIResumen: Calculadora de figuras11Conceptos avanzados de POO
Composición vs. HerenciaMixins mediante CRTPIdioma PimplBorrado de tiposEnum Classes y tipado fuerteManejo de excepciones en POOJerarquías de excepciones personalizadas14Patrones de diseño - Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositeRAII como patrón3Constructores y Destructores
Constructor por defectoConstructor parametrizadoConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis profundo del destructorRegla de tres / cinco / ceroResumen - Clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujo (Stream)Sobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tiposResumen - Clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasConceptos básicos de SFINAE y Type TraitsResumen - Contenedor genérico