Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

POO : Langage C++

Séquence 2 : Fonctions amies et surcharges d’opérateurs

POO : Langage C++


Dr Khalifa SYLLA
Séquence 2 : Fonctions amies et surcharges d’opérateurs

I. Introduction
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. Le principe d’encapsulation interdit à une fonction membre d’une classe
d’accéder à des données privées d’une autre classe.
Grâce aux fonctions amies, on pourra accéder aux membres privés d’une classe. 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é :

 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.

II. FONCTION INDEPENDANTE AMIE D’UNE CLASSE


Une fonction indépendante amie d’une classe est une fonction ordinaire qui peut manipuler les membres
privés d’une autre classe. L'amitié est déclarée en utilisant le mot-clé friend.
Syntaxe
Class NomClasse{
friend type nomfonction(parametres) ;
friend type nomfonction2(parametres2) ;
}

Dr Khalifa SYLLA 1
POO : Langage C++
Séquence 2 : Fonctions amies et surcharges d’opérateurs

Considérons la classe Point(x,y) définie dans les exercices précédents, faire une fonction coincide qui
permet de tester si deux sont égaux. La fonction coïncide est indépendante et amie de la classe point.
Créez un fichier tpfonctionamies.cpp

int main()
{ point a(0,0), b, c ;
if ( coincide (a,b) )
cout<< "A coincide avec B"<<endl;
else
cout<<"A et B sont différents"<<endl;
return 0:
};

Dr Khalifa SYLLA 2
POO : Langage C++
Séquence 2 : Fonctions amies et surcharges d’opérateurs

III. Fonction membre d’une classe amie d’une autre classe


Considérons la fonction fct, membre de la classe B, ayant le prototype spécifié, est autorisée à accéder aux
membres privés de la classe A. Pour qu’il puisse compiler convenablement la déclaration de A, donc en
particulier la déclaration d’amitié relative à fct, le compilateur devra connaître la déclaration de B (mais pas
nécessairement sa définition). Généralement, la fonction membre fct possédera un argument ou une valeur de
retour de type A. Pour compiler sa déclaration (au sein de la déclaration de A), il suffira au compilateur de savoir
que A est une classe ; si sa déclaration n’est pas connue à ce niveau, on pourra se contenter de : class A ; En
revanche, pour compiler la définition de fct, le compilateur devra posséder les caractéristiques de A, donc
disposer de sa déclaration.

class A { ..... friend int B :: fct () ;


; ..... } ;

IV. Toutes les fonctions d’une classe B sont amies d’une autre classe A
Dans ce cas, plutôt que d’utiliser autant de déclarations d’amitié que de fonctions membre, on utilise (dans la
déclaration de la classe A) la déclaration (globale) suivante : friend class B ; Pour compiler la déclaration de
A, on précisera simplement que B est une classe par : class B ; Quant à la déclaration de la classe B, elle
nécessitera généralement (dès qu’une de ses fonctions membre possédera un argument ou une valeur de retour
de type A) la déclaration de la classe A.

Remarque
L’amitié n’est ni symétrique ni transitive
- Si la classe A est amie de la classe B n’implique pas que 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 n’implique pas que la classe A
est amie de la classe C (pas de transitivité).

- Souvent l'amitié est utilisée quand la fonction manipule plus de deux objets à la fois. - Sinon, on utilise une
fonction membre d'une classe.
- Utiliser une fonction membre quand vous pouvez, et une fonction amie quand vous êtes dans l'obligation de
le faire.

Dr Khalifa SYLLA 3
POO : Langage C++
Séquence 2 : Fonctions amies et surcharges d’opérateurs

Exercice 1
Soit la classe point suivante : class point { int x, y ; public : point (int abs=0, int ord=0) { x = abs ; y = ord ; } }
; Écrire une fonction indépendante affiche, amie de la classe point, permettant d’afficher les coordonnées d’un
point. On fournira séparément un fichier source contenant la nouvelle déclaration (définition) de point et un
fichier source contenant la définition de la fonction affiche. Écrire un petit programme (main) qui crée un point
de classe automatique et un point de classe dynamique et qui en affiche les coordonnées.

Exercice 2
Créer deux classes (dont les membres donnés sont privés) :
 L’une, nommée vect, permettant de représenter des vecteurs à 3 composantes de type double; elle comportera
un constructeur et une fonction membre d’affichage ;
 L’autre, nommée matrice, permettant de représenter des matrices carrées de dimension 3 x 3 ; elle
comportera un constructeur avec un argument (adresse d’un tableau de 3 x 3 valeurs) qui initialisera la
matrice avec les valeurs correspondantes. Réaliser une fonction indépendante prod permettant de fournir le
vecteur correspondant au produit d’une matrice par un vecteur. Écrire un petit programme de test. On
fournira séparément les deux déclarations de chacune des classes, leurs deux définitions, la définition de
prod et le programme de test

Surcharges d’opérateurs

Un opérateur est une opération sur un ou entre deux opérande(s) (variable(s)/expression(s)) :


 opérateurs arithmétiques (+, -, *, /, ...),
 opérateurs logiques (&&, ||, !),
 opérateurs de comparaison (==, >=, <=, ...),
 opérateur d’incrément (++).

Considérons une classe Complexe chargée d’implémenter la gestion des nombres complexes dans un
programme. On va certainement être amené à définir les opérations courantes sur ces nombres. Par exemple,
l’addition entre deux nombres complexes pourrait se définir comme une fonction ayant comme prototype :
Complexe add(const Complexe &) ; Pour appeler cette fonction dans un programme on utilisera la syntaxe
suivante :
Complexe c1(1, 1), c2(2, 2);
Complexe c3 = c1.add(c2) ;

Cette solution marche bien, mais on est habitué à une écriture qui nous semble plus naturelle : On aurait envie
d’écrire : Complexe c3 = c1 + c2;
L’opérateur ‘+’ existe bien en C++, mais il n’existe que pour des types prédéfinis, de base, tels que int, float,
double, etc. Pour que nous puissions l’utiliser dans le cadre des nombres complexes que nous avons définis, il
faudrait que nous puissions le redéfinir dans ce contexte.
Le langage C++ autorise le programmeur à étendre la signification d’opérateurs.
On appelle ce mécanisme la surcharge ou surdéfinition d’opérateurs.

Dr Khalifa SYLLA 4
POO : Langage C++
Séquence 2 : Fonctions amies et surcharges d’opérateurs

La plupart des opérateurs peuvent être redéfinis ou surchargés, seuls quelques-uns échappent à cette règle. Les
opérateurs suivants ne peuvent pas être redéfinis :
o :: (opérateur de résolution de portée)
o . (opérateur point, pour accéder aux champs d’un objet)
o sizeof
o ?: (opérateur ternaire)

Les opérateurs C++ que l’on surcharge habituellement sont:


– Affectation, affectation avec opération (=, +=, *=, etc.) : Méthode
– Opérateur « fonction » () : Méthode
– Opérateur « indirection » * : Méthode
– Opérateur « crochets » [] : Méthode
– Incrémentation ++, décrémentation −− : Méthode
– Opérateur « flèche » et « flèche appel » -> et ->* : Méthode
– Opérateurs de décalage « et » : Méthode
– Opérateurs new et delete : Méthode
– Opérateurs de lecture et écriture sur flux « et » : Fonction

Surcharge d’un operateur par une fonction membre


Une première méthode pour surcharger les opérateurs consiste à les considérer comme des méthodes normales
de la classe sur laquelle ils s'appliquent. Le nom de ces méthodes est donné par le mot clé operator, suivi de
l'opérateur à surcharger. Le type de la fonction de l'opérateur est le type du résultat donné par l'opération, et les
paramètres, donnés entre parenthèses, sont les opérandes. Les opérateurs de ce type sont appelés opérateurs
internes, parce qu'ils sont déclarés à l'intérieur de la classe.
syntaxe :
type operatorOp(paramètres)

A Op B
se traduisant par :
A.operatorOp(B)
Avec cette syntaxe, le premier opérande est toujours l'objet auquel cette fonction s'applique. Les paramètres de
la fonction opérateur sont alors le deuxième opérande et les suivants.
Les opérateurs définis en interne devront souvent renvoyer l'objet sur lequel ils travaillent Cela est faisable grâce
au pointeur this.

Dr Khalifa SYLLA 5
POO : Langage C++
Séquence 2 : Fonctions amies et surcharges d’opérateurs

Exemple

class complexe
{
double m_x, m_y; // Les parties réelles et imaginaires.
public:
// Constructeurs et opérateur de copie :
complexe(double x=0, double y=0);
complexe(const complexe &);
complexe &operator=(const complexe &);

// surcharges des opérateurs de base:


complexe &operator+=(const complexe &);
complexe &operator-=(const complexe &);
complexe &operator*=(const complexe &);
complexe &operator/=(const complexe &);
};

complexe::complexe(double x, double y)
{
m_x = x;
m_y = y;
return ;
}

complexe::complexe(const complexe &source)


{
m_x = source.m_x;
m_y = source.m_y;
return ;
}

complexe &complexe::operator=(const complexe &source)


{
m_x = source.m_x;
m_y = source.m_y;
return *this;
}

complexe &complexe::operator+=(const complexe &c)


{
m_x += c.m_x;
m_y += c.m_y;
return *this;
}

complexe &complexe::operator-=(const complexe &c)


{
m_x -= c.m_x;
m_y -= c.m_y;
return *this;
}

complexe &complexe::operator*=(const complexe &c)


{
double temp = m_x*c.m_x -m_y*c.m_y;
m_y = m_x*c.m_y + m_y*c.m_x;
m_x = temp;
return *this;
}

complexe &complexe::operator/=(const complexe &c)

Dr Khalifa SYLLA 6
POO : Langage C++
Séquence 2 : Fonctions amies et surcharges d’opérateurs

{
double norm = c.m_x*c.m_x + c.m_y*c.m_y;
double temp = (m_x*c.m_x + m_y*c.m_y) / norm;
m_y = (-m_x*c.m_y + m_y*c.m_x) / norm;
m_x = temp;
return *this;
}

Surcharge des opérateurs externes

Une deuxième possibilité nous est offerte par le langage pour surcharger les opérateurs. La définition de
l'opérateur ne se fait plus dans la classe qui l'utilise, mais en dehors de celle-ci, par surcharge d'un opérateur de
l'espace de nommage global. Il s'agit donc d'opérateurs externes cette fois.

La surcharge des opérateurs externes se fait donc exactement comme on surcharge les fonctions normales. Dans
ce cas, tous les opérandes de l'opérateur devront être passés en paramètres : il n'y aura pas de paramètre implicite
(le pointeur this n'est pas passé en paramètre).

La syntaxe est la suivante :

type operatorOp(opérandes)
où opérandes est la liste complète des opérandes.

Exemple

class complexe
{
friend complexe operator+(const complexe &, const complexe &);
friend complexe operator-(const complexe &, const complexe &);
friend complexe operator*(const complexe &, const complexe &);
friend complexe operator/(const complexe &, const complexe &);

double m_x, m_y; // Les parties réelles et imaginaires.


public:
// Constructeurs et opérateur de copie :
complexe(double x=0, double y=0);
complexe(const complexe &);
complexe &operator=(const complexe &);

// Surcharge des opérateurs de base:


complexe &operator+=(const complexe &);
complexe &operator-=(const complexe &);
complexe &operator*=(const complexe &);
complexe &operator/=(const complexe &);
};

Dr Khalifa SYLLA 7
POO : Langage C++
Séquence 2 : Fonctions amies et surcharges d’opérateurs

complexe operator+(const complexe &c1, const complexe &c2)


{
complexe result = c1;
return result += c2;
}

complexe operator-(const complexe &c1, const complexe &c2)


{
complexe result = c1;
return result -= c2;
}

complexe operator*(const complexe &c1, const complexe &c2)


{
complexe result = c1;
return result *= c2;
}

complexe operator/(const complexe &c1, const complexe &c2)


{
complexe result = c1;
return result /= c2;
}

complexe operator+(const complexe &c1, const complexe &c2)


{
return complexe(c1.m_x + c2.m_x, c1.m_y + c2.m_y);
}

complexe operator*(double k, const complexe &c)


{
complexe result(c.re()*k,c.im()*k);
return result;
}

Dr Khalifa SYLLA 8

You might also like