Vous êtes sur la page 1sur 34

Fonctions et classes amies

Surcharge d’opérateurs

Programmations Orientées Objet


Programmation en C++

Laila AMIR

IRISI & Licence SIR


Année universitaire 2013/2014

Laila AMIR Programmations Orientées Objet


Fonctions et classes amies
Surcharge d’opérateurs

Plan

1 Fonctions et classes amies


fonction indépendante, amie d’une classe
fonction membre d’une classe, amie d’une autre classe
fonction amie de plusieurs classes
classe amie

2 Surcharge d’opérateurs
Les opérateurs que l’on peut surcharger
Surcharge des opérateurs externes
Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Laila AMIR Programmations Orientées Objet


Fonctions et classes amies
Surcharge d’opérateurs

Plan

1 Fonctions et classes amies


fonction indépendante, amie d’une classe
fonction membre d’une classe, amie d’une autre classe
fonction amie de plusieurs classes
classe amie

2 Surcharge d’opérateurs
Les opérateurs que l’on peut surcharger
Surcharge des opérateurs externes
Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

Plan

1 Fonctions et classes amies


fonction indépendante, amie d’une classe
fonction membre d’une classe, amie d’une autre classe
fonction amie de plusieurs classes
classe amie

2 Surcharge d’opérateurs
Les opérateurs que l’on peut surcharger
Surcharge des opérateurs externes
Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

mot-clé friend

encapsulation –> interdiction d’accès aux données privées


En POO pure, l’encapsulation des données est obligatoire. Dans ce cadre,
une fonction membre d’une classe ou une fonction indépendante ne peut
accéder aux données privées (resp. protégées) d’une autre classe (resp.
autre qu’une dérivée).

Amitié –>Autorisation d’accès aux données privées


Afin de rendre accessibles les données privées (ou protégées) d’une classe à
une fonction, on déclare cette fonction amie avec le mot-clé friend dans
cette classe pour laquelle on souhaite accéder aux membres.

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

mot-clé friend

encapsulation –> interdiction d’accès aux données privées


En POO pure, l’encapsulation des données est obligatoire. Dans ce cadre,
une fonction membre d’une classe ou une fonction indépendante ne peut
accéder aux données privées (resp. protégées) d’une autre classe (resp.
autre qu’une dérivée).

Amitié –>Autorisation d’accès aux données privées


Afin de rendre accessibles les données privées (ou protégées) d’une classe à
une fonction, on déclare cette fonction amie avec le mot-clé friend dans
cette classe pour laquelle on souhaite accéder aux membres.

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

Situations d’amitié

Il existe plusieurs 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 :
classe amie

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

Exemple : fonction indépendante, amie d’une classe

class Point {
int x; int y;
public:
Point(int a, int b) { x = a; y = b; };
friend int coincide(Point, Point);
};
int coincide(Point p, Point q) {
if ((p.x==q.x)&&(p.y==q.y)) return 1 ;
else return 0 ;
}

coincide est une fonction indépendante de la classe Point,


coincide est une fonction amie (friend) de la classe Point, donc elle
est autorisée à accéder aux données privés de la classe.

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

fonction membre d’une classe, amie d’une autre classe

class B {
class A {
...
//Partie privée
int fct(char, A);
...
};
//Partie publique
int B::fct(char c, A a){
...
//accès aux membres privés de A
friend int B::fct(char, A);
...
};
};

La fonction fct membre de la classe B est autorisée à accéder aux


membres privés de la classe A.
La fonction membre fct possédera un argument ou une valeur de
retour de type A (ce qui justifiera sa déclaration d’amitié).

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

fonction membre d’une classe, amie d’une autre classe

Pour compiler convenablement les déclarations de la classe A


contenant une déclaration d’amitié telle que :
friend int B::fct(char, A);
le compilateur a besoin de connaı̂tre les caractéristiques de la classe B,
cela signifié que la déclaration de B (pas nécessairement la définition
des fonctions membres) dera avoir été compilé avant celle de A.

Mais pour compiler convenablement la déclaration :


int fct(char, A);
au sein de la classe B, le compilateur n’a pas besoin de connaı̂tre les
caractéristiques de A. Il lui suffit de savoir qu’il s’agit d’une classe.
Ceci est possible avec l’instruction :
class A;

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

fonction membre d’une classe, amie d’une autre classe

A titre indicatif, voici une façon de compiler les deux classes :

class A;
class B {
int fct(char, A);
};
class A {
...
friend int B::fct(char, A);
};
int B::fct(char c, A a){
//accès aux membres privés de A
...
};

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

fonction amie de plusieurs classes


C’est le cas d’une fonction (indépendante, ou membre d’une autre classe)
qui fait l’objet de déclarations d’amitié dans différentes classes.

class A { class B {
//Partie privée //Partie privée
... ...
//Partie publique //Partie publique
friend int fct(A, B); friend int fct(A, B);
}; };
int fct(A a, B b){
//accès aux membres privés des objets de type A ou B
};

Pour la compilation, on utilise l’une des deux déclarations (class A; si B


est déclarée avant A, ou class B; sinon).

Laila AMIR Programmations Orientées Objet


fonction indépendante, amie d’une classe
Fonctions et classes amies fonction membre d’une classe, amie d’une autre classe
Surcharge d’opérateurs fonction amie de plusieurs classes
classe amie

classe amie

Un ensemble de fonctions peuvent être amies d’une classe. En particulier


toute une classe peut être amie d’une autre. Pour dire que toutes les
fonctions membres de la classe AutreClasse sont amies de la classe Point,
on notera :

class Point { ...


friend class AutreClasse;
...
};

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Plan

1 Fonctions et classes amies


fonction indépendante, amie d’une classe
fonction membre d’une classe, amie d’une autre classe
fonction amie de plusieurs classes
classe amie

2 Surcharge d’opérateurs
Les opérateurs que l’on peut surcharger
Surcharge des opérateurs externes
Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Surcharge d’opérateurs

C++ permet de surdéfinir les opérateurs éxistants (+, -, *, ++, +=,


=, ==,...), c-à-d de leur donner une nouvelle signification lorsqu’ils
portent sur des objets de type classe.
Pour surdéfinir un opérateur existant op, on définit une fonction
nommée operator op :
Soit sous forme d’une fonction indépendante (généralement une
fonction amie) => opérateur externe;
Dans le cas où op est opérateur binaire, la notation a op b est
équivalente à operator op (a, b).
Soit sous forme d’une fonction membre de classe => opérateur
interne;
Dans le cas où op est opérateur binaire, la notation a op b est
équivalente à a.operator op (b).

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Se limiter aux opérateurs existants

Le symbole suivant le mot clé operator doit obligatoirement un


opérateur déjà défini pour les types de base. Il n’est donc pas
possible de créer des nouveaux symboles.
Certains opérateurs ne peuvent pas être redéfinis du tout. c’est le cas
de l’opérateur . (pour la sélection de membre) et l’opérateur :: (pour
la résolution de portée)
Certains opérateurs imposent quelques contraintes supplémentaires.
Par exemple, il faut conserver la pluralité (unaire, binaire) de
l’opérateur initial. Ainsi, on ne peut pas surdéfinir de = unaire et de
++ binaire.
Les opérateurs ainsi surdéfinis gardent leur priorité et leur
associativité.

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 1 : surcharge de l’opérateur + avec une fonction amie

On veut redéfinir l’opérateur + afin de donner une signification à


l’expression a+b, lorsque a et b sont de type Point :
Le prototype de notre fonction operator + sera :

Point operator + (Point, Point);

Ses deux arguments correspondront aux opérandes de l’opérateur +


lorsqu’il sera appliqué à des valeurs de type Point.
La valeur de retour représente le résultat de l’opération;
Le reste du travail est classique :
déclaration d’amitié au sein de la classe point;
définition de la fonction;

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 1 : surcharge de l’opérateur + avec une fonction amie

class Point {
int x; int y;
public:
Point(int abs=0, int ord=0) { x = abs; y = ord; };
friend Point operator + (Point, Point);
void affiche (){cout<<”coordonnées :”<<x<<” ”<<y<<endl; };
};
Point operator + (Point a, Point b) {
Point p;
p.x = a.x + b.x; p.y = a.y + b.y;
return p;
}

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 1 : surcharge de l’opérateur + avec une fonction amie

main(){ Résultat :
Point a(1,2); a.affiche();
Point b(2,5); b.affiche(); coordonnées : 1 2
Point c; coordonnées : 2 5
c = a+b; c.affiche(); coordonnées : 3 7
}

L’expression a+b est interprétée par le compilateur comme l’appel :


operator + (a, b);
c = a + b est équivalente à c = operator + (a, b);
Une expression telle que a+b+c est évaluée en tenant compte les
règles de priorité et d’associativité de l’opérateur +
a + b + c est évaluée comme (a + b) + c qui est interprétée par le
compilateur comme l’appel : operator + (operator + (a, b), c);
Laila AMIR Programmations Orientées Objet
Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 1 : surcharge de l’opérateur + avec une fonction amie

main(){ Résultat :
Point a(1,2); a.affiche();
Point b(2,5); b.affiche(); coordonnées : 1 2
Point c; coordonnées : 2 5
c = a+b; c.affiche(); coordonnées : 3 7
}

L’expression a+b est interprétée par le compilateur comme l’appel :


operator + (a, b);
c = a + b est équivalente à c = operator + (a, b);
Une expression telle que a+b+c est évaluée en tenant compte les
règles de priorité et d’associativité de l’opérateur +
a + b + c est évaluée comme (a + b) + c qui est interprétée par le
compilateur comme l’appel : operator + (operator + (a, b), c);
Laila AMIR Programmations Orientées Objet
Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 2 : surcharge de l’opérateur + avec une fonction membre

Cette fois, le premier opérande sera l’objet ayant appelé la fonction


membre. Ainsi une expression telle que a + b sera interprétée par le
compilateur comme : a.operator + (b);.
Le prototype de notre fonction membre operator + sera donc :

Point operator + (Point);

Voici comment l’exemple précédent pourrait être adapté :

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 2 : surcharge de l’opérateur + avec une fonction membre

class Point {
int x; int y;
public:
Point(int abs=0, ord b=0) { x = abs; y = ord; };
Point operator + (Point);
void affiche (){cout<<”coordonnées :”<<x<<” ”<<y<<endl; };
};
Point Point::operator + (Point b) {
Point p;
p.x = x + b.x; p.y = y + b.y;
return p;
}

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 2 : surcharge de l’opérateur + avec une fonction membre

main(){ Résultat :
Point a(1,2); a.affiche();
Point b(2,5); b.affiche(); coordonnées : 1 2
Point c; coordonnées : 2 5
c = a+b; c.affiche(); coordonnées : 3 7
}

a+b est interprétée par le compilateur comme l’appel :


a.operator + (b);
c = a + b est équivalente à c = a.operator + (b);

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple 2 : surcharge de l’opérateur + avec une fonction membre

Mais une expression telle que f= a+b+c est évaluée différement selon
le compilateur :

Certains compilateurs créeront un objet temporaire t :


t = a.operator + (b);
f= t.operator + (c);

D’autres compilateurs l’interprète comme l’appel :


f = (a.operator + (b)).operator + (c);

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Choisir entre surcharge interne ou externe?


Comment choisir si l’on doit définir un opérateur surchargé en tant que
méthode ou bien en tant que fonction externe à la classe ?

Une règle bien utile:


En règle générale, nous appliquerons la règle suivante pour déterminer si
un opérateur doit être surchargé en tant que méthode membre ou en tant
que fonction externe (éventuellement amie).

Un opérateur ne sera déclaré en tant que méthode membre que


dans les cas où this joue un rôle privilégié par rapport aux autres
arguments.
Autrement : Un opérateur sera déclaré externe si l’opération n’induit
pas de modification des données membre de l’objet en entrée.

Donnons deux exemples qui nous permettrons de juger du bien fondé de


cette règle fondée sur des critères conceptuels.
Laila AMIR Programmations Orientées Objet
Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Le cas de l’opérateur d’affectation

Soit le cas de l’opérateur d’affectation que nous écrivons comme une


méthode membre de la classe T. Etudions les rôles respectifs de
l’argument par défaut this et de l’argument explicite a.

T& T::operator=(const T&a)


L’argument a n’est accédé qu’en lecture et l’opération ne modifie
en rien son statut.
En revanche, this est considérablement modifié car, a priori, tous ces
attributs sont modifiés. En outre, c’est une référence sur l’objet
*this qui est renvoyée par l’opérateur.
this joue un rôle privilégié par rapport au second argument a, il est donc
logique que ce soit une méthode membre de la classe T.

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Le cas de l’opérateur d’addition

Equipons notre classe T d’un opérateur dyadique quelconque, par exemple,


l’addition. Si nous décidons d’en faire une méthode, son prototype sera :

T T::operator+(const T&a)
Etudions les rôles respectifs de l’argument par défaut this et de l’argument
explicite a. Dans une addition, aucun des deux membres n’est
modifié et le résultat n’est ni le membre de gauche, ni celui de droite : en
fait les deux arguments jouent un rôle absolument symétrique.

De ce fait, this n’a pas un rôle privilégié par rapport à a et l’opérateur est
alors transformé en fonction externe, soit :

T ::operator+(const T&a, const T&b)

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

interne ?

Soit l’exemple : multiplication d’un point par un réel

Point Point::operator*(double d){ int main ( ){


Point Q; Point P ( 3 , 1 ) ;
Q.x = x * d ; Point Q = P * 2. ;
Q.y = y * d ; };
return Q;
P*2. => P.(operator *)(2.)
}
2*P n’est pas possible !

Surcharge interne ne fonctionne pas pour l’opération : double * Point

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

externe?
Déclaration à l’extérieur d’une classe : surcharge externe (à 2 arguments)

Point operator * (double d, Point & P) int main ( ){


{ Point M( 3 , 1 ) ;
Point Q; Point Q=3*M; // * externe
Q.x=P.x * d ; Point P= M*2 ; // *
Q.y=P.y * d ; //interne ou externe
return Q; }
}
Point operator * (Point & P, double d){
Point Q;
Q.x=P.x * d ;
Q.y=P.y * d ;
return Q;
}
Laila AMIR Programmations Orientées Objet
Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Les opérateurs de redirection << et >>


Supposons, que l’on souhaite surcharger les opérateurs << pour écrire le
contenu de T sur un flux en sortie (ostream) et >> pour lire depuis un
flux en entrée (istream) le contenu de T.
Ces opérations ne peuvent absolument pas être codées en tant que
méthodes membres de T. Les résultats désastreux que cela pourrait avoir:
Avec la déclaration : T t;
class T {
L’utilisation d’opérateur << :
public:
ostream &operator<<(ostream &a){ t.operator<<(cout);
// ...
return a; ou :
}
t << cout;
};
Ce qui ne correspond absolument pas à l’utilisation habituelle de cet
opérateur.
Laila AMIR Programmations Orientées Objet
Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Le seul moyen d’utiliser une méthode pour le surcharger avec sa syntaxe


habituelle serait donc de l’inclure dans la classe ostream, ce qui est
inconcevable. Il est donc nécessaire de le définir sous la forme d’une
fonction externe, soit :

ostream &operator<<(ostream &a, const T &t)

Il sera également judicieux de déclarer sous forme d’une fonction externe


l’opérateur de redirection depuis un flux.

Laila AMIR Programmations Orientées Objet


Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Exemple : Surcharge des opérateurs << et >> pour la


classe Point
Surcharge des opérateurs << et >> pour un flux d’écriture ou de lecture
ostream & operator <<(ostream &out , const Point &P){
out<<”Point : ” ;
out<<P.x <<” ” ;
out<<P.y <<” ” ;
return out ;
}

istream & operator >>(istream &in , const Point &P){


in>>P.x ;
in>>P.y ;
return in ;
}
Laila AMIR Programmations Orientées Objet
Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Surcharge interne conseillée


Pour les opérateurs unaires ”auto-écrasants” += -= *= /= ... surcharge
interne (données membre modifiées).
Exemple : Point *=double
class Point{
public :
Point & operator *= ( double d ) ;
};
Point & Point::operator *= ( double d ){
x*=d ;
y*=d ;
return *this ;
}
On retourne une référence sur l’objet lui-même (*this), autorise :
M=(P*=2)
Laila AMIR Programmations Orientées Objet
Les opérateurs que l’on peut surcharger
Fonctions et classes amies Surcharge des opérateurs externes
Surcharge d’opérateurs Surcharge des opérateurs internes
Choisir entre surcharge interne ou externe?

Récapitulatif

Le tableau suivant récapitule quels opérateurs seront décrits en tant que


méthode membre interne ou fonction externe :
Affectation, affectation avec opération (=, +=, *=, etc.) interne
Opérateur ”fonction” () interne
Opérateur ” crochets ” [] interne
Incrémentation ++, décrémentation – interne
Opérateurs new et delete interne
Opérateurs de lecture et écriture sur flux << et >> externe
Opérateurs dyadiques genre ”arithmétique ” (+, -, / etc.) externe

Laila AMIR Programmations Orientées Objet

Vous aimerez peut-être aussi