Vous êtes sur la page 1sur 28

Classes et fonctions amies

Plan du chapitre

1. Besoin à une telle notion ( fonction amie )


2. Définition
3. Les différentes situations d'amitiés
4. Remarques

2
Besoin à une telle notion ( fonction amie )

▪ La P.O.O. pure impose l’encapsulation des données. Nous avons vu comment la mettre
en œuvre en C++ : les membres privés (données ou fonctions) ne sont accessibles
qu'aux fonctions membres (publiques ou privées) et seuls les membres publics sont
accessibles "de l'extérieur".
▪ Ce même principe d'encapsulation interdit à une fonction membre d'une classe
d'accéder à des données privées d'une autre classe

• Il est parfois nécessaire d'avoir des fonctions qui ont un accès illimité aux champs d'une classe.
• Comment ? → via des fonctions amies

3
Définition

▪ Une fonction membre a accès aux membres publics et privés de la classe.


▪ Les données sont masquées, seules les fonctions membres y ont accès. Si l’on veut
que ces données soient accessibles de l'extérieur, on peut utiliser aussi les fonctions
amies.
▪ Une fonction amie d'une classe est une fonction qui, bien que non membre de la classe,
a accès aux données privées de la classe.
▪ L'amitié est déclarée en utilisant le mot-clé réservé: friend.
▪ Il importe peu de déclarer une fonction amie dans la partie public ou private d'une classe
donnée. Dans les deux cas, la fonction sera vue comme étant une fonction public.
▪ Il existe plusieurs situations d'amitié …

4
Les différentes situations d'amitié

▪ On distingue généralement de quatre situations d'amitiés

▪ fonction indépendante, amie d'une classe,


▪ fonction membre d'une classe, amie d'une autre classe,
▪ fonction amie de plusieurs classes,
▪ toutes les fonctions membres d'une classe, amies d'une autre classe.

5
Les différentes situations d'amitiés
1. Fonction indépendante, amie d'une classe,
▪ Exemple class A {
int i;
friend void fct_exemple (A&);
public:
A(){cout << "creation de a";}
};
void fct_exemple (A & b) {
// accès direct à i qui est membre données privées.
cout << b.i << endl; }
int main() {
A y;
fct_exemple(y);
return 0;
}

6
Les différentes situations d'amitiés
1. Fonction indépendante, amie d'une classe,

▪ Remarques

▪ La fonction « exemple » est une fonction amie de la classe « A ».


▪ Déclarer la fonction « exemple » « private » ou « public » importe peu.

▪ La définition de la fonction amie est différente de la définition d'une fonction membre d'une
classe.

// Fausse (déclaration utilisée pour une fonction membre).


void A::exemple (A& a) {/* etc. */}

// Correcte (déclaration utilisée pour une fonction amie).


void exemple (A& a) {/* etc. */}

7
Exemple
#include<iostream>
using namespace std;
class X {
int a;
friend void f (X *); Le corps de la fonction est défini plus loin sans faire
}; précéder son nom du nom de la classe (lignes 7 à 9).
Les instructions de cette fonction peuvent cependant
void f (X *p) { atteindront tous les membres de la classe même si ceux-
p->a = 2; ci ne sont pas publics, d'où le nom friend.
cout<<p->a<<endl;
}
int main () {
X *ptr = new X;
f (ptr);

system ("PAUSE");
return 0;
}

8
Les différentes situations d'amitiés
1. Fonction indépendante, amie d'une classe,

▪ Exercice

Creér une fonction amie indépendante "coincide(point , point)" de la classe "point"

9
#include<iostream>
using namespace std ;
class point{
int x,y;

public:
point(int abs=0, int ord=0)
{ x= abs;
y=ord; Dans cet exemple, la fonction
} coincide est AMIE de la classe
friend int coincide(point,point);
};
point. C’est une fonction ordinaire
int coincide(point p, point q) qui peut manipuler les membres
{ privés de la classe point.
if ((p.x==q.x)&&(p.y==q.y))return 1 ;
else return 0 ;
}
int main(){
point a(4,0),b(4),c;
if(coincide(a,b)
cout<<"a coincide avec b\n";
else
cout<<"a est différent de b\n";

if(coincide(a,c))
cout<<"a coincide avec c\n";
else
cout<<"a est différent de c\n";
system("PAUSE ") ;
return 0 ; 10
}
Autre exemple

#include <iostream>
using namespace std;

class simple{
int a,b;
public:
friend int somme(simple x);
simple(int,int); //Constructeur
};

simple::simple(int i, int j) {
a=i;
b=j; }

int somme (simple objet)


{
return objet.a+objet.b;
}

int main(){

simple entier(3,4);
cout<<" La somme de 3 et 4 vaut: "<<endl;

cout<<somme(entier)<<endl;

system("PAUSE");
return 0;
}

11
Les différentes situations d'amitiés
2. Fonction membre d'une classe, amie d'une autre classe
▪ Il s'agit un peu d'un cas particulier de la situation précédente. En fait, il suffit simplement de
préciser, dans la déclaration d'amitié, la classe à laquelle appartient la fonction concernée, à l'aide
de l'opérateur de résolution de portée (::).

▪ Exemple
Supposons que nous ayons à définir deux classes nommées A et B et que nous ayons besoin dans
B d'une fonction membre f, de prototype :
int f(char, A) ;
Si, comme il est probable, f doit pouvoir accéder aux membres privés de A, elle sera déclarée
amie au sein de la classe par :
friend int B::f(char, A) ;

12
Les différentes situations d'amitiés
2. Fonction membre d'une classe, amie d'une autre classe

▪ Exemple (Schema)

class A class B
{ {
// partie privée .....
..... int f (char, A) ;
// partie publique };
friend int B::f (char, A) ; int B::f (char ..., A ...)
..... {
}; // on a accès ici aux membres privés
// de tout objet de type A
}

13
Les différentes situations d'amitiés
2. Fonction membre d'une classe, amie d'une autre classe

▪ Remarques

▪ Pour compiler convenablement les déclarations d'une classe A contenant une déclaration d'amitié telle que :
friend int B::f(char, A) ; le compilateur a besoin de connaître les caractéristiques de B ; cela signifie que la
déclaration de B (mais pas nécessairement la définition de ses fonctions membres) devra avoir été
compilée avant celle de A.
▪ En revanche, pour compiler convenablement la déclaration : int f(char, A) figurant au sein de la classe B, le
compilateur n'a pas besoin de connaître précisément les caractéristiques de A. Il lui suffit de savoir qu'il
s'agit d'une classe. Comme, d'après ce qui vient d’être dit, la déclaration de B n'a pu apparaître avant, on
fournira l'information voulue au compilateur en faisant précéder la déclaration de A de : class A ;

14
#include<iostream>
using namespace std ;
// Déclaration de la classe point

class point; /* Cette déclaration est importante à ce niveau


car si non f(point) sera ambigu,
le compilateur génère une erreur*/
class utilisepoint{
private : Cas : fonction membre d'une classe, amie d'une autre
float x, y;
public : classe
void f(point);
};
Il suffit simplement de préciser, dans la déclaration
class point{ d'amitié, la classe à laquelle appartient la fonction
private :
float abscisse, ordonnee; concernée, à l'aide de l'opérateur de résolution de porté
public : (::)
point (float, float);
friend void utilisepoint::f(point);};

// Définition du constructeur de la classe point


point::point (float a, float b){
abscisse = a;
ordonnee = b;}

void utilisepoint::f (point p){


x = p.abscisse; y = p.ordonnee;
cout<<p.abscisse<<" "<<p.ordonnee<<endl;}
// Programme principal client des classes point et utilisepoint
int main (){point p1(2,3);
utilisepoint d;
d.f(p1);
return 0 ;}
15
Les différentes situations d'amitiés
3. Fonction amie de plusieurs classes

▪ Rien n'empêche qu'une même fonction (qu'elle soit indépendante ou fonction membre) fasse l'objet
de déclarations d'amitié dans différentes classes. Voici un exemple d'une fonction amie de deux
classes A et B :

class A class B
{ {
void f(A..., B...)
// partie privée // partie privée
{
..... .....
// on a accès ici aux membres privés
// partie publique // partie publique
// de n’importe quel objet de type A ou B
friend void f(A, B) ; friend void f(A, B) ;
}
..... .....
}; };

16
Les différentes situations d'amitiés
4. Toutes les fonctions d'une classe amies d'une autre classe

▪ On pourrait d'ailleurs effectuer autant de déclarations d'amitié qu'il y a de fonctions concernées.


▪ Mais il est plus simple d'effectuer une déclaration globale.
▪ Ainsi, pour dire que toutes les fonctions membres de la classe B sont amies de la classe A, on
placera, dans la classe A, la déclaration : friend class B ;

17
Classe Amie #include <iostream>
using namespace std;

class A {
private:
int a;
int b;
public:
A() { a = 2; b=4;}
friend class B; // Classe ami
};
class B {
private:
int b;
public:
void afficherA(A& f) {
//Puisque B est un ami de A, il peut accéder aux membres privés
de A
cout << "La valeur de a dans la classe A = " << f.a<<endl;
}
void afficherA1(A& f1){
cout << "La valeur de b dans la classe A = " << f1.b<<endl;

}
};
int main() {
A a,a1;
B b;
b.afficherA(a);
b.afficherA1(a1); 18
return 0; }
Remarques
▪ Si la classe A est amie de la classe B ⇏ la classe B est amie de la classe A (pas de
symétrie)

▪ Si la classe A est amie de la classe B ET si la classe B est amie de la classe C ⇏ la


classe A est amie de la classe C (pas de transitivité)

▪ Quand utiliser l’amitié ?

▪ Dans le cas de l'amitié décrite dans "fonction indépendante, amie d'une classe", assez souvent
l'amitié est utilisée quand la fonction manipule plus de deux objets à la fois.
▪ Utiliser une fonction membre quand vous pouvez, et une fonction amie quand vous êtes dans
l'obligation de le faire.

19
Exercices

Soit une classe vecteur3d ayant 3 données membres privées, de type entier, les composantes du vecteur
(x,y,z). Elle a un constructeur permettant d’initialiser les données membres.
1 Ecrire une fonction indépendante, coincide, amie de la classe vecteur3d, permettant de savoir si 2
vecteurs ont mêmes composantes. Si v1 et v2 désignent 2 vecteurs de type vecteur3d, écrire le
programme qui permet de tester l’égalité de ces 2 vecteurs.

20
#include<iostream>
using namespace std ;

class vecteur3d{
int x;int y;int z;
public:
vecteur3d(int a=0,int b=0, int c=0);
friend void coincide (vecteur3d p, vecteur3d q);};
vecteur3d::vecteur3d(int a,int b,int c){
x=a;y=b;z=c;
}
void coincide(vecteur3d p, vecteur3d q){
if(p.x==q.x && p.y==q.y && p.z==q.z){
cout<<"Les 2 vecteurs sont egaux"<<endl;
}
else
cout<<"les deux vecteurs ne sont pas egaux"<<endl;}
main(){
vecteur3d v1(3,2,5);
vecteur3d v2(3,4,5);
coincide(v1,v2);
}

21
Exercices
1. Créer 2 classes (dont les membres données sont privés) :

• l’une nommée vecteur, permettant de représenter des vecteurs à 3 composantes de type int ; elle
comportera un constructeur et une fonction membre affiche.
• L’autre nommée matrice, permettant de représenter des matrices carrées de dimension 3x3 ; elle
comportera un constructeur avec un argument (adresse d’un tableau de 3x3 valeurs) qui
initialisera la matrice avec les valeurs correspondantes.
2
2. Réaliser une fonction indépendante prod permettant de fournir le vecteur correspondant au produit
d’une matrice par un vecteur.
3. Réaliser une fonction membre vecteur prod(matrice) faisant le même travail que la fonction
indépendante
4. Ecrire un programme de test.

22
23
#include<iostream>
using namespace std;
class matrice;
class vecteur{
int v[3];
public:
vecteur(int *tab){
for(int i=0;i<3;i++)
v[i] = tab[i];
}
vecteur(){
for(int i=0;i<3;i++)
v[i] = 0;
}
void affiche(){cout<<"("<<v[0]<<","<<v[1]<<","<<v[2]<<")"<<endl;}

//Décalartion d'amitié pour la fonction indépendante


friend vecteur produit(matrice,vecteur);

//Déclaration de la fonction membre


vecteur produit(matrice);
};

24
class matrice{
int m[3][3];
public:
matrice(int tab[3][3]){
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
m[i][j] = tab[i][j]; }
matrice() {
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
m[i][j] = 0; }
void affiche() {
for(int i=0;i<3;i++) {
for(int j=0;j<3;j++)
cout<<m[i][j]<<" ";
cout<<endl;
}
}
//Décalartion d'amitié pour la fonction indépendante
friend vecteur produit(matrice,vecteur);

//Décalartion d'amitié pour la fonction membre à la classe vecteur


friend vecteur vecteur::produit(matrice);
25
};
//Définition de la fonction indépendante
vecteur produit(matrice M, vecteur V)
{
vecteur r;
for(int i=0;i<3;i++)
{
r.v[i]=0;
for(int j=0;j<3;j++){
r.v[i] += M.m[i][j] * V.v[j];
}
}
return r;
}

//Définition de la fonction membre à la classe Vecteur


vecteur vecteur::produit(matrice M)
{
vecteur r;
for(int i=0;i<3;i++)
{
r.v[i]=0;
for(int j=0;j<3;j++){
r.v[i]+=M.m[i][j]*v[j];
}
}
return r; 26
}
int main()
{
int A[3]={1,2,3},B[3][3]={{4,2,1},{8,7,0},{3,5,6}};
vecteur V(A);
matrice M(B);
cout << "Affichage du vecteur V: " << endl;
V.affiche();
cout << endl << "Affichage de la matrice M: " << endl;
M.affiche();
vecteur res;
cout << endl << "Appel avec la fonction independante: " << endl;
res=produit(M,V);
cout << "Le vecteur produit M*V: " << endl;
res.affiche();

cout << endl << "Appel avec la fonction membre: " << endl;
res=V.produit(M);
cout << "Le vecteur produit M*V: " << endl;
res.affiche();

return 0;
}
27
#include <iostream>
using namespace std; Toutes les méthodes de Amie sont amies.
class Hote{
friend class Amie;
int i, j; // Donnée privée de la classe Hote.
public:
Hote(){ i=3; j=6;
cout<<" Les données privées de la classe Hote sont\n"<<"i = "<<i<<"
"<<"j="<<j<<endl;
}
void affiche(){cout<<"i="<<i<<" "<<"j="<<j<<endl;}
};
Hote h;
class Amie
{
public:
void print_hote(){
cout<<" La valeur cherchee est \n"<<"i= "<<h.i<<" "<<"j= "<<h.j<<endl;
}
};
int main(){
Amie a;
a.print_hote();

cout<<"\n";
system ("PAUSE");
28
return 0;
}

Vous aimerez peut-être aussi