| ||
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).
|
| ||
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.
|
| ||
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 :
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&).
|
| ||
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.
|
| ||
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
|
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.