C++ Fonctions amies

Laaris -  
pascal.barbier Messages postés 33 Date d'inscription   Statut Membre Dernière intervention   -
Bonjour,

J'ai une question à propos des classes amies en C++ (j'ai déjà posté ça ailleurs mais ce n'était pas le bon forum, désolé pour le doublon)

Comment fait-on pour déclarer "amie" une fonction d'une autre classe sans déclarer "amie" la classe entière?

J'ai lu quelque part qu'il faut "préciser son nom complet à l'aide de l'opérateur de résolution de portée" mais qu'est-ce donc qu'un opérateur de résolution de portée?

Merci d'avance.

9 réponses

le père
 
Bonjour

L'opérateur de résolution de portée c'est ::

Si ta fonction amie est membre d'une classe, il faut que tu la déclares amie par
friend returntype maclasse::mafonction(parametres);

Si elle n'est pas membre d'une classe, il n'y a bien sûr pas de maclasse::
3
pascal.barbier Messages postés 33 Date d'inscription   Statut Membre Dernière intervention   6
 
Dans l'exemple qui suit, la classe B se déclare "amie" de la fonction fct de la classe A. Ainsi, cette fonction pourra utiliser la partie privée de la classe B :

class A
{
public:
	int fct(int a, int b);
};
class B
{
friend int A::fct(int a, int b);
private:
	static void f(void) {}
};

L'opérateur de résolution de portée est le double deux-points qui précède le nom de la méthode dans la déclaration friend. Il permet de préciser à quelle classe appartient cette fonction.
Pour plus de précisions voir :
Thinking in C++ : https://bruce-eckel.developpez.com/livres/cpp/traduction/ticpp2vol1/?vue=Comparatif&chapitre=5.3
1
le père
 
Si j'en crois mon manuel C++, ce problème est classique et ne peut être contourné qu'en déclarant la classe complète comme friend :

class B
{
friend class A;
private:
static void f(void) {}
};

class A
{
public:
int fct(B instance_de_B);
};

ce qui est moins propre, puisque toutes les fonctions membres de A ont maintenant accès à la partie privée de B.
1
pascal.barbier Messages postés 33 Date d'inscription   Statut Membre Dernière intervention   6
 
Deux choses :
d'abord int fct(B instance_de_B); va créer une copie temporaire de instance_de_B dans la pile. Ce qui peut avoir des effets indésirables (copy constructeur). Il vaut mieux passer une référence de instance_de_B. Si on veut garantir que cet objet ne sera pas modifié par fct (comme dans le cas d'un passage par valeur) il suffit de déclarer la référence const :
int fct(const B& instance_de_B); 

Deuxième chose :
dans la classe A si on n'utilise qu'une référence de B, il suffit de faire précéder le prototype de la classe A par la déclaration d'existance de la classe B :
class B;
class A 
{ 
public: 
    int fct(const B& instance_de_B); 
}; 
class B 
{ 
    friend int A::fct(int a, int b); 
private: 
    static void f(void) {} 
}; 
1
le père
 
Je ne crois pas que le compilateur apprécie la redéfinition de class B;. As-tu essayé ?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Laaris
 
ça risque de faire la même chose non?
0
pascal.barbier Messages postés 33 Date d'inscription   Statut Membre Dernière intervention   6
 
Bien sur c'est une technique courante qui permet d'utiliser des pointeurs ou des références d'une classe avant d'en avoir donné le prototype détaillé.
0
le père
 
Le compilateur n'aime pas, mais pour une autre raison, tu n'as pas mis les mêmes paramètres à A::fct dans A et dans B

Le problème dont je parle n'intervient pas ici, il se pose quand il y a des friend croisés entre deux classes :

class A;
class B;

class B 
{ 
    friend int A::fct(const B& instance_de_B); 
    static void f(void) {} 
}; 

class A 
{ 
    friend void B::f(void); 
    int fct(const B& instance_de_B); 
}; 
0
pascal.barbier Messages postés 33 Date d'inscription   Statut Membre Dernière intervention   6
 
Pour la définition de la fonction fct mille excuses c'est un copier/coller trop rapide.

En ce qui concerne les friends croisés effectivement on ne peut pas s'en sortir sans déclarer une amitié de classe.

Toutefois le cas doit être très rare d'avoir à déclarer deux amitiés croisées de fonctions. Personnellement je n'ai quasiment jamais eu besoin des déclarations d'amitié. En général une petite revue d'architecture permet de trouver une solution plus pure.
0
Laaris
 
Merci pour cette info, mais un autre problème se pose.

Si je fais:

class A
{
public:
int fct(B instance_de_B);
};
class B
{
friend int A::fct(int a, int b);
private:
static void f(void) {}
};

le compilateur me dit "B has not been declared", et si je déclare B avant A, il me dit "A has not been declared"
-1