L'Évolution des Amis (friend) en C++ de C++11 à C++23

Au cours de l'évolution du C++ de C++11 à C++23, la définition centrale du mot-clé friend (accès privilégié) n'a pas radicalement changé, mais sa flexibilité syntaxique, sa gestion avec les templates et sa sécurité d'encapsulation ont été considérablement renforcées.

Nous pouvons examiner les améliorations apportées à la notion d'ami (friend) sous quatre angles :

  1. Simplification syntaxique : le mot-clé class/struct n'est plus obligatoire (C++11)

En C++ traditionnel (C++98), pour déclarer une classe comme amie, il fallait utiliser le mot-clé class ou struct.

  • Ancienne syntaxe : friend class Vector;
  • Nouvelle syntaxe : friend Vector;

Cette amélioration, bien que mineure en apparence, résout le problème des alias de types (typedef/using) qui ne pouvaient pas être déclarés amis auparavant.

Pourquoi est-ce important ?

En C++ moderne, nous utilisons souvent using pour définir des types complexes. Avant C++11, on ne pouvait pas déclarer un alias comme ami ; désormais c'est possible :

using MatriceGlobale = Matrice<double, 4, 4>;

class AnalyseurMateriel {
    friend MatriceGlobale;  // Autorisé en C++11, erreur avant
};


  1. Amélioration des amis template (C++11)

C'est l'une des améliorations les plus pratiques du C++ moderne : l'ami paramétré par un template.

Dans l'ancien standard, on ne pouvait pas déclarer un paramètre de template comme ami, car le compilateur ne savait pas ce qu'était T lors de la définition de la classe. C++11 a introduit la syntaxe friend T;.

Cas d'usage : pattern singleton ou usine (factory)

Imaginons que vous écriviez une bibliothèque et que vous souhaitiez qu'une classe définie par l'utilisateur T puisse accéder à un constructeur privé interne :

template <typename Type>
class OctroiAccesseur {
private:
    OctroiAccesseur() {}  // Constructeur privé
    
    friend Type;  // Le paramètre template est déclaré ami
};

class Cliente : public OctroiAccesseur<Cliente> {
    // En tant qu'ami, Cliente peut accéder au constructeur privé d'OctroiAccesseur
};


  1. Amis contraints : association avec les Concepts (C++20)

C++20 a intorduit les Concepts, ce qui a changé la façon d'écrire les templates. Bien que la syntaxe de déclaration d'ami n'ait pas changé, on peut maintenant utiliser la clause requires pour restreindre qui peut devenir ami, ou pour contraindre les fonctions amies.

Cela répond au problème que "l'ami est trop puissant". On peut déclarer une fonction amie, mais exiger que ses opérandes satisfassent certaines conditions (par exemple, être std::incrementable).

  1. Popularisation des amis cachés (Hidden Friends)

Ce n'est pas un changement syntaxique imposé, mais un schéma de conception privilégié par le C++ moderne (notamment dans les bibliothèques fortement templatisées comme la bibliothèque standard elle-même).

Qu'est-ce qu'un ami caché ?

Il s'agit de définir (pas seulement déclarer) une fonction amie directement à l'intérieur de la définition de la classe.

class Fraction {
    int numerateur, denominateur;
public:
    // Voici un ami caché
    friend bool operator==(const Fraction& gauche, const Fraction& droite) {
        return gauche.numerateur == droite.numerateur && 
               gauche.denominateur == droite.denominateur;
    }
};


Quels sont les bénéfices ?

  1. Vitesse de compilation : un ami caché ne peut être trouvé que par ADL (Argument-Dependent Lookup). Le compilateur n'a pas besoin de parcourir des milliers de fonctions dans l'espace de noms global ; il cherche uniquement dans la classe des arguments.
  2. Évite la pollution : il ne peut pas être appelé accidentellement par des types non apparentés, réduisant les risques de conflits de noms.
  3. Encapsulation renforcée : bien qu'il soit ami, il est invisible en dehors de la portée de la classe (sauf via ses types de paramètres).

Conclusion : tendance d'évolution des amis en C++

Aspect C++ traditionnel (98/03) C++ moderne (11/17/20/23)
Flexibilité de déclaration Obligation de spécifier class/struct Support des alias (using) et des paramètres template
Mécanisme de résolution Tendance à la déclaration globale Tendance aux Amis Cachés (résolution ADL)
Support des templates Difficile d'autoriser une instanciation template Autorisation directe du paramètre template T
Sécurité "Tout ou rien" Combinaison avec les Concepts pour un accès conditionnel

Prochaine étape suggérée

Puisque vous venez du C#, le mot-clé internal de C# correspond en C++ à cette relation d'ami soigneusement conçue.

Étiquettes: C++ friend hidden friends friend template concepts

Publié le 30 juin à 23h40