Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Pour ou contre l'amitié entre classes

Le , par Eusebius

21PARTAGES

0  0 
Ceci est un fork de la discussion héritage et classes permettant à chacun de donner son avis sur le concept d'amitié

Citation Envoyé par Aspic Voir le message
Question : Dans la classe ZoneDonjon, j'ai besoin d'accéder à l'attribue "nbCle" qui se trouve dans la classe Donjon. Comment faire intelligemment, sachant que j'ai besoin de modifier cet attribue dans la classe ZoneDonjon ?
Il y a plusieurs manières.
Celle qui a ma préférence, et qui est la plus "classique" : tu ajoutes un getter et un setter (méthodes publiques getNbCle() et setNbCle(int)) dans la classe Donjon. Ca te donne un peu de contrôle sur les accès et les modifications, si tu as des tests à faire pour vérifier que les modifs sont cohérentes par exemple.

Sinon, tu peux déclarer la classe ZoneDonjon ou certaines de ses méthodes comme "friend" de Donjon, mais à mon sens c'est une brèche dans la "sécurité" objet en C++.

Sinon, encore pire à mon sens, tu repasses nbCle en public, c'est-à-dire que tu renonces tout-à-fait aux fonctionnalités de contrôle d'accès pour cette variable membre.

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de Emmanuel Deloget
Expert confirmé https://www.developpez.com
Le 19/11/2010 à 14:05
friend est plus fin que ça. En conception, il est utilisé pour permettre à une classe ou une fonction amie de voir ou modifier l'invariant de la classe de base. Il doit être utilisé avec parcimonie, mais c'est une opération tout à fait légitime. L'effet demandé est d'offrir un meilleur contrôle sur l'accès à certaines informations à partir de l'extérieur. En particulier, friend est souvent utiliser pour donner à une classe (ou une fonction) l'accès à une API privée - plutôt que de laisser cette API en public et dire dans la doc "do not use, plz, or you'll be pwnd quickly".

Je donne un exemple, tiré d'un test d'architecture pour un wrapper DirectX:

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class resource
{
private:
  bool tie(IDirect3DDevice9* device);
  bool untie();
  
  friend class device;
};

class device
{
private:
  resource_collection resources;
  IDirect3DDevice9* hdevice;
  
public:
  bool register(resource* r)
  {
    if (r->tie(hdevice)) { resources.add(r); }
  }
private:
  bool reset_resources()
  {
    try
    {
      resources.foreach([]() { if (!r->untie()) throw resource_exception(); });
      resources.foreach([hdevice]() 
        { if (!r->tie(hdevice)) throw resource_exception(); }
      );
    }
    catch (resource_exception e)
    { return false; }
    
    return true;
  }
};
(désolé pour les lambda; j'essaie de simplifier le code . Le code réel n'utilise pas de lambda, mais je ne voulais pas trop alourdir la déclaration de la collection resources, son utilisation. Pour des informations sur les lambda, cf cet article.).

En utilisant le mot-clef, plutôt que de casse l'encapsulation, j'ai un meilleur contrôle sur celle-ci. tie() et untie() ne peuvent être appelées qu'à partir de la classe device. has_reseted() et reset_resources() ne peut être appelé qu'à partir de la classe renderer. Je ne permet pas à l'utilisateur de mon API d'utiliser ces fonctions.

Pour information, l'idée de base de ce test était

1) de créer des classes en obéissant au principe de responsabilité unique (et ce n'est pas au device de faire le rendu d'une scène)

2) de ne pas autoriser l'accès à quoi que ce soit de DX9 (wrapper parfait; une application complète du DP facade, en somme).
1  0 
Avatar de Eusebius
Membre expert https://www.developpez.com
Le 19/11/2010 à 13:16
Alors le message suivant (récupéré d'un MP) est rajouté à la demande expresse de koala1, visiblement désireux de me basher en public

De plus, je ne suis pas un spécialiste de C++.
Cependant :

- je suis persuadé (EDIT: en d'autres termes, ça relève ici de l'intuition) qu'il est possible de mettre en place un contrôle d'accès relativement fin dans un getter/setter ;

- déclarer un friend, c'est, en gros, sortir le contrôle de la classe à qui il correspond. Si tu déclares une méthode ou une classe comme friend, que le développement de ladite méthode ou classe est confié à une autre équipe qui trouve que ça serait bien pratique si ta variable privée était quand même publique, elle a le pouvoir de la rendre publique "de fait" en implémentant un getter et un setter d'interface. Et toi qui trouvais que les getter et les setter n'étaient pas assez sécurisés, tu te retrouves avec un getter et un setter dont tu ne maîtrises même pas le code (dont tu ne connais même pas l'existence, d'ailleurs) alors que tu aurais sans doute pu faire mieux. En résumé, c'est une considération assez théorique, mais si l'enceinte "à sécuriser" est ta classe de départ (le reste de l'application en étant a priori exclu), alors un "friend" constitue en théorie une faille dans les processus de contrôle d'accès via les mots-clés, puisqu'il permet à une classe (et donc théoriquement à toutes les autres) de les contourner.
0  0 
Avatar de Eusebius
Membre expert https://www.developpez.com
Le 19/11/2010 à 14:14
Citation Envoyé par Emmanuel Deloget Voir le message

En utilisant le mot-clef, plutôt que de casse l'encapsulation, j'ai un meilleur contrôle sur celle-ci. tie() et untie() ne peuvent être appelées qu'à partir de la classe device. has_reseted() et reset_resources() ne peut être appelé qu'à partir de la classe renderer. Je ne permet pas à l'utilisateur de mon API d'utiliser ces fonctions.
Juste pour préciser, ça n'est pas en contradiction avec ce que j'ai dit plus haut : le friend introduit une "faille" lorsqu'il pointe vers l'extérieur de la partie de code "sensible" (i.e. fonctionnalités à protéger, code non modifiable par d'autres a priori). Dans mon hypothèse c'était une seule classe, ici la classe friend (device) est également dans le scope.
0  0 
Avatar de koala01
Expert éminent sénior https://www.developpez.com
Le 19/11/2010 à 14:16
Citation Envoyé par Eusebius Voir le message
Alors le message suivant (récupéré d'un MP) est rajouté à la demande expresse de koala1, visiblement désireux de me basher en public
Ce n'est pas mon genre , mais je vais pourtant y répondre...
- je suis persuadé (EDIT: en d'autres termes, ça relève ici de l'intuition) qu'il est possible de mettre en place un contrôle d'accès relativement fin dans un getter/setter ;
Primo, l'acesseur (getter) donne déjà accès à "un détail d'implémentation" qu'il est rarement judicieux d'exposer en OO, pour la simple et bonne raison que l'idée générale de ce paradigme et, justement, de baser la réflexion sur les service qu'un objet peut rendre, et non sur les données qu'il contient et qui lui permettent de rendre les services attendus.

Si, pour une raison ou une autre, tu décide de changer la manière dont une donnée est représentée dans un objet, tu devra, non seulement modifier ton accesseur, mais également tout code qui y fait appel.

C'est encore pire avec les mutateurs (getters) car ils impliquent que "n'importe qui" peut décider "n'importe quand" que la valeur d'une partie de l'objet ne lui convient pas, alors que cette valeur a une raison particulière d'être et qu'elle devrait, si elle est modifiée, être modifiée au fur et à mesure de l'utilisation de l'objet (comprend: lorsque l'objet rend un service donné, il peut en profiter pour modifier la valeur qui lui permet de rendre le service en question

Secundo, la seule manière dont tu puisse envisager de gérer l'accès à une partie de ton objet (de manière tout à fait générale), et donc aux accesseurs / mutateurs, est d'en changer la visibilité.

Le problème est qu'une partie privée ne sera accessible qu'à la classe elle-même et qu'une partie protégée ne sera accessible... qu'à la classe elle-même et aux classes qui en dérivent de manière directe ou indirecte.

Tu peux donc envisager de mettre ton accesseur/mutateur dans l'accessibilité protégée, mais cela t'obligera à envisager de faire dériver la classe qui en a besoin de celle qui les propose.

Or:
  • L'héritage publique est la relation la plus forte qui puisse exister et elle doit donc être utilisée avec parcimonie
  • Les héritages protégé et privé sont une relation "EST IMPLEMENE EN TERME DE", certes utiles dans certaines situations, mais qui gagnent généralement à être remplacés par des agrégations (ou des compositions) classiques
  • L'héritage, de manière générale, complexifie énormément la conception, l'évolutivité et la maintenance de ton projet.
Je ne dis absolument pas que ce ne soit pas une possibilité à explorer dans certaines circonstances, mais je dis juste que cette possibilité est rarement applicable
- déclarer un friend, c'est, en gros, sortir le contrôle de la classe à qui il correspond. Si tu déclares une méthode ou une classe comme friend, que le développement de ladite méthode ou classe est confié à une autre équipe qui trouve que ça serait bien pratique si ta variable privée était quand même publique,
Tout à fait...

Mais il faut te rappeler que l'amitié n'est ni héritée (ce n'est pas parce que Base est amie de trucmuche que Derivée (qui dérive de Base ) est amie de trucmuche) ni transitive (les amis de mes amis ne sont pas forcément mes amis ) ni réciproque (je ne suis pas forcément l'ami de ceux que je reconnais comme étant mes amis).

Tu garde donc un contrôle complet sur "qui peut aller tripatouiller" dans les détails d'implémentation, et de manière beaucoup plus fine qu'avec les mutateurs/accesseurs
elle a le pouvoir de la rendre publique "de fait" en implémentant un getter et un setter d'interface. Et toi qui trouvais que les getter et les setter n'étaient pas assez sécurisés, tu te retrouves avec un getter et un setter dont tu ne maîtrises même pas le code (dont tu ne connais même pas l'existence, d'ailleurs) alors que tu aurais sans doute pu faire mieux.

C'est bien pour cela que je parle d'utiliser l'amitié en connaissance de cause et avec parcimonie...

Par "en connaissance de cause", j'entends que tu dois avoir clairement déterminer à quoi la classe amie doit pouvoir accéder et comment, ce qui exclu, a priori, toute classes sur lequel tu n'a pas un contrôle total, et par "avec parcimonie", j'entends que tu dois, bien évidemment, veiller à ne pas déclarer une tonne d'amis simplement parce que tu ne veux pas placer de mutateur ou d'accesseur

En résumé, c'est une considération assez théorique, mais si l'enceinte "à sécuriser" est ta classe de départ (le reste de l'application en étant a priori exclu), alors un "friend" constitue en théorie une faille dans les processus de contrôle d'accès via les mots-clés, puisqu'il permet à une classe (et donc théoriquement à toutes les autres) de les contourner.
Tu peux effectivement en théorie, déclarer un grand nombre de classes amies d'un autre.

Et c'est la raison pour laquelle, je le répète encore une fois, il faut envisager l'amitié avec parcimonie. Il est, en effet, tout à fait clair qu'au delà d'un nombre finalement très bas de déclarations d'amitié (maximum trois ou quatre, de manière tout à fait arbitraire), il faut envisager le fait que la présence d'accesseurs et de mutateurs soit en définitive la "moins mauvaise" solution.

Ce n'est cependant pas une raison pour renoncer sans appel à l'amitié.

Je t'accorde sans peine que l'amitié est à ranger au rayon des possibilités qui nous sont offertes mais qu'il faut utiliser avec extrême prudence, et uniquement lorsque c'est réellement nécessaire, au même titre que la récursivité, que le goto (et dieu sais que j'en ai horreur) ou d'autres méthodes "border line", mais si tu l'utilise a bon escient, elle s'avère d'une efficacité et d'une sécurité remarquable (pour ne pas dire inégalable).
0  0 
Avatar de Eusebius
Membre expert https://www.developpez.com
Le 19/11/2010 à 14:40
Citation Envoyé par koala01 Voir le message
Si, pour une raison ou une autre, tu décide de changer la manière dont une donnée est représentée dans un objet, tu devra, non seulement modifier ton accesseur, mais également tout code qui y fait appel.
Bah, pas forcément, tu peux avoir une fonction qui a un rôle d'accesseur sans qu'elle colle absolument au modèle de représentation interne. Ce n'est pas parce que tu as une fonction getX() qui te renvoie une instance de la classe Y que cette instance est effectivement une variable membre de la classe, elle peut dériver d'autre chose. J'entends "getter" dans un sens assez général, mais j'ai peut-être tort.

Citation Envoyé par koala01 Voir le message
C'est encore pire avec les mutateurs (getters) car ils impliquent que "n'importe qui" peut décider "n'importe quand" que la valeur d'une partie de l'objet ne lui convient pas, alors que cette valeur a une raison particulière d'être et qu'elle devrait, si elle est modifiée, être modifiée au fur et à mesure de l'utilisation de l'objet (comprend: lorsque l'objet rend un service donné, il peut en profiter pour modifier la valeur qui lui permet de rendre le service en question
D'où ma remarque sur le possible contrôle d'accès "plus fin".

Citation Envoyé par koala01 Voir le message
Secundo, la seule manière dont tu puisse envisager de gérer l'accès à une partie de ton objet (de manière tout à fait générale), et donc aux accesseurs / mutateurs, est d'en changer la visibilité.
Non, pas d'accord. Rien ne m'empêche de coder un accesseur ou un mutateur qui se fonde sur une politique de sécurité complexe pour donner ou non l'accès. On a tout C++ à notre disposition, non ? Si ça me branche, je peux très bien soumettre l'activation du mutateur à un tirage aléatoire, à une authentification RADIUS, à la consultation de l'horoscope du mois ou à n'importe quoi d'autre.

Citation Envoyé par koala01 Voir le message
Mais il faut te rappeler que l'amitié n'est ni héritée (ce n'est pas parce que Base est amie de trucmuche que Derivée (qui dérive de Base ) est amie de trucmuche) ni transitive (les amis de mes amis ne sont pas forcément mes amis ) ni réciproque (je ne suis pas forcément l'ami de ceux que je reconnais comme étant mes amis).

Tu garde donc un contrôle complet sur "qui peut aller tripatouiller" dans les détails d'implémentation, et de manière beaucoup plus fine qu'avec les mutateurs/accesseurs
Non, tu ne m'as pas compris. Je ne parle pas de la possibilité de créer une classe dérivée de la classe amie, mais de la possibilité de modifier le code de la classe amie elle-même. Mon hypothèse est très restrictive, c'est ce qui fait qu'on a l'air de ne pas être d'accord.

Citation Envoyé par koala01 Voir le message
C'est bien pour cela que je parle d'utiliser l'amitié en connaissance de cause et avec parcimonie...
Tout-à-fait, cf les hypothèse de sécurité du développement.

Citation Envoyé par koala01 Voir le message
Par "en connaissance de cause", j'entends que tu dois avoir clairement déterminer à quoi la classe amie doit pouvoir accéder et comment
Encore une fois, à condition d'avoir la garantie qu'elle ne peut pas être modifiée par quelqu'un d'autre.

Citation Envoyé par koala01 Voir le message
Ce n'est cependant pas une raison pour renoncer sans appel à l'amitié.
Je l'ai juste dépréciée dans le cas sous-spécifié qui nous avait été soumis.

Citation Envoyé par koala01 Voir le message
Je t'accorde sans peine que l'amitié est à ranger au rayon des possibilités qui nous sont offertes mais qu'il faut utiliser avec extrême prudence, et uniquement lorsque c'est réellement nécessaire, au même titre que la récursivité, que le goto (et dieu sais que j'en ai horreur) ou d'autres méthodes "border line", mais si tu l'utilise a bon escient, elle s'avère d'une efficacité et d'une sécurité remarquable (pour ne pas dire inégalable).
Attends... on n'est pas dans le même débat là, et probablement dans le troll, mais... tu mets la récursivité, un des modèles à la base de la notion même de programmation, au même niveau que le goto, qui sert principalement à empêcher toute analyse sémantique ??
0  0 
Avatar de koala01
Expert éminent sénior https://www.developpez.com
Le 19/11/2010 à 15:14
Citation Envoyé par Eusebius Voir le message
Bah, pas forcément, tu peux avoir une fonction qui a un rôle d'accesseur sans qu'elle colle absolument au modèle de représentation interne. Ce n'est pas parce que tu as une fonction getX() qui te renvoie une instance de la classe Y que cette instance est effectivement une variable membre de la classe, elle peut dériver d'autre chose. J'entends "getter" dans un sens assez général, mais j'ai peut-être tort.
Imagine un simple accesseur renvoyant un entier (getx() const) renvoyant la coordonnée sur l'axe des X de n'importe quoi.

Il est, sans doute, suivi de près par un autre accesseur renvoyant un autre entier (getY() const) renvoyant la coordonnée sur l'axe Y de ce même n'importe quoi.

Tu te rend compte que, finalement, X et Y vont tellement bien ensemble qu'il est intéressant d'en faire une structure (ou une classe).

Soit tu dois modifier tes deux accesseurs pour que l'un renvoye Coordonnee.x (ou Coordonnee[0], selon le cas) et l'autre Coordonnee.y (respectivement Coordonnee[1]), soit tu vire carréement tes deux accesseurs, et tu en crée un autre "getCoordonnee() const"...

Et là, tout le code qui utilise getX et getY est bon pour la poubelle
D'où ma remarque sur le possible contrôle d'accès "plus fin".
Le controle le plus fin que tu puisse donner à un mutateur, c'est qu'il n'existe pas en tant que telle, mais qu'il soit intégré dans les services rendus par ta classe

Mais, à partir du moment où il est accessible publiquement, tu n'a plus le choix: il est accessible pour ... tout le monde et n'importe quand

Non, pas d'accord. Rien ne m'empêche de coder un accesseur ou un mutateur qui se fonde sur une politique de sécurité complexe pour donner ou non l'accès. On a tout C++ à notre disposition, non ? Si ça me branche, je peux très bien soumettre l'activation du mutateur à un tirage aléatoire, à une authentification RADIUS, à la consultation de l'horoscope du mois ou à n'importe quoi d'autre.
Bien sur que tu peux mettre en place un certain nombre de sécurités sur ton mutateur...

Mais une bonne partie de ces sécurités échoira... à celui qui l'appelle, alors qu'une autre (celle qui ne sait absolument pas qui essaye d'y avoir recours) sera finalement fort limité dans les vérifications qu'elle peut entreprendre

Et comme, à la base, tout le monde peut faire appel au mutateur (à moins d'en changer la visibilité)... quoi tu compte faire confiance à l'appelant pour avoir vérifier qu'il avait bien le droit d'appeler le mutateur

Non, tu ne m'as pas compris. Je ne parle pas de la possibilité de créer une classe dérivée de la classe amie, mais de la possibilité de modifier le code de la classe amie elle-même. Mon hypothèse est très restrictive, c'est ce qui fait qu'on a l'air de ne pas être d'accord.
C'est la raison pour laquelle je dis qu'il faut avoir le contrôle total sur la classe que l'on déclare amie.

La classe amie ne pouvant être modifiée que par toi ou ton équipe, et devant surtout être suffisamment documentée pour que, en cas de modification, on puisse veiller à ce qu'elle n'accède qu'à ce à quoi elle a droit
Encore une fois, à condition d'avoir la garantie qu'elle ne peut pas être modifiée par quelqu'un d'autre.
De prime abord, lorsque tu fournit une classe, soit tu donne le code (en-tête + implémentation) à quelqu'un en qui tu as suffisamment confiance pour lui laisser la modifier, soit tu ne donne que le stricte minimum (en-tête) à celui qui l'utilisera
Attends... on n'est pas dans le même débat là, et probablement dans le troll, mais... tu mets la récursivité, un des modèles à la base de la notion même de programmation, au même niveau que le goto, qui sert principalement à empêcher toute analyse sémantique ??
Je met la récurisvité, le goto, les variables statiques et l'amitié dans le même sac de choses qu'il faut utiliser intelligemment, jamais à la légère, et lorsqu'il apparait clairement que c'est la moins mauvaise solution, en effet, et ce n'est pas un troll:
  • Bien que je sois grand défenseur de récursivité, j'ai les cheveux qui se dressent sur ma tête à l'idée de rencontrer une fonction récursive pour calculer une exponentielle ou une factorielle.
  • A l'inverse, bien que j'ai une sainte horreur du goto, j'admets (et ca me fait mal au bide ) qu'il puisse, dans certaines circonstances, s'avérer utile.


Ce n'est bien sur que mon avis personnel, et je te laisse libre d'avoir le tien sur le sujet, mais je me suis déjà exprimé dans les discussions qui y étaient relatives

Je n'ai plus les adresses en tête, mais une petite recherche devrait te permettre de retrouver les discussions en question
0  0 
Avatar de white_tentacle
Membre émérite https://www.developpez.com
Le 19/11/2010 à 16:01
Je rajouterai à ce qui a déjà été dit par Koala que déterminer que certaines fonctionnalités ne sont accessibles qu'à certains utilisateurs me parait un besoin crucial. D'ailleurs, beaucoup de langages fournissent un mécanisme pour ce faire :

C# fournit internal, qui a comme granularité la propriété, mais restreint l'appelant seulement à tout le package (c'est beaucoup). Java fait la même chose me semble-t-il.

C++ fournit friend, qui est très fin sur l'appelant (classe ou fonction libre), mais pas sur la propriété (toute la classe devient accessible)

Eiffel a la double granularité, mais il faut être prudent car elle est héritée (si ma méthode est disponible pour A, elle l'est pour toute classe dérivée de A.

Je ne saurais pas dire laquelle de ces approches est la meilleure, bien que ma préférence aille vers le modèle « Eiffel ». Mais pour qu'on ait à chaque fois intégré un mécanisme tel dans le langage, c'est que ça répond à un réel besoin.

Enfin,

Rien ne m'empêche de coder un accesseur ou un mutateur qui se fonde sur une politique de sécurité complexe pour donner ou non l'accès. On a tout C++ à notre disposition, non ? Si ça me branche, je peux très bien soumettre l'activation du mutateur à un tirage aléatoire, à une authentification RADIUS, à la consultation de l'horoscope du mois ou à n'importe quoi d'autre.
Tu confonds deux choses :
- la vérification statique, faite par le compilateur, destinée à aider le programmeur à ne pas faire n'importe quoi
- la vérification dynamique, pour améliorer la sécurité du programme

private, public, friend et consorts sont, en C++, des informations purement statiques. Destinées à simplifier la vie du programmeur et l'aider à ne pas faire de bêtises. Certainement pas des fonctionnalités de sécurité.
0  0 
Avatar de seeme
Membre éclairé https://www.developpez.com
Le 19/11/2010 à 16:12
Je suis vraiment content de ce débat, car c'est un des points sur lequel j'hésite le plus quand je conçois une classe..

J'essaye de ne jamais utilisé public, et friend le moins possible.

Je l'utilise malgré tout pour créer mes singletons (classe template Singleton). Les classes que je déclare singleton sont amies, en ce qui concerne les méthode getInstance et kill avec le singleton.

Est-ce un cas valide d'utilisation de friend?
0  0 
Avatar de Joel F
Membre chevronné https://www.developpez.com
Le 19/11/2010 à 22:11
Citation Envoyé par seeme Voir le message
Je suis vraiment content de ce débat, car c'est un des points sur lequel j'hésite le plus quand je conçois une classe..

J'essaye de ne jamais utilisé public, et friend le moins possible.

Je l'utilise malgré tout pour créer mes singletons (classe template Singleton). Les classes que je déclare singleton sont amies, en ce qui concerne les méthode getInstance et kill avec le singleton.

Est-ce un cas valide d'utilisation de friend?
si on considére le singleton comme valide ... ce qui est tout relatif.

J'abonde dans le sens d'Emmanuel : avec parcimonie, friend résout des problèmes fins sans tout mettre par terre.
0  0 
Avatar de Emmanuel Deloget
Expert confirmé https://www.developpez.com
Le 20/11/2010 à 11:44
Citation Envoyé par seeme Voir le message
Je suis vraiment content de ce débat, car c'est un des points sur lequel j'hésite le plus quand je conçois une classe..

J'essaye de ne jamais utilisé public, et friend le moins possible.

Je l'utilise malgré tout pour créer mes singletons (classe template Singleton). Les classes que je déclare singleton sont amies, en ce qui concerne les méthode getInstance et kill avec le singleton.

Est-ce un cas valide d'utilisation de friend?
Hélas, si je cherche à répondre à la question, je vais commencer par te dire que les singletons, c'est pas bon. Donc utiliser friend dans un singleton, j'ai du mal à en voir l'intérêt
0  0