Spécificateurs d'accès en profondeur
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 35 sur 104.
Maintenant que vous comprenez les trois spécificateurs d'accès, explorons comment ils se comportent lorsque vous avez plusieurs objets de la même classe. Une idée fausse courante est que private signifie « seulement cet objet » — mais cela signifie en réalité « seulement cette classe ».
Les objets d'une même classe peuvent accéder aux membres privés les uns des autres :
class Person {
std::string secret;
public:
Person(std::string s) : secret(s) {}
void readSecret(const Person& other) {
// Accès au membre privé d'un autre objet - autorisé !
std::cout << other.secret;
}
};Cela fonctionne parce que le contrôle d'accès est appliqué au niveau de la classe, et non au niveau de l'objet. La méthode readSecret fait partie de la classe Person, elle peut donc accéder aux membres privés de n'importe quel objet Person. Cette conception permet à des opérations telles que les constructeurs de recopie et les opérateurs de comparaison de manipuler l'état interne d'autres objets.
Vous pouvez également basculer entre les spécificateurs d'accès plusieurs fois au sein d'une classe :
class Mixed {
public:
void publicMethod1();
private:
int privateData;
public:
void publicMethod2(); // De nouveau public
private:
void privateHelper(); // De nouveau privé
};Bien que cela soit du C++ valide, il est généralement préférable de regrouper les membres par niveau d'accès pour la lisibilité. La plupart des guides de style recommandent de lister les membres public en premier (puisqu'ils forment l'interface de la classe), suivis de protected, puis private.
Défi
FacileConstruisons un système de comparaison de portefeuilles qui démontre comment les objets d'une même classe peuvent accéder aux membres privés les uns des autres. C'est un aspect essentiel du contrôle d'accès en C++ — il est appliqué au niveau de la classe, et non au niveau de l'objet.
Vous créerez deux fichiers pour organiser votre code :
Wallet.h: Définissez une classeWalletqui stocke des données financières privées mais permet des comparaisons entre portefeuilles. Votre classe doit comporter :- Membres privés :
ownerName(string) etbalance(double) - Un constructeur qui prend le nom du propriétaire et le solde initial
- Un getter public
getOwnerName()qui retourne le nom du propriétaire - Une méthode
hasMoreThan(const Wallet& other)qui compare le solde de ce portefeuille avec le solde privé d'un autre portefeuille, retournanttruesi ce portefeuille a plus d'argent - Une méthode
combinedBalance(const Wallet& other)qui retourne la somme des soldes privés des deux portefeuilles - Une méthode
transferTo(Wallet& other, double amount)qui transfère de l'argent de ce portefeuille vers un autre — elle doit modifier directement les soldes privés des deux portefeuilles (uniquement si le montant est positif et ne dépasse pas le solde de ce portefeuille)
- Membres privés :
main.cpp: Démontrez l'accès aux membres privés entre objets. Lisez deux noms de propriétaires et deux soldes à partir de l'entrée (quatre lignes : name1, balance1, name2, balance2), puis :- Créez deux objets
Walletavec les valeurs saisies - Affichez
"Combined wealth: "Combined wealth: $<amount>"lt;amount>"en utilisantcombinedBalance() - Comparez les portefeuilles et affichez
"<name> has more money"pour le propriétaire qui a le solde le plus élevé (utilisezhasMoreThan()pour déterminer cela) - Transférez
100.0du premier portefeuille vers le second en utilisanttransferTo() - Affichez
"After transfer:" - Affichez à nouveau
"Combined wealth: "Combined wealth: $<amount>"lt;amount>"(cela ne devrait pas avoir changé) - Comparez à nouveau et affichez
"<name> has more money"(le résultat peut avoir changé)
- Créez deux objets
Le concept clé ici est que des méthodes comme hasMoreThan() et transferTo() peuvent accéder directement au membre privé balance d'un autre objet Wallet — aucun getter n'est nécessaire. Cela fonctionne car le contrôle d'accès en C++ est basé sur la classe : tout code à l'intérieur de la classe Wallet peut accéder aux membres privés de n'importe quel objet Wallet.
Formatez toutes les valeurs monétaires avec deux décimales en utilisant std::fixed et std::setprecision(2) de <iomanip>. Convertissez les entrées de solde en utilisant std::stod().
Aide-mémoire
Le contrôle d'accès en C++ est appliqué au niveau de la classe, et non au niveau de l'objet. Cela signifie que les objets d'une même classe peuvent accéder aux membres privés les uns des autres :
class Person {
std::string secret;
public:
Person(std::string s) : secret(s) {}
void readSecret(const Person& other) {
// Accès au membre privé d'un autre objet - autorisé !
std::cout << other.secret;
}
};La méthode readSecret peut accéder au membre privé secret de n'importe quel objet Person car elle fait partie de la classe Person. Cette conception permet des opérations telles que les constructeurs de copie et les opérateurs de comparaison.
Vous pouvez basculer entre les spécificateurs d'accès plusieurs fois au sein d'une classe :
class Mixed {
public:
void publicMethod1();
private:
int privateData;
public:
void publicMethod2(); // Retour au public
private:
void privateHelper(); // De nouveau privé
};Cependant, il est préférable de regrouper les membres par niveau d'accès pour une meilleure lisibilité. La plupart des guides de style recommandent de lister d'abord les membres publics, suivis des membres protégés, puis des membres privés.
Essayez vous-même
#include <iostream>
#include <string>
#include <iomanip>
#include "Wallet.h"
using namespace std;
int main() {
// Lire les entrées : 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);
// Définir le formatage de sortie pour les valeurs monétaires
cout << fixed << setprecision(2);
// TODO: Créer deux objets Wallet avec les valeurs d'entrée
// TODO: Afficher la richesse combinée en utilisant combinedBalance()
// Format : "Combined wealth: $<amount>"
// TODO: Comparer les portefeuilles en utilisant hasMoreThan() et afficher qui a le plus d'argent
// Format : "<name> has more money"
// TODO: Transférer 100.0 du premier portefeuille vers le second en utilisant transferTo()
// TODO: Afficher "After transfer:"
// TODO: Afficher à nouveau la richesse combinée
// TODO: Comparer à nouveau et afficher qui a le plus d'argent
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