Menu
Coddy logo textTech

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.

challenge icon

Défi

Facile

Construisons 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 classe Wallet qui stocke des données financières privées mais permet des comparaisons entre portefeuilles. Votre classe doit comporter :
    • Membres privés : ownerName (string) et balance (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, retournant true si 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)
  • 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 Wallet avec les valeurs saisies
    • Affichez "Combined wealth: "Combined wealth: $<amount>"lt;amount>" en utilisant combinedBalance()
    • Comparez les portefeuilles et affichez "<name> has more money" pour le propriétaire qui a le solde le plus élevé (utilisez hasMoreThan() pour déterminer cela)
    • Transférez 100.0 du premier portefeuille vers le second en utilisant transferTo()
    • 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é)

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;
}
quiz iconTestez-vous

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