Specificatori di accesso in dettaglio
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 35 di 104.
Ora che hai compreso i tre specificatori di accesso, scopriamo come si comportano quando hai più oggetti della stessa classe. Un malinteso comune è che private significhi «solo questo oggetto», ma in realtà significa «solo questa classe».
Gli oggetti della stessa classe possono accedere ai membri privati degli altri:
class Person {
std::string secret;
public:
Person(std::string s) : secret(s) {}
void readSecret(const Person& other) {
// Accesso al membro privato di un altro oggetto - consentito!
std::cout << other.secret;
}
};Questo funziona perché il controllo degli accessi viene applicato a livello di classe, non a livello di oggetto. Il metodo readSecret fa parte della classe Person, quindi può accedere ai membri privati di qualsiasi oggetto Person. Questa progettazione consente a operazioni come i costruttori di copia e gli operatori di confronto di lavorare con lo stato interno di altri oggetti.
Puoi anche passare da uno specificatore di accesso all'altro più volte all'interno di una classe:
class Mixed {
public:
void publicMethod1();
private:
int privateData;
public:
void publicMethod2(); // Di nuovo public
private:
void privateHelper(); // Di nuovo private
};Sebbene questo sia C++ valido, in genere è meglio raggruppare i membri in base al livello di accesso per migliorare la leggibilità. La maggior parte delle guide di stile consiglia di elencare prima i membri pubblici (poiché costituiscono l’interfaccia della classe), poi quelli protetti e infine quelli privati.
Sfida
FacileCostruiamo un sistema di confronto tra portafogli che mostri come oggetti della stessa classe possano accedere ai membri privati degli altri oggetti. Questo è un aspetto fondamentale del controllo degli accessi in C++: viene applicato a livello di classe, non di oggetto.
Creerai due file per organizzare il codice:
Wallet.h: definisci una classeWalletche memorizza dati finanziari privati, ma consente confronti tra portafogli. La classe dovrebbe avere:- Membri privati:
ownerName(stringa) ebalance(double) - Un costruttore che accetta il nome del proprietario e il saldo iniziale
- Un getter pubblico
getOwnerName()che restituisce il nome del proprietario - Un metodo
hasMoreThan(const Wallet& other)che confronta il saldo di questo portafoglio con il saldo privato di un altro portafoglio e restituiscetruese questo portafoglio ha più denaro - Un metodo
combinedBalance(const Wallet& other)che restituisce la somma dei saldi privati di entrambi i portafogli - Un metodo
transferTo(Wallet& other, double amount)che trasferisce denaro da questo portafoglio a un altro. Dovrebbe modificare direttamente i saldi privati di entrambi i portafogli (solo se l'importo è positivo e non supera il saldo di questo portafoglio)
- Membri privati:
main.cpp: mostra l'accesso ai membri privati di un altro oggetto. Leggi dall'input due nomi di proprietari e due saldi (quattro righe: name1, balance1, name2, balance2), poi:- Crea due oggetti
Walletcon i valori inseriti - Stampa
"Combined wealth: $<amount>"usandocombinedBalance() - Confronta i portafogli e stampa
"<name> has more money"per il proprietario con il saldo più alto (usahasMoreThan()per stabilirlo) - Trasferisci
100.0dal primo portafoglio al secondo usandotransferTo() - Stampa
"After transfer:" - Stampa di nuovo
"Combined wealth: $<amount>"(dovrebbe rimanere invariato) - Confronta di nuovo e stampa
"<name> has more money"(il risultato potrebbe essere cambiato)
- Crea due oggetti
Il concetto chiave è che metodi come hasMoreThan() e transferTo() possono accedere direttamente al membro privato balance di un altro oggetto Wallet: non servono getter. Questo è possibile perché il controllo degli accessi in C++ è basato sulla classe: qualsiasi codice all'interno della classe Wallet può accedere ai membri privati di qualsiasi oggetto Wallet.
Formatta tutti gli importi con due cifre decimali usando std::fixed e std::setprecision(2) da <iomanip>. Converti i valori dei saldi in input usando std::stod().
Provalo tu
#include <iostream>
#include <string>
#include <iomanip>
#include "Wallet.h"
using namespace std;
int main() {
// Leggi l'input: name1, balance1, name2, balance2
string name1, name2;
string balanceStr1, balanceStr2;
getline(cin, name1);
getline(cin, balanceStr1);
getline(cin, name2);
getline(cin, balanceStr2);
double balance1 = stod(balanceStr1);
double balance2 = stod(balanceStr2);
// Imposta il formato di output per i valori monetari
cout << fixed << setprecision(2);
// TODO: Crea due oggetti Wallet con i valori di input
// TODO: Stampa il patrimonio complessivo usando combinedBalance()
// Formato: "Combined wealth: $<amount>"
// TODO: Confronta i portafogli usando hasMoreThan() e stampa chi ha più denaro
// Formato: "<name> has more money"
// TODO: Trasferisci 100.0 dal primo portafoglio al secondo usando transferTo()
// TODO: Stampa "After transfer:"
// TODO: Stampa di nuovo il patrimonio complessivo
// TODO: Confronta di nuovo i portafogli e stampa chi ha più denaro
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