C ++ à un ami ou pas à un ami

19

J'ai une programmation orientée objet avec cours c ++ ce semestre à l'université et nous apprenions les fonctions des amis.

Je les déteste instinctivement pour leur capacité à contourner la sécurité offerte par l'encapsulation et le masquage des données, j'ai lu quelques articles sur Internet et certaines personnes ont pensé que c'était une bonne idée avec des utilisations légitimes.

Que dirait un expert OOPs des fonctions d'ami en C ++? Dois-je simplement le parcourir ou devrais-je en savoir plus?

nikhil
la source
@all: Réponses et commentaires impressionnants, c'est un excellent moyen d'apprendre, il n'y a aucun moyen que j'aurais appris sur des amis dans de tels détails dans un manuel.
nikhil

Réponses:

13

Il n'est pas toujours commode de faire toutes les fonctions liées à une classe C ++ membres de cette classe. Par exemple, imaginez une implémentation d'algèbre vectorielle avec multiplication scalaire. Nous voulons écrire:

 double a;
 Vector v, w;
 w = v * a;

Nous pouvons le faire avec une fonction membre:

public class Vector {
 ...
 Vector operator*(double a);
}

Mais nous aimerions également écrire:

w = a * v

Cela nécessite une fonction gratuite:

 Vector operator*(double a, Vector v)

Le friendmot clé a été ajouté à C ++ pour prendre en charge cette utilisation. La fonction free fait partie de l'implémentation de la classe Vector et doit être déclarée dans le même en-tête et implémentée dans le même fichier source.

De même, nous pouvons utiliser friendpour simplifier l'implémentation de classes étroitement couplées, comme une collection et un itérateur. Encore une fois, je déclarerais les deux classes dans le même en-tête et les implémenterais dans le même fichier source.

Kevin Cline
la source
3
"Cela nécessite une fonction gratuite". Non, ce ne est pas: inline Vector operator*(double a, Vector v) { return v*a; }. Solution canonique en fait.
MSalters
1
@MSalters: Bon point. J'ai choisi un mauvais exemple. Je pense que votre fonction en ligne est une fonction libre par définition, mais aucune déclaration d'ami n'est requise.
Kevin Cline
4
@MSalters: Cela n'est valable que si * est un respect commutatif de a et v (x). Si les composants vectoriels sont génériques (pas nécessairement scalaires), vous devez conserver l'ordre des opérandes
Emilio Garavaglia
C'est assez théorique. Peut-être que le seul cas commun non commutatif serait inline Vector operator*(double a, Vector v) { return -v*a; }et cela ne nécessite toujours pas d'amitié.
MSalters
16

Les fonctions ami ne sont pas différentes des fonctions membres en termes d'encapsulation. Ils peuvent cependant offrir d'autres avantages, comme être plus génériques, en particulier en ce qui concerne les modèles. De plus, certains opérateurs ne peuvent être spécifiés que comme fonctions libres, donc si vous voulez qu'ils aient un accès membre, vous devez friend.

Il vaut mieux pour friendune seule fonction que d'être forcé de faire quelque chose que vous ne voulez pas rendre public. Cela signifie que le monde entier peut l'utiliser - au lieu d'une seule fonction.

DeadMG
la source
Les fonctions +1 pour les amis ne sont pas différentes des fonctions membres en termes d'encapsulation. Cela n'est vrai que pour les fonctions de membre public.
TheFogger
1
@TheFogger: Sans doute, vous pourriez également avoir friendune fonction qui est également "privée", telle qu'elle n'est déclarée que dans un seul TU.
DeadMG
5

Si vous êtes passionné par ce que vous faites, vous apprenez tout sur le C ++. Découvrez à quoi ils servent, comment les utiliser, puis - et alors seulement - décidez de ne pas les utiliser. À tout le moins, vous serez prêt à lire le code de quelqu'un d'autre qui utilise cette facette de C ++.

JK
la source
5

" Que dirait un expert OOPs ... " Cela dépend surtout de son expertise en C ++, qui - selon ses propres spécifications - n'est pas (et ne veut pas être) un langage pour puriste.

Les fanatiques de POO n'utilisent pas C ++ (ils préfèrent Smalltalk et comme Java).

Les zelots de programmation fonctionnelle n'utilisent pas C ++ (ils préfèrent LISP et ses successeurs)

La plupart des experts OOP n'aiment pas la fonction ami simplement parce qu'ils veulent que la partie OOP de C ++ se comporte comme Smalltalk. Mais C ++ n'est pas Smalltalk, et ils ne peuvent même pas comprendre que friend ne rompt pas l'encapsulation , pour la raison très simple qu'une fonction ne peut pas être amie de votre classe sans que votre classe le veuille .

Et du point de vue "fonctionnalité", entre a.fn(b)et fn(a,b)il n'y a pas de différence (où fnest un ami): les parties impliquées sont les mêmes. Simplement, une syntaxe peut être plus appropriée qu'une autre: si fn est commutatif en ce qui concerne aet b, fn(a,b)est probablement plus approprié alors a.fn(b)(où un semble avoir un "rôle spécial" que, en fait, il ne l'est pas.)

Emilio Garavaglia
la source
1
Les «fanatiques de POO» qui aiment Java n'ont pas compris la POO. Getters? Setters? Pas de syntaxe simple pour les fermetures? Pour paraphraser Alan Kay, ce n'est pas ainsi qu'il a imaginé la POO.
Konrad Rudolph
@Konrad: les fanatiques sont un ensemble illimité supérieur. Il y a toujours un fanatique plus fanatique qu'un fanatique donné.
Emilio Garavaglia
Je dois dire que j'ai voté positivement parce que j'ai vraiment aimé ce dernier paragraphe. Cela a beaucoup de sens.
julealgon
5

"Ami" viole-t-il l'encapsulation?

Non. "Friend" est un mécanisme explicite pour accorder l'accès, tout comme l'adhésion. Vous ne pouvez pas (dans un programme conforme standard) vous accorder l'accès à une classe sans modifier sa source.

fredoverflow
la source
2

La FAQ C ++ est succincte:

Utilisez un membre quand vous le pouvez et un ami quand vous le devez.

La FAQ présente l'une des façons les plus utiles de penser à l'amitié:

Beaucoup de gens pensent qu'une fonction d'ami est quelque chose en dehors de la classe. Essayez plutôt de penser à une fonction ami dans le cadre de l'interface publique de la classe. Une fonction amie dans la déclaration de classe ne viole pas plus l'encapsulation qu'une fonction membre publique ne viole l'encapsulation: les deux ont exactement la même autorité en ce qui concerne l'accès aux parties non publiques de la classe.

L'utilisation la plus courante des fonctions ami est peut-être la surcharge << pour les E / S.

Gnawme
la source
0

Les fonctions Friend sont mieux utilisées pour les définitions d'opérateur définies par l'utilisateur. Ils sont utiles dans d'autres situations, mais si vous vous retrouvez à spécifier fréquemment des classes d'amis, vous pouvez être sur un détour par la conception (juste une bonne auto-vérification à utiliser lors de l'écriture de code).

Faites attention à la déclaration de «sécurité» dans la question d'origine. Les modificateurs d'accès sont là pour vous empêcher d'écrire du mauvais code en cas d'accident, tout comme le compilateur en quelque sorte. Les modificateurs d'accès limitent l'interface et servent à communiquer quelles fonctions sont importantes pour utiliser la classe (publiques et protégées), et lesquelles ont été créées dans le but de rendre la classe plus jolie pour les mainteneurs (privées). Les modificateurs ne constituent pas une sécurité dans la mesure où il existe de nombreuses façons d'accéder aux données privées. Par exemple, obtenez un pointeur sur la classe et sa taille et allez à la pêche.

anon
la source
-2

Les fonctions d'ami C ++ sont étroitement liées aux fonctionnalités suivantes:

  1. fonctions libres
  2. fonctions statiques
  3. fonctions d'ami

Cela signifie qu'ils n'ont pas ce pointeur et sont donc en dehors de la classe / objet. En revanche, ils prennent souvent des paramètres qui les font à nouveau appartenir à la classe. Voici un exemple qui clarifie le lien:

class B;
class A {
public:
    friend void f(A &a, B &b);
private:
    int m_a;
};
class B {
public:
   friend void f(A &a, B &b);
private:
   int m_b;
};
void f(A &a, B &b) { /* uses both A's and B's private data */ }

La seule différence entre les fonctions statiques et les fonctions ami est qu'une fonction ami peut utiliser plusieurs classes.

L'utilisation du mécanisme ami en c ++ nécessite des programmeurs qui ont environ 10 à 15 ans d'expérience avec la méthode de programmation c ++, et donc vous devriez d'abord l'éviter. C'est une fonctionnalité avancée.

tp1
la source
7
Et vous avez dérivé 10-15 ans comment?
DeadMG
10-15 ans vient du moment où cela devient réellement nécessaire.
tp1
3
Vous avez donc composé arbitrairement un chiffre.
DeadMG
3
-1: "Vous devriez l'éviter." Chaque fonctionnalité de C ++ a été créée pour résoudre un problème. Lorsque ce problème survient, utilisez la fonctionnalité appropriée.
Kevin Cline
Merci pour le -1. Il y avait une raison à ce commentaire. Je suppose que c'est juste un concept difficile que toutes les fonctionnalités ne conviennent pas aux débutants.
tp1