IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo
Sommaire > Les classes en C++ > Les amis (friend)
        Que signifie 'friend' ?
        Les amis brisent-ils l'encapsulation ?
        Quels avantages/désavantages y a-t-il à utiliser des fonctions friend ?
        Que signifie 'l'amitié n'est ni héritée ni transitive, ni réciproque' ?
        Doit-on utiliser plutôt des fonctions membres ou plutôt des fonctions friend ?



Que signifie 'friend' ?
Créé le 19/03/2004[haut]
auteur : Marshall Cline
Quelque chose qui permet à une classe d'offrir des droits d'accès privilégiés à une autre classe ou fonction.

Les amis (friends) peuvent être soit des fonctions, soit d'autres classes. Une classe offre des droits d'accès privilégiés à ses amis. Le développeur d'une classe exerce en théorie un contrôle technique et politique aussi bien sur les friends que sur les fonctions membres de la classe (si ce n'était pas le cas, il lui faudrait obtenir une autorisation de ceux qui ont écrits des amis lorsqu'il souhaite modifier sa classe).


Les amis brisent-ils l'encapsulation ?
Créé le 19/03/2004[haut]
auteur : Marshall Cline
C'est tout le contraire : s'ils sont utilisés correctement, ils renforcent l'encapsulation.

Il est souvent nécessaire de séparer une classe en deux, par exemple quand les deux moitiés ne peuvent pas avoir le même nombre d'instances ou quand elles n'ont pas la même durée de vie. Dans ce genre de cas, les deux moitiés ont généralement besoin de pouvoir accéder directement l'une à l'autre (dans la mesure où ces deux moitiés appartenaient à une unique classe, le nombre de lignes de code nécessitant un accès direct à la structure de données n'a pas augmenté ; le code a simplement été redistribué entre deux classes plutôt que laissé dans une seule). La façon la plus sûre d'implémenter cela est de rendre les deux moitiés amies l'une de l'autre.

En vous basant sur le modèle ci-dessus pour utiliser les amis, vous garantissez que les parties private restent private. Les gens qui ne comprennent pas ce modèle font souvent des tentatives naïves pour éviter d'utiliser l'amitié dans des situations se rapprochant de celle vue au-dessus. Ces tentatives vont en fait le plus souvent briser l'encapsulation. Soit ces personnes utilisent des données public (c'est grotesque !), soit elles offrent un accès aux données à travers des fonctions membres public de type get()/set(). Il n'y a pas de problème à avoir des fonctions membres public de type get()/set() qui donnent accès à des données private, mais seulement quand accéder à ces données private "a un sens" du point de vue de l'extérieur de la classe (du point de vue de l'utilisateur). Dans de nombreux cas, à utiliser des fonctions membres get()/set() s'avère presque aussi mauvais que d'utiliser directement des données public : ces fonctions à membres cachent (seulement) le nom de la donnée private, mais elles ne cachent pas son existence.

De façon similaire, utiliser des fonctions amies comme une alternative syntaxique aux fonctions d'accès public : de la classe ne brise pas plus l'encapsulation que le font les fonctions membres de la classe. On pourrait dire que les amis d'une classe ne brisent pas la barrière d'encapsulation : avec les fonctions membres de la classe, ils sont la barrière d'encapsulation.


Quels avantages/désavantages y a-t-il à utiliser des fonctions friend ?
Créé le 19/03/2004[haut]
auteur : Marshall Cline
Elles offrent plus de possibilités dans la conception d'une interface.

Les fonctions membres et les fonctions friend ont des droits d'accès identiques (c'est 100% garanti). La différence principale est qu'un appel à une fonction friend est de la forme f(x), alors qu'un appel à une fonction membre est de la forme x.f(). Ainsi, la possibilité qu'a le concepteur de la classe de choisir entre les fonctions membres (x.f()) et les fonctions friend (f(x)) lui permet de sélectionner la syntaxe qu'il estime la plus lisible, ce qui diminuera le coût de maintenance.

Le désavantage principal des fonctions friend est qu'elles nécessitent une ligne de code supplémentaire pour obtenir une liaison dynamique (dynamic binding). Pour simuler un virtual friend, il est nécessaire que la fonction friend appelle une fonction membre virtual cachée (qui est habituellement protected:). C'est ce que l'on appelle l'Idiome de la Fonction Friend Virtuelle. Voici un exemple :
class Base {
   public:
      friend void f(Base& b);
      // ...
   protected:
      virtual void do_f();
      // ...
};

inline void f(Base& b)
{
   b.do_f();
}

class Derived : public Base {
   public:
      // ...
   protected:
      virtual void do_f();  // "Redéfinit" le comportement de f(Base& b)
      // ...
};

void userCode(Base& b)
{
    f(b);
}
L'instruction f(b) dans la fonction userCode(Base&) va invoquer b.do_f(), qui est virtual. Ce qui veut dire que Derived::do_f() va être appelée si b est effectivement un objet de la classe Derived. Notez que Derived redéfinit le comportement de la fonction membre protected: virtual do_f(); elle, n'a pas sa propre version de la fonction friend f(Base&).


Que signifie "l'amitié n'est ni héritée ni transitive, ni réciproque" ?
Mise à jour le 17/03/2008[haut]
auteur : Marshall Cline
Ce n'est pas parce que je vous donne accès à ma classe en tant qu'ami que j'autorise vos enfants à y accéder, ni à vos amis, et cela ne me donne pas non plus automatiquement accès à votre classe.

Je ne fais pas forcément confiance aux enfants de mes amis Les privilèges de l'amitié ne sont pas hérités. Les classes dérivées d'une classe amie ne sont pas forcément des amis. Si la classe Fred déclare que la classe Base est une amie, les classes dérivées de Base n'ont pas à avoir automatiquement des droits d'accès particuliers aux objets de type Fred.

Je ne fais pas forcément confiance aux amis de mes amis Les privilèges de l'amitié ne sont pas transitifs. Un ami d'un ami n'est pas forcément un ami. Si la classe Fred déclare que la classe Wilma est une amie, et que la classe Wilma déclare que Betty est une amie, la classe Betty n'a pas à avoir automatiquement des droits d'accès particuliers aux objets de type Fred.

L'amitié n'est pas réciproque Vous ne me faites pas confiance simplement parce que je déclare que vous être mon ami. Les privilèges de l'amitié ne sont pas réciproques. Si la classe Fred déclare que la classe Wilma est une amie, les objets de type Fred n'ont pas à avoir automatiquement des droits d'accès particuliers aux objets de type Wilma.


Doit-on utiliser plutôt des fonctions membres ou plutôt des fonctions friend ?
Mise à jour le 17/03/2008[haut]
auteur : Marshall Cline
Utilisez les membres quand vous le pouvez, et les friend quand vous le devez.

Les amis sont parfois un meilleur choix d'un point de vue syntaxique (comme par exemple quand une fonction amie permet à un objet de type Fred d'être utilisé en tant que second paramètre de la fonction, tandis qu'une fonction membre obligerait à ce que l'objet Fred soit en premier). Les opérateurs arithmétiques binaires infixes sont un autre cas où l'utilisation des fonctions friend est appropriée. Par exemple, aComplex + aComplex doit être défini comme un ami plutôt que comme un membre si vous voulez aussi pouvoir écrire aFloat + aComplex (les fonctions membres n'autorisent pas la promotion de l'argument de gauche, la raison étant que cela changerait la classe de l'objet sur lequel on invoque la fonction membre).

Dans les autres cas, utilisez une fonction membre plutôt qu'une fonction friend. De plus; il est préférable d'utiliser au maximum des fonctions libres dans le même namespace



Consultez les autres F.A.Q.


Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.