Menu
Coddy logo textTech

Fonctions et classes amies

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 32 sur 104.

Parfois, une fonction ou une classe en dehors de votre classe a besoin d'accéder à ses membres privés. Plutôt que de rendre ces membres publics, le C++ fournit le mot-clé friend pour accorder un accès sélectif tout en maintenant l'encapsulation.

Une fonction amie est déclarée à l'intérieur d'une classe mais n'est pas un membre de cette classe. Elle peut accéder aux membres privés et protégés de la classe :

class Box {
    double width;
    
public:
    Box(double w) : width(w) {}
    
    // Déclarer printWidth comme amie
    friend void printWidth(const Box& b);
};

// Définition de la fonction amie - n'est PAS une fonction membre
void printWidth(const Box& b) {
    std::cout << b.width;    // Peut accéder au membre privé
}

Notez que printWidth est définie en dehors de la classe sans l'opérateur de résolution de portée. C'est une fonction régulière qui se trouve avoir des privilèges d'accès spéciaux.

Vous pouvez également déclarer une classe entière comme amie, accordant à toutes ses fonctions membres l'accès aux membres privés :

class Engine {
    int horsepower;
    
    friend class Mechanic;    // Mechanic peut accéder aux membres privés
    
public:
    Engine(int hp) : horsepower(hp) {}
};

class Mechanic {
public:
    void diagnose(const Engine& e) {
        std::cout << e.horsepower;    // Autorisé - Mechanic est un ami
    }
};

L'amitié n'est pas mutuelle - si Engine déclare Mechanic comme ami, Mechanic peut accéder aux membres privés de Engine, mais pas l'inverse. Utilisez les amis avec parcimonie, car ils créent un couplage étroit entre les classes. Ils sont particulièrement utiles pour la surcharge d'opérateurs et les fonctions d'aide étroitement liées.

challenge icon

Défi

Facile

Construisons un système de messagerie sécurisé où une classe MessageReader a besoin d'un accès spécial pour lire des messages cryptés stockés dans une classe SecureMessage. C'est un scénario parfait pour utiliser des fonctions amies (friend functions) et des classes amies (friend classes).

Vous allez créer deux fichiers pour organiser votre code :

  • SecureMessage.h : Définissez une classe SecureMessage qui stocke des données de message privées et accorde un accès sélectif aux entités de confiance. Votre classe doit avoir :
    • Membres privés : content (string) et secretKey (int)
    • Un constructeur qui prend le contenu et la clé secrète
    • Déclarez MessageReader comme une classe amie afin qu'elle puisse accéder aux membres privés
    • Déclarez une fonction amie decryptMessage(const SecureMessage& msg, int key) qui renvoie le contenu uniquement si la clé fournie correspond à la clé secrète, sinon elle renvoie "Access Denied"

    Ensuite, définissez la classe MessageReader dans le même fichier d'en-tête :

    • Une méthode readContent(const SecureMessage& msg) qui accède directement et renvoie le content privé du message
    • Une méthode verifyKey(const SecureMessage& msg, int key) qui vérifie si la clé fournie correspond à la secretKey du message et renvoie "Valid" ou "Invalid"

    Enfin, définissez la fonction amie decryptMessage après les classes.

  • main.cpp : Démontrez l'utilisation des fonctions amies et des classes amies. Lisez un contenu de message, une clé secrète et une clé de test à partir de l'entrée (chacun sur une ligne séparée), puis :
    • Créez un SecureMessage avec le contenu et la clé secrète
    • Créez un objet MessageReader
    • Affichez "Reader access: <content>" en utilisant la méthode readContent() du lecteur
    • Affichez "Key verification: <result>" en utilisant verifyKey() avec la clé de test
    • Affichez "Decrypt with test key: <result>" en utilisant la fonction amie avec la clé de test
    • Affichez "Decrypt with correct key: <result>" en utilisant la fonction amie avec la clé secrète d'origine

Rappelez-vous que les fonctions amies sont définies en dehors de la classe sans l'opérateur de résolution de portée — ce sont des fonctions régulières avec des privilèges d'accès spéciaux. La classe MessageReader, étant une amie, peut accéder directement aux membres privés de SecureMessage dans toutes ses méthodes.

Convertissez les entrées de clé de chaînes de caractères en entiers en utilisant std::stoi(). Incluez votre fichier d'en-tête dans main.cpp en utilisant #include "SecureMessage.h".

Aide-mémoire

Le mot-clé friend accorde un accès sélectif aux membres privés tout en maintenant l'encapsulation.

Fonction amie : Une fonction déclarée à l'intérieur d'une classe qui peut accéder à ses membres privés et protégés, mais qui n'est pas un membre de la classe :

class Box {
    double width;
    
public:
    Box(double w) : width(w) {}
    
    // Déclarer une fonction amie
    friend void printWidth(const Box& b);
};

// Définir en dehors de la classe sans l'opérateur de résolution de portée
void printWidth(const Box& b) {
    std::cout << b.width;    // Peut accéder au membre privé
}

Classe amie : Une classe entière peut être déclarée comme amie, accordant à toutes ses fonctions membres l'accès aux membres privés :

class Engine {
    int horsepower;
    
    friend class Mechanic;    // Toutes les méthodes de Mechanic peuvent accéder aux membres privés
    
public:
    Engine(int hp) : horsepower(hp) {}
};

class Mechanic {
public:
    void diagnose(const Engine& e) {
        std::cout << e.horsepower;    // Autorisé
    }
};

Points clés :

  • L'amitié n'est pas mutuelle - si A déclare B comme ami, B peut accéder aux membres privés de A, mais pas l'inverse
  • Les fonctions amies sont définies en dehors de la classe sans l'opérateur de résolution de portée
  • Utilisez les fonctions amies avec parcimonie car elles créent un couplage étroit entre les classes
  • Très utile pour la surcharge d'opérateurs et les fonctions utilitaires étroitement liées

Essayez vous-même

#include <iostream>
#include <string>
#include "SecureMessage.h"
using namespace std;

int main() {
    // Lire l'entrée
    string messageContent;
    string secretKeyStr;
    string testKeyStr;
    
    getline(cin, messageContent);
    getline(cin, secretKeyStr);
    getline(cin, testKeyStr);
    
    int secretKey = stoi(secretKeyStr);
    int testKey = stoi(testKeyStr);
    
    // TODO: Créer un SecureMessage avec le contenu et la clé secrète (secret key)
    
    // TODO: Créer un objet MessageReader
    
    // TODO: Afficher "Reader access: <content>" en utilisant readContent()
    
    // TODO: Afficher "Key verification: <result>" en utilisant verifyKey() avec la clé de test (test key)
    
    // TODO: Afficher "Decrypt with test key: <result>" en utilisant decryptMessage avec la clé de test (test key)
    
    // TODO: Afficher "Decrypt with correct key: <result>" en utilisant decryptMessage avec la clé secrète (secret key)
    
    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