Surcharge des opérateurs arithmétiques
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 41 sur 104.
Les opérateurs arithmétiques comme +, -, * et / sont couramment surchargés pour que les classes personnalisées se comportent comme des types numériques intégrés. Ces opérateurs renvoient généralement un nouvel objet plutôt que de modifier les opérandes.
Voici une classe Fraction avec des opérateurs arithmétiques :
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);
}
};Remarquez que les deux opérateurs sont marqués const puisqu'ils ne modifient aucun des deux opérandes. Ils créent et retournent une nouvelle Fraction avec le résultat.
Pour les opérateurs d'affectation composée comme +=, le modèle diffère. Ceux-ci modifient l'opérande de gauche et retournent une référence vers celui-ci :
Fraction& operator+=(const Fraction& other) {
numerator = numerator * other.denominator + other.numerator * denominator;
denominator = denominator * other.denominator;
return *this;
}Une pratique courante consiste à implémenter l'opérateur de base en termes d'affectation composée, réduisant ainsi la duplication de code :
Fraction operator+(const Fraction& other) const {
Fraction result = *this; // Copier cet objet
result += other; // Utiliser l'affectation composée
return result;
}Cette approche garantit que les deux opérateurs restent cohérents et facilite la maintenance.
Défi
FacileConstruisons une classe Money qui gère les calculs de devises en utilisant la surcharge des opérateurs arithmétiques. Vous implémenterez plusieurs opérateurs arithmétiques qui vous permettront de manipuler des valeurs monétaires aussi naturellement que vous le feriez avec des nombres ordinaires.
Vous créerez deux fichiers pour organiser votre code :
Money.h: Définissez une classeMoneyqui stocke un montant en cents (sous forme d'unint) pour éviter les problèmes de précision des nombres à virgule flottante. Votre classe doit prendre en charge :- Un constructeur qui prend les dollars et les cents comme des entiers distincts
- Un getter
getDollars()qui retourne la partie dollars - Un getter
getCents()qui retourne la partie cents (0-99) - Les opérateurs surchargés
+et-qui retournent un nouvel objetMoney - Les opérateurs d'affectation composée surchargés
+=et-=qui modifient l'objet actuel et retournent une référence vers celui-ci - Une méthode
display()qui affiche l'argent au format$X.YY(toujours deux chiffres pour les cents)
Implémentez les opérateurs de base (
+et-) en utilisant les opérateurs d'affectation composée pour réduire la duplication de code, comme montré dans la leçon. Tous les opérateurs arithmétiques doivent être marquésconstlorsque cela est approprié.main.cpp: Lisez quatre entiers à partir de l'entrée représentant deux montants d'argent (dollars1, cents1, dollars2, cents2 sur des lignes séparées). Créez deux objetsMoney, puis faites la démonstration de tous vos opérateurs :- Affichez
"Amount 1: "suivi du premier montant affiché - Affichez
"Amount 2: "suivi du deuxième montant affiché - Additionnez les deux montants et affichez
"Sum: "suivi du résultat - Soustrayez le deuxième du premier et affichez
"Difference: "suivi du résultat - Utilisez
+=pour ajouter le deuxième montant au premier, puis affichez"After +=: "suivi du premier montant modifié
- Affichez
Pour la méthode display(), utilisez std::setw(2) et std::setfill('0') de <iomanip> pour vous assurer que les cents affichent toujours deux chiffres (par exemple, $5.07 et non $5.7).
Convertissez les chaînes d'entrée en entiers à l'aide de std::stoi(). N'oubliez pas les gardes d'inclusion dans votre fichier d'en-tête.
Aide-mémoire
Les opérateurs arithmétiques comme +, -, * et / peuvent être surchargés pour que les classes personnalisées se comportent comme des types numériques intégrés. Ces opérateurs renvoient généralement un nouvel objet plutôt que de modifier les opérandes.
Les opérateurs arithmétiques de base doivent être marqués const car ils ne modifient aucun des deux opérandes :
Fraction operator+(const Fraction& other) const {
return Fraction(
numerator * other.denominator + other.numerator * denominator,
denominator * other.denominator
);
}Les opérateurs d'affectation composée comme += et -= modifient l'opérande de gauche et renvoient une référence à celui-ci :
Fraction& operator+=(const Fraction& other) {
numerator = numerator * other.denominator + other.numerator * denominator;
denominator = denominator * other.denominator;
return *this;
}Une pratique courante consiste à implémenter les opérateurs de base en s'appuyant sur les opérateurs d'affectation composée afin de réduire la duplication de code :
Fraction operator+(const Fraction& other) const {
Fraction result = *this; // Copier cet objet
result += other; // Utiliser l'affectation composée
return result;
}Essayez vous-même
#include <iostream>
#include <string>
#include "Money.h"
using namespace std;
int main() {
// Lire l'entrée pour deux montants d'argent
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: Créer deux objets Money avec les valeurs d'entrée
// TODO: Afficher "Amount 1: " suivi du premier montant affiché
// TODO: Afficher "Amount 2: " suivi du deuxième montant affiché
// TODO: Additionner les deux montants et afficher "Sum: " suivi du résultat
// TODO: Soustraire le deuxième du premier et afficher "Difference: " suivi du résultat
// TODO: Utiliser += pour ajouter le deuxième montant au premier, puis afficher "After +=: " suivi du premier montant modifié
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesBuild et Compilation C++Fichiers d'en-tête et Fichiers sourceEspaces de noms et PortéeIntroduction à la POO en C++Classes vs ObjetsLe pointeur 'this'Méthodes (Fonctions membres)Attributs (Membres de données)Bases des Ctors et DtorsRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d'instance vs membres statiquesGetters et SettersFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d'accès à l'héritageOrdre d'appel des Ctor et DtorRedéfinition de méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif - Hiérarchie des employés10Présentation de la STL
Présentation et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - Fréquence des mots13Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonFabrique & Fabrique abstraitePatron MonteurPatron ObservateurPatron Stratégie2Gestion de la mémoire
Mémoire Pile vs TasPointeurs et RéférencesMémoire dynamique (new/delete)Smart Pointers en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d'accès en C++Spécificateurs d'accès en profondeurMasquage d'informationStruct vs ClassClasses imbriquées et internesRécapitulatif - Système de gestion d'étudiants8Polymorphisme
Polymorphisme : Compilation vs ExécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d'interfaces en C++Dynamic Casting & RTTIRécapitulatif - Calculateur de formes11Concepts avancés de la POO
Composition vs HéritageMixins via CRTPIdiome PimplEffacement de typeEnum Classes & Typage fortGestion des exceptions en POOHiérarchies d'exceptions personnalisées14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeRAII en tant que patron3Constructeurs et Destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d'initialisation du constructeurConstructeurs déléguésAnalyse approfondie du destructeurRègle de trois / cinq / zéroRécapitulatif - Classe String6Surcharge d'opérateurs
Introduction à la surcharge d'opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l'opérateur d'affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif - Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation de templatesTemplates variadiquesBases de SFINAE & Type TraitsRécapitulatif - Conteneur générique