Arithmetische Operatorüberladung
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 41 von 104.
Arithmetische Operatoren wie +, -, * und / werden häufig überladen, damit sich benutzerdefinierte Klassen wie integrierte numerische Typen verhalten. Diese Operatoren geben in der Regel ein neues Objekt zurück, anstatt die Operanden zu ändern.
Hier ist eine Fraction-Klasse mit arithmetischen Operatoren:
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);
}
};Beachten Sie, dass beide Operatoren als const markiert sind, da sie keinen der Operanden verändern. Sie erstellen und geben ein neues Fraction mit dem Ergebnis zurück.
Für Verbundzuweisungsoperatoren wie += unterscheidet sich das Muster. Diese modifizieren den linken Operanden und geben eine Referenz darauf zurück:
Fraction& operator+=(const Fraction& other) {
numerator = numerator * other.denominator + other.numerator * denominator;
denominator = denominator * other.denominator;
return *this;
}Eine gängige Praxis besteht darin, den Basisoperator auf Basis der Verbundzuweisung zu implementieren, um Codeduplizierung zu reduzieren:
Fraction operator+(const Fraction& other) const {
Fraction result = *this; // Dieses Objekt kopieren
result += other; // Verbundzuweisung verwenden
return result;
}Dieser Ansatz stellt sicher, dass beide Operatoren konsistent bleiben und erleichtert die Wartung.
Aufgabe
EinfachLassen Sie uns eine Money-Klasse erstellen, die Währungsberechnungen mittels Überladung von arithmetischen Operatoren verarbeitet. Sie werden mehrere arithmetische Operatoren implementieren, mit denen Sie mit Geldwerten so natürlich arbeiten können wie mit normalen Zahlen.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
Money.h: Definieren Sie eineMoney-Klasse, die einen Betrag in Cents (alsint) speichert, um Probleme mit der Fließkommapräzision zu vermeiden. Ihre Klasse sollte Folgendes unterstützen:- Einen Konstruktor, der Dollar und Cents als separate Ganzzahlen entgegennimmt
- Einen Getter
getDollars(), der den Dollar-Anteil zurückgibt - Einen Getter
getCents(), der den Cent-Anteil zurückgibt (0-99) - Überladene
+und-Operatoren, die ein neuesMoney-Objekt zurückgeben - Überladene
+=und-=Verbundzuweisungsoperatoren, die das aktuelle Objekt ändern und eine Referenz darauf zurückgeben - Eine
display()-Methode, die den Geldbetrag im Format$X.YYausgibt (immer zwei Stellen für Cents)
Implementieren Sie die Basisoperatoren (
+und-) unter Verwendung der Verbundzuweisungsoperatoren, um Code-Duplizierung zu reduzieren, wie in der Lektion gezeigt. Alle arithmetischen Operatoren sollten, wo angemessen, alsconstmarkiert werden.main.cpp: Lesen Sie vier Ganzzahlen von der Eingabe ein, die zwei Geldbeträge repräsentieren (dollars1, cents1, dollars2, cents2 in separaten Zeilen). Erstellen Sie zweiMoney-Objekte und demonstrieren Sie dann alle Ihre Operatoren:- Geben Sie
"Amount 1: "gefolgt vom ersten angezeigten Betrag aus - Geben Sie
"Amount 2: "gefolgt vom zweiten angezeigten Betrag aus - Addieren Sie die beiden Beträge und geben Sie
"Sum: "gefolgt vom Ergebnis aus - Subtrahieren Sie den zweiten vom ersten und geben Sie
"Difference: "gefolgt vom Ergebnis aus - Verwenden Sie
+=, um den zweiten Betrag zum ersten zu addieren, und geben Sie dann"After +=: "gefolgt vom geänderten ersten Betrag aus
- Geben Sie
Verwenden Sie für die display()-Methode std::setw(2) und std::setfill('0') aus <iomanip>, um sicherzustellen, dass Cents immer zweistellig angezeigt werden (z. B. $5.07 statt $5.7).
Konvertieren Sie Eingabestrings mit std::stoi() in Ganzzahlen. Vergessen Sie nicht die Header-Guards in Ihrer Header-Datei.
Spickzettel
Arithmetische Operatoren wie +, -, * und / können überladen werden, damit sich benutzerdefinierte Klassen wie integrierte numerische Typen verhalten. Diese Operatoren geben normalerweise ein neues Objekt zurück, anstatt die Operanden zu verändern.
Grundlegende arithmetische Operatoren sollten als const markiert werden, da sie keinen der Operanden verändern:
Fraction operator+(const Fraction& other) const {
return Fraction(
numerator * other.denominator + other.numerator * denominator,
denominator * other.denominator
);
}Zusammengesetzte Zuweisungsoperatoren wie += und -= verändern den linken Operanden und geben eine Referenz darauf zurück:
Fraction& operator+=(const Fraction& other) {
numerator = numerator * other.denominator + other.numerator * denominator;
denominator = denominator * other.denominator;
return *this;
}Eine gängige Praxis ist es, grundlegende Operatoren mithilfe von zusammengesetzten Zuweisungsoperatoren zu implementieren, um Code-Duplizierung zu reduzieren:
Fraction operator+(const Fraction& other) const {
Fraction result = *this; // Dieses Objekt kopieren
result += other; // Zusammengesetzte Zuweisung verwenden
return result;
}Probier es selbst
#include <iostream>
#include <string>
#include "Money.h"
using namespace std;
int main() {
// Eingabe für zwei Geldbeträge lesen
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: Zwei Money-Objekte mit den Eingabewerten erstellen
// TODO: "Amount 1: " gefolgt vom ersten angezeigten Betrag ausgeben
// TODO: "Amount 2: " gefolgt vom zweiten angezeigten Betrag ausgeben
// TODO: Die beiden Beträge addieren und "Sum: " gefolgt vom Ergebnis ausgeben
// TODO: Den zweiten vom ersten Betrag subtrahieren und "Difference: " gefolgt vom Ergebnis ausgeben
// TODO: += verwenden, um den zweiten Betrag zum ersten zu addieren, dann "After +=: " gefolgt vom geänderten ersten Betrag ausgeben
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container