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, examinons leur comportement lorsque vous avez plusieurs objets de la même classe. Une idée reçue courante est que private signifie « uniquement cet objet » — mais cela signifie en réalité « uniquement 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éder 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 tout objet Person. Cette conception permet à des opérations telles que les constructeurs de copie et les opérateurs de comparaison de fonctionner avec l’état interne d’autres objets.
Vous pouvez également alterner plusieurs fois entre les spécificateurs d’accès au sein d’une classe :
class Mixed {
public:
void publicMethod1();
private:
int privateData;
public:
void publicMethod2(); // Retour au public
private:
void privateHelper(); // Privé à nouveau
};Bien que ce soit du C++ valide, il est généralement préférable de regrouper les membres par niveau d’accès pour améliorer la lisibilité. La plupart des guides de style recommandent de lister d’abord les membres publics (puisqu’ils constituent l’interface de la classe), suivis des membres protégés, puis des membres privés.
Défi
FacileConstruisons un système de comparaison de portefeuilles qui montre comment des objets de la même classe peuvent accéder aux membres privés les uns des autres. Il s’agit d’un point essentiel concernant le contrôle d’accès de C++ : il est appliqué au niveau de la classe, et non au niveau de l’objet.
Vous allez créer deux fichiers pour organiser votre code :
Wallet.h: définissez une classeWalletqui stocke des données financières privées, mais permet les comparaisons entre portefeuilles. Votre classe doit comporter :- Membres privés :
ownerName(chaîne de caractères) etbalance(double) - Un constructeur qui prend le nom du propriétaire et le solde initial
- Un accesseur public
getOwnerName()qui renvoie le nom du propriétaire - Une méthode
hasMoreThan(const Wallet& other)qui compare le solde de ce portefeuille au solde privé d’un autre portefeuille et renvoietruesi ce portefeuille contient davantage d’argent - Une méthode
combinedBalance(const Wallet& other)qui renvoie 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 depuis l’entrée (quatre lignes : name1, balance1, name2, balance2), puis :- Créez deux objets
Walletavec les valeurs saisies - Affichez
"Combined wealth: $<amount>"à l’aide decombinedBalance() - Comparez les portefeuilles et affichez
"<name> has more money"pour le propriétaire dont le solde est le plus élevé (utilisezhasMoreThan()pour le déterminer) - Transférez
100.0du premier portefeuille vers le second à l’aide detransferTo() - Affichez
"After transfer:" - Affichez à nouveau
"Combined wealth: $<amount>"(le résultat doit être inchangé) - Comparez à nouveau et affichez
"<name> has more money"(le résultat peut avoir changé)
- Créez deux objets
Le concept essentiel ici est que des méthodes comme hasMoreThan() et transferTo() peuvent accéder directement au membre privé Wallet d’un autre objet balance : aucun accesseur n’est nécessaire. Cela fonctionne parce que le contrôle d’accès en C++ est fondé sur la classe : tout code situé à 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 à l’aide de std::stod().
Essayez vous-même
#include <iostream>
#include <string>
#include <iomanip>
#include "Wallet.h"
using namespace std;
int main() {
// Lire l'entrée : 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: Print combined wealth using combinedBalance()
// Format: "Combined wealth: $<amount>"
// TODO: Compare wallets using hasMoreThan() and print who has more money
// Format: "<name> has more money"
// TODO: Transférer 100.0 du premier wallet au second en utilisant transferTo()
// TODO: Print "After transfer:"
// TODO: Print combined wealth again
// TODO: Compare again and print who has more money
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 externesGénération et compilation en C++Fichiers d’en-tête et fichiers sourceEspaces de noms et portéeIntroduction à la POO en C++Classes et objetsLe pointeur « this »Méthodes (fonctions membres)Attributs (membres de données)Bases des constructeurs et destructeursRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d’instance et statiquesAccesseurs et mutateursFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d’accès de l’héritageOrdre d’appel des constructeurs et destructeursRedéfinition des méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif : hiérarchie des employés10Vue d’ensemble de la STL
Vue d’ensemble et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - fréquence des mots13Modèles de conception, partie 1
Introduction aux modèles de conceptionModèle SingletonFabrique et fabrique abstraiteModèle BuilderModèle ObserverModèle Strategy2Gestion de la mémoire
Mémoire de pile ou de tasPointeurs et référencesMémoire dynamique (new/delete)Pointeurs intelligents 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 de l’informationStruct vs classeClasses imbriquées et internesRécapitulatif - Système de gestion des dossiers étudiants8Polymorphisme
Polymorphisme à la compilation vs à l’exécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d’interfaces en C++Conversion dynamique et RTTIRécapitulatif - Calculateur de formes3Constructeurs et destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d’initialisation des constructeursConstructeurs déléguésApprofondissement des destructeursRègle des trois / cinq / zéroRécapitulatif - Classe String6Surcharge des opérateurs
Introduction à la surcharge des 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 des templatesTemplates variadiquesBases de SFINAE et des traits de typesRécapitulatif - Conteneur génériqueEntraînez-vous par vous-même : Compilateur C++ en ligne