Sovraccarico degli operatori aritmetici
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 41 di 104.
Gli operatori aritmetici come +, -, * e / vengono comunemente sovraccaricati per far sì che le classi personalizzate si comportino come i tipi numerici integrati. Questi operatori in genere restituiscono un nuovo oggetto anziché modificare gli operandi.
Ecco una classe Fraction con operatori aritmetici:
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);
}
};Nota che entrambi gli operatori sono contrassegnati come const poiché non modificano nessuno dei due operandi. Creano e restituiscono una nuova Fraction con il risultato.
Per gli operatori di assegnazione composta come +=, il modello è diverso. Questi modificano l'operando sinistro e restituiscono un riferimento a esso:
Fraction& operator+=(const Fraction& other) {
numerator = numerator * other.denominator + other.numerator * denominator;
denominator = denominator * other.denominator;
return *this;
}Una pratica comune consiste nell'implementare l'operatore di base in termini dell'assegnazione composta, riducendo la duplicazione del codice:
Fraction operator+(const Fraction& other) const {
Fraction result = *this; // Copia questo oggetto
result += other; // Usa l'assegnazione composta
return result;
}Questo approccio garantisce la coerenza di entrambi gli operatori e semplifica la manutenzione.
Sfida
FacileCreiamo una classe Money che gestisce i calcoli monetari usando l’overloading degli operatori aritmetici. Implementerai diversi operatori aritmetici che ti permetteranno di lavorare con valori monetari con la stessa naturalezza con cui lavori con i numeri normali.
Creerai due file per organizzare il codice:
Money.h: Definisci una classeMoneyche memorizza un importo in centesimi (comeint) per evitare problemi di precisione con i numeri in virgola mobile. La tua classe deve supportare:- Un costruttore che accetta dollari e centesimi come interi separati
- Un getter
getDollars()che restituisce la parte in dollari - Un getter
getCents()che restituisce la parte in centesimi (0-99) - Gli operatori
+e-sovraccaricati, che restituiscono un nuovo oggettoMoney - Gli operatori di assegnazione composta
+=e-=sovraccaricati, che modificano l’oggetto corrente e restituiscono un riferimento a esso - Un metodo
display()che stampa l’importo nel formato$X.YY(sempre due cifre per i centesimi)
Implementa gli operatori di base (
+e-) usando gli operatori di assegnazione composta, per ridurre la duplicazione del codice, come mostrato nella lezione. Tutti gli operatori aritmetici devono essere contrassegnati comeconstquando opportuno.main.cpp: Leggi quattro interi dall’input, che rappresentano due importi monetari (dollars1, cents1, dollars2, cents2 su righe separate). Crea due oggettiMoney, poi mostra il funzionamento di tutti gli operatori:- Stampa
"Amount 1: "seguito dal primo importo visualizzato - Stampa
"Amount 2: "seguito dal secondo importo visualizzato - Somma i due importi e stampa
"Sum: "seguito dal risultato - Sottrai il secondo dal primo e stampa
"Difference: "seguito dal risultato - Usa
+=per aggiungere il secondo importo al primo, poi stampa"After +=: "seguito dal primo importo modificato
- Stampa
Per il metodo display(), usa std::setw(2) e std::setfill('0') di <iomanip> per assicurarti che i centesimi siano sempre visualizzati con due cifre (ad es., $5.07 e non $5.7).
Converti le stringhe di input in interi usando std::stoi(). Non dimenticare le protezioni contro le inclusioni multiple nel file header.
Provalo tu
#include <iostream>
#include <string>
#include "Money.h"
using namespace std;
int main() {
// Leggi i dati di input per due importi di denaro
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: Crea due oggetti Money con i valori di input
// TODO: Stampa "Amount 1: " seguito dal primo importo visualizzato
// TODO: Stampa "Amount 2: " seguito dal secondo importo visualizzato
// TODO: Somma i due importi e stampa "Sum: " seguito dal risultato
// TODO: Sottrai il secondo importo dal primo e stampa "Difference: " seguito dal risultato
// TODO: Usa += per aggiungere il secondo importo al primo, poi stampa "After +=: " seguito dal primo importo modificato
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniBuild e compilazione in C++File header e file sorgenteNamespace e ambitoIntroduzione alla programmazione orientata agli oggetti in C++Classi e oggetti a confrontoIl puntatore 'this'Metodi (funzioni membro)Attributi (membri dati)Fondamenti di costruttori e distruttoriRiepilogo - Calcolatrice semplice4Proprietà delle classi
Membri di istanza e staticiGetter e setterFunzioni membro constParola chiave mutableMetodi e variabili staticiFunzioni e classi friendRiepilogo - Gestore di conti bancari7Ereditarietà
Ereditarietà di baseLivelli di accesso nell’ereditarietàOrdine di chiamata di costruttori e distruttoriRidefinizione dei metodiFunzioni virtuali e VTableEreditarietà multiplaEreditarietà virtualeRiepilogo - Gerarchia dei dipendenti2Gestione della memoria
Memoria Stack vs HeapPuntatori e riferimentiMemoria dinamica (new/delete)Puntatori intelligenti in C++RAII in C++Riepilogo - Gestore di array dinamico5Incapsulamento
Specificatori di accesso in C++Specificatori di accesso in dettaglioOccultamento delle informazioniStruct vs classClassi annidate e interneRiepilogo - Sistema di registrazione degli studenti8Polimorfismo
Polimorfismo a compile time e a runtimeOverload delle funzioniFunzioni virtuali: ripassoFunzioni virtuali pureClassi astratteProgettazione delle interfacce in C++Dynamic casting e RTTIRipasso: calcolatrice di forme11Concetti avanzati di OOP
Composizione vs ereditarietàMixin tramite CRTPIdiom PimplType ErasureEnum class e tipizzazione forteGestione delle eccezioni in OOPGerarchie personalizzate di eccezioni14Pattern di progettazione - Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeRAII come pattern3Costruttori e distruttori
Costruttore predefinitoCostruttore con parametriCostruttore di copiaCostruttore di spostamentoListe di inizializzazione dei costruttoriCostruttori delegantiApprofondimento sui distruttoriRegola del Tre / Cinque / ZeroRipasso - classe String6Sovraccarico degli operatori
Introduzione al sovraccarico degli operatoriSovraccarico degli operatori aritmeticiSovraccarico degli operatori di confrontoOperatori di flussoSovraccarico dell'operatore di assegnazioneSovraccarico degli operatori [] e ()Operatori di conversione di tipoRipasso - Classe Matrix9Template
Template di funzioneTemplate di classeSpecializzazione dei templateTemplate variadiciBasi di SFINAE e dei trait di tipoRiepilogo - Contenitore genericoEsercitati da solo: Compilatore C++ online