Occultamento delle informazioni
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 36 di 104.
L'occultamento delle informazioni va oltre il semplice utilizzo degli specificatori di accesso. È un principio di progettazione in cui nascondi non solo i dati, ma anche i dettagli di implementazione del funzionamento interno della tua classe.
L'obiettivo è esporre solo ciò che gli utenti della tua classe devono sapere, mantenendo nascosto tutto il resto. Questo ti consente di modificare l'implementazione interna senza influire sul codice che usa la tua classe:
class Temperature {
double kelvin; // Rappresentazione interna - dettaglio nascosto
public:
void setCelsius(double c) {
kelvin = c + 273.15; // Conversione nascosta all'utente
}
double getCelsius() const {
return kelvin - 273.15;
}
double getFahrenheit() const {
return (kelvin - 273.15) * 9.0/5.0 + 32;
}
};Gli utenti di questa classe non sanno (e non hanno bisogno di sapere) che la temperatura è memorizzata internamente in Kelvin. Se in seguito decidi di memorizzarla invece in Celsius, ti basta modificare l’implementazione privata: l’interfaccia pubblica rimane invariata.
Questa separazione tra interfaccia e implementazione offre diversi vantaggi: riduce la complessità per chi usa la tua classe, evita l'uso improprio accidentale dei dati interni e rende il tuo codice più facile da mantenere. Quando i dettagli interni sono nascosti, puoi ottimizzare o riorganizzare il codice senza compromettere il codice esistente che dipende dalla tua classe.
Sfida
FacileCostruiamo una classe Distance che dimostri l'incapsulamento delle informazioni memorizzando internamente le distanze in centimetri e fornendo al contempo un'interfaccia semplice per lavorare con diverse unità. Chi usa la tua classe non dovrà sapere (né preoccuparsi di) come viene memorizzata internamente la distanza: potrà semplicemente usare l'unità più comoda.
Creerai due file per organizzare il codice:
Distance.h: definisci una classeDistanceche nasconda la propria rappresentazione interna, esponendo al contempo un'interfaccia pubblica flessibile. Memorizza internamente la distanza in centimetri (comedouble). Questo è un dettaglio di implementazione nascosto. L'interfaccia pubblica deve consentire agli utenti di:- Impostare la distanza usando
setMeters(double m),setCentimeters(double cm)oppuresetKilometers(double km) - Ottenere la distanza usando
getMeters(),getCentimeters()oppuregetKilometers(): devono essere tutti metodi const - Sommare due distanze con
add(const Distance& other), che restituisce un nuovo oggettoDistance
Includi un costruttore predefinito che inizializzi la distanza a zero. La logica di conversione deve essere nascosta nei tuoi metodi: gli utenti chiamano semplicemente
setKilometers(5)egetMeters()senza preoccuparsi del formato di memorizzazione interno.- Impostare la distanza usando
main.cpp: dimostra che gli utenti possono lavorare con la tua classe senza conoscere la rappresentazione interna. Leggi due valori di distanza dall'input: il primo in metri, il secondo in chilometri. Poi:- Crea un oggetto
Distancee impostalo usando il valore in metri - Stampa
"In meters: <value> m" - Stampa
"In centimeters: <value> cm" - Stampa
"In kilometers: <value> km" - Crea un secondo oggetto
Distancee impostalo usando il valore in chilometri - Somma le due distanze e memorizza il risultato
- Stampa
"Combined in meters: <value> m"
- Crea un oggetto
Il vantaggio dell'incapsulamento delle informazioni è che in seguito potresti cambiare la memorizzazione interna da centimetri a millimetri (o a qualsiasi altra unità) senza modificare il modo in cui gli utenti interagiscono con la tua classe. L'interfaccia pubblica rimane stabile anche se l'implementazione cambia.
Formatta tutti i valori di output con due cifre decimali usando std::fixed e std::setprecision(2) di <iomanip>. Converti le stringhe di input in double usando std::stod().
Riferimento per le conversioni: 1 metro = 100 centimetri, 1 chilometro = 1000 metri.
Provalo tu
#include <iostream>
#include <string>
#include <iomanip>
#include "Distance.h"
using namespace std;
int main() {
// Leggi i valori in input
string metersInput, kmInput;
cin >> metersInput; // Primo valore in metri
cin >> kmInput; // Secondo valore in chilometri
// Converti le stringhe in valori double usando std::stod()
double metersValue = stod(metersInput);
double kmValue = stod(kmInput);
// Imposta la formattazione dell'output
cout << fixed << setprecision(2);
// TODO: Crea il primo oggetto Distance e impostalo usando il valore in metri
// TODO: Stampa "In meters: <value> m"
// TODO: Stampa "In centimeters: <value> cm"
// TODO: Stampa "In kilometers: <value> km"
// TODO: Crea il secondo oggetto Distance e impostalo usando il valore in chilometri
// TODO: Somma le due distanze usando il metodo add()
// TODO: Stampa "Combined in meters: <value> m"
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