Vous êtes sur la page 1sur 38

Surdéfinition des opérateurs

Plan du cours

▪ Introduction
▪ Le mécanisme de la surdéfinition d’opérateurs
▪ Les possibilités et les limites de la surdéfinition d’opérateurs en C++
▪ Exemple de surdefinition de l’operateur ‘=’
▪ Exemple de surdefinition de l’operateur ‘[ ]’
▪ Exemple de surdefinition des operateurs >> et <<

2
Introduction
▪ En langage C, l'opérateur division « / » est défini comme suit:
▪ 3/2 Division de deux valeurs entières
▪ 3.3/2.1 Division de deux valeurs réelles

▪ L’opérateur « / » a été redéfini afin de réaliser deux types de division: une entière et
une réelle.

▪ En langage C++, il est possible de redéfinir cet opérateur pour les classes.

▪ Pourquoi?
▪ Afin d'assurer une meilleure intégration des classes au programme.
▪ Permet de fournir aux utilisateurs des interfaces plus simples à manipuler.

3
Introduction
▪ Comment?
▪ Les opérateurs ont tous le même préfixe : « operator ».
▪ Ainsi donc, surcharger l’opérateur « /» consiste à définir la méthode « operator ».
/

▪ Cette méthode désigne la fonction à 2 opérandes associée à l'opérateur «/»


▪ Un des opérandes doit être de type classe.
▪ Les arguments ne peuvent pas avoir des valeurs par défaut.
▪ La priorité et l’associativité des opérateurs ne changent pas (standard).
▪ Les opérateurs peuvent être définis comme membres ou non membres d'une classe.

4
Le mécanisme de la surdéfinition d’opérateurs
▪ Pour surdéfinir un operateur ‘Op’, il faut définir une fonction de nom : ‘operator op’.

▪ Syntaxe

type_de_retour operator op (parametres)

▪ Exemple

point operator + (point, point) ;

5
Le mécanisme de la surdéfinition d’opérateurs
▪ Ici, notre fonction operator+ doit disposer de deux arguments de type point et
fournir une valeur de retour du même type. En ce qui concerne sa nature, cette
fonction peut à notre gré être une fonction membre de la classe concernée ou
une fonction indépendante ; dans ce dernier cas, il s'agira généralement d'une
fonction amie, car elle devra pouvoir accéder aux membres privés de la classe.
Deux solutions
sont possibles
pour surcharger un
opérateur

En utilisant une En utilisant une


fonction membre fonction amie

6
Le mécanisme de la surdéfinition d’opérateurs
1 . Surdefinition d’operateur avec une fonction amie (exemple)

class point
{
int x, y ; main ()
public : point operator + (point p1 ,point p2) {
point (int a=0 , int b=0) { point o1(10,20) ; o1.affiche () ;
{ x=a ; y=b ;} point p; point o2(40,50) ; o2.affiche () ;
void affiche () p.x=p1.x+p2.x; point o3 ; o3.affiche() ;
{ cout<<″Les points : ″<<x<<″ - ″ p.y=p1.y+p2.y ; o3=o3+o2 ; o3.affiche () ;
<<y<<endl ; return p ; o3=o3+o1+o2 ; o3.affiche () ;
} } }
friend point operator+ (point, point) ;
}; Operateur + surchargé

Classe Point Fonction main


7
Le mécanisme de la surdéfinition d’opérateurs
2 . Surdéfinition d’opérateur avec une fonction membre

▪ L’expression ‘o1+o2’ sera interprétée par le compilateur comme l’expression


o1.operator+(o2) .
▪ Le prototype de la fonction membre ‘operator+’ sera donc ‘point operator +
(point)’

8
Le mécanisme de la surdéfinition d’opérateurs
2 . Surdéfinition d’opérateur avec une fonction membre
▪ Exemple
class point
{
int x, y ;
void main ()
public :
point point::operator + (point p1) {
point (int a=0, int b=0)
{ point o1(10,20) ; o1.affiche () ;
{ x=a ; y=b ; }
point p ; point o2(40,50) ; o2.affiche () ;
void affiche ()
p.x=x+p1.x ; p.y=y+p1.y ; point o3 ; o3.affiche () ;
{
return p ; o3=o3+o2 ; o3.affiche () ;
cout<<″Point : ″<<x<<″ - ″<<y<<endl
} o3=o3+o1+o2 ; o3.affiche ( ) ;
;
}
}
point operator + (point) ; Operateur + surchargé
};
Classe Point Fonction main
9
Le mécanisme de la surdéfinition d’opérateurs
3 . Exercices

Soit une classe vecteur3d définie comme suit :


class vecteur3d
{ float x, y, z ;
public :
vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0)
{ x = c1 ; y = c2 ; z = c3 ;
1 }
};
Définir les opérateurs == et != de manière qu’ils permettent
de tester la coïncidence ou la
non-coïncidence de deux points :
a. en utilisant des fonctions membres;
b. en utilisant des fonctions amies.

10
#include <iostream>
using namespace std;
Cas des fonctions membres class vecteur3d
{ float x, y, z ;
public :
vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0){ x = c1 ; y = c2 ; z = c3
;}
int operator== (vecteur3d) ;
int operator!= (vecteur3d) ;
};
int vecteur3d::operator == (vecteur3d v){
if ( (v.x == x) && (v.y == y) && (v.z ==z) ) return 1 ;
else return 0 ;
}
int vecteur3d::operator != (vecteur3d v)
{ return !( (*this) == v ) ;
}

main(){
vecteur3d u,v,w(1,2,3);
int i;
i=(u==v);
cout<<i<<endl;
i=(u!=w);
cout<<i<<endl;

11
#include <iostream>
using namespace std;
Cas des fonctions amies class vecteur3d
{ float x, y, z ;
public :
vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0){ x = c1 ; y = c2 ; z = c3
;}
friend int operator== (vecteur3d,vecteur3d) ;
friend int operator!= (vecteur3d,vecteur3d) ;
};
int operator == (vecteur3d v,vecteur3d u){
if ( (v.x == u.x) && (v.y == u.y) && (v.z ==u.z) ) return 1 ;
else return 0 ;
}
int operator != (vecteur3d v,vecteur3d u)
{ return ( (v.x != u.x) || (v.y != u.y) || (v.z ==u.z) ); }
main(){
vecteur3d u,v,w(1,2,3); int i;
i=(u==w);
cout<<i<<endl;
int j=(u!=w);
cout<<j<<endl;

12
Les possibilités et les limites de la surdéfinition
d’opérateurs en C++
1 . Il faut se limiter aux opérateurs existants
▪ Le symbole suivant le mot clé ‘operator’ doit obligatoirement être un operateur
déjà défini par les types de base, sauf l’operateur point ‘.’. Il n’est donc pas
possible de créer de nouveaux symboles.
▪ Lorsque plusieurs operateurs sont combinés au sein d’une même expression, ils
conservent leurs priorités relatives et leurs associativités.
▪ Il faut conserver la pluralité (unaire, binaire) de l’operateur initial.

13
Les possibilités et les limites de la surdéfinition
d’opérateurs en C++
2 . Tableau d’opérateurs surdéfinissabes
+ - * / % ^ &
⎢ ˜ ! = < > +=
<< >> >>= <<= == != <=
>= && ⎢⎥ ++ -- ->* ,
-> [] () new new[ ] delete delete[ ]

3 . Opéranteurs ne pouvant pas êtres surdéfinies

:: . .* sizeof

14
15
Les possibilités et les limites de la surdéfinition
d’opérateurs en C++
4 . Choix entre une fonction membre et une fonction amie

▪ C++ vous laisse libre de surdéfinir un opérateur à l'aide d'une fonction membre
ou d'une fonction indépendante (en général amie). Vous pouvez donc parfois
vous demander sur quels critères effectuer le choix. Certes, il semble qu’on
puisse énoncer la règle suivante :
▪ Si un opérateur doit absolument recevoir un type de base en premier argument, il ne
peut pas être défini comme fonction membre (puisque celle-ci reçoit implicitement un
premier argument du type de sa classe).

16
Exemple de surdéfinition de l’opérateur ‘=’
1 . Exemple d’une classe vecteur
▪ Remarques
▪ Une affectation vect2=vect1 ; pourrait être traitée de la façon suivante :
▪ Libération de l’emplacement pointé par vect2.
▪ Création dynamique d’un nouvel emplacement dans lequel on recopie les valeurs de
l’emplacement pointé par vect1.
▪ Mise en place des valeurs des membres données de vect2.
▪ Il faut décider de la valeur de retour fournie par l’operateur d’affectation en fonction de l’utilisation
que l’on souhaite faire (void ou autre).
▪ dans l’affectation vect2=vect1 ; vect2 est le premier opérande (ici this car l’operateur ‘=’ est une
fonction membre) et vect1 devient le second opérande (ici v).

Prototype : T& operator = ( const T& )

17
Exemple de surdéfinition de l’opérateur ‘=’
#include<iostream>
using namespace std;
class localisation{
int longitude;
int latitude;
public:
localisation(){ }; //constructeur temporaire;
localisation(int lg, int lt)
{
longitude=lg;
latitude=lt;
}
void afficher(void)
{
cout<<longitude<<" ";
cout<<latitude<<" "<<endl;
}
localisation& operator=(const localisation& op2);
};
localisation& localisation ::operator=(const localisation& op2){
longitude=op2.longitude;
latitude=op2.latitude;
return *this;
}
main(){
localisation ob1(10,20), ob2;
ob1.afficher();
ob2=ob1;
ob2.afficher();
system("pause");
};

18
Surdéfinition des opérateurs ++ et --
1 . Notation préfixée (exemple: X = ++N)

Fonction membre : T operator ++():


Fonction amie : T operator ++( T & )

2 . Notation postfixée (exemple: X = N++)


Notez bien la présence d'un second
▪ prototype
opérande de type int. Celui-ci est
totalement fictif, en ce sens qu'il
permet au compilateur de choisir
l'opérateur à utiliser mais qu'aucune
Fonction membre : X operator++(int); valeur ne sera réellement
Fonction amie: X operator++(X &, int); transmise lors de l'appel.

19
Exemple #include <iostream>
using namespace std;

class algo
{
private:
int a,b,r;

public:
algo() { a=0; b=1; r=a+b; } // constructeur par défaut

void increment() { a = b; b = r; r = a+b; }


void affiche() { cout << r << endl; }
};

main (void)
{
algo a;
int i;

for(i = 0;i<10;i++)
{
a.increment();
a.affiche();
}
}

20
Exemple: Utilisation de void operator++() {...}

La fonction opérateur est une fonction membre, elle a donc un argument implicite (this)
et accès aux données privées

exemple :

void algo::operator++()
{
a = b;
b = r;
r = a+b;
}
On va pouvoir écrire
algo X;
...
++X; // équivalent à : X.operator++()

21
#include <iostream>
using namespace std;
class algo
{
private:
int a,b,r;

public:

algo() { a=0; b=1; r=a+b; } // constructeur par défaut

void operator++ ();

void affiche() { cout << r << endl; }


};

void algo::operator++()
{
a = b;
b = r;
r = a+b;
}
main (){
algo a;

for(int i = 0;i<10;i++)
{
++a;
a.affiche();

}
system("pause");
}

22
Règle:

Le membre gauche d'un opérateur unaire doit toujours être un objet de la classe
Si la fonction opérateur est une fonction indépendante
• Elle doit tout de même accéder aux données privées et elle va être déclarée fonction amie
• Elle aura obligatoirement un objet de la classe par adresse qui correspond à l'objet à modifier.
Exemple pour la classe algo
friend void operator++(algo &)

// Déclaration à mettre dans la définition de la classe qui autorise l'accès


// A sa partie privée via un objet de classe.

A l'extérieur on aura : Dans le programme utilisateur :


void operator++( algo &x)
{ algo a;
x.a = x.b; ...
x.b = x.r; ++a; // équivalent à operator++(&a)
x.r = x.a+x.b;
}

Les mêmes règles sont valable pour l’opérateur - -

23
#include <iostream>
using namespace std;

class algo
{
private:
int a,b,r;

public:

algo() { a=0; b=1; r=a+b; } // constructeur par défaut


friend void operator++ (algo &);
Programme complet : void affiche() { cout << r << endl; }
};

void operator++(algo & X)


{
X.a = X.b;
X.b = X.r;
X.r = X.a+X.b;
}
main (){
algo a;

for(int i = 0;i<10;i++)
{
++a;
a.affiche();

} 24
}
▪ Règle:
On définit à la fois un opérateur ++ utilisable en notation préfixée et un autre utilisable en notation
postfixée.

Cas d'une fonction membre

▪ Si T désigne un type classe et que ++ est définit sous la forme d'une fonction membre.

▪ T opertor++() est utilisée en notation préfixée.

▪ T operator++(int) est utilisé en notation postfixée

▪ Cet argument int est totalement fictif, en ce sens qu'il permet au compilateur de choisir l'opérateur à
utiliser, mais qu'aucune valeur n'est transmise lors de l'appel.

▪ Cas d'une fonction amie


▪ De même, si ++ est définit sous forme de fonction amie:
▪ l'opérateur usuel d'en tête T operator (T&) est utilisé en cas de notation préfixée
▪ l'opérateur usuel d'en tête T operator(T&,int) est utilisé en cas de notation posfixée

25
Résumé : comment surcharger ++ et - -

▪ Etant donné que ces opérateurs peuvent avoir deux définitions,


▪ C++ leur donne deux signatures différentes. Les deux s'appellent operator++()
▪ La version pré-incrémentation ne prend pas de paramètre,
▪ L'autre prend un entier bidon.
▪ Les cas de ++ et -- se comportent de façon similaire. Tout ce qui s'applique à l'un
s'applique donc à l'autre.

26
Exemple:class Number {
public: Number& operator++ (); // prefix ++
Number operator++ (int); // postfix ++
};
Remarque:
•la différence des types de retour.

La version préfixée renvoie par référence, la post fixée par valeur.

27
Exemple de surdéfinition de l’opérateur ‘[]’

▪ Surdéfinir l’operateur ‘[ ]’ de manière que ‘o[i]’ désigne l’élément d’emplacement ‘i’ de


l’objet ‘o’ de la classe ‘vecteur’.

▪ La seule précaution a prendre consiste a faire en sorte que cette notation puisse être
utilisée non seulement dans une expression, mais également a gauche d’une affectation.

▪ Il est donc nécessaire que la valeur de retour fournie par l’operateur ‘[]’ soit transmise par
référence : int & operator [ ] (int) ;

▪ Le premier opérande de ‘o[i]’ étant ‘o’.

28
Exemple de surdéfinition de l’opérateur ‘[]’
Exercices

Soit la classe vecteur3d ainsi définie :


class vecteur3d
{
float v[3] ;
public :
vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0)
3 { // à compléter
}
};
Compléter la définition du constructeur (en ligne), puis définir l’opérateur [] pour qu’il permette
d’accéder à l’une des trois composantes d’un vecteur, et cela aussi bien au sein d’une
expression ( ... = v1[i]) qu’à gauche d’un opérateur d’affectation (v1[i] = ...) ; de
plus, on cherchera à se protéger contre d’éventuels risques de débordement d’indice.

29
#include <iostream>
using namespace std;
class vecteur3d
{
float v [3] ;
public :
vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0){
v[0] = c1 ; v[1] = c2 ; v[2] = c3 ;
}
float& operator[] ( int) ;
};
float & vecteur3d::operator [] (int i)
{ if ( (i<0) || (i>2) ) i = 0 ; // pour éviter un "débordement"

return v[i] ;
}
main()
{
vecteur3d v1 (3,4,5) ;
int i ;
cout << "v1 = " ;
for (i=0 ; i<3 ; i++) cout << v1[i] << " " ;
for (i=0 ; i<3 ; i++) v1[i] = i ;
cout << "\nv1 = " ;
for (i=0 ; i<3 ; i++) cout << v1[i] << " " ;
}

30
Exemple de surdéfinition de l’opérateur ‘[]’
#include <iostream>
using namespace std;
class vecteur3d
{
float v[3] ;
public :
vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0){
v[0] = c1 ; v[1] = c2 ; v[2] = c3 ;}
float & operator [] (int i){
return v[i] ; }
};
main(){
vecteur3d o1(3,4,5) ;
int i ;
for (int i=0; i<3 ;i++){
o1[i]=i+1;
}
for (i=0 ; i<3 ; i++)
cout<<o1[i]<< "\t" ;
cout<<endl ;

}
31
Surcharge des opérateurs d'entrées-sorties

Injection et extraction de données dans les flux

32
Exemple de surdéfinition de l’opérateur >> et <<
▪ Prototype pour surcharger l’opérateur >>

istream& operator >> ( istream &flux, Nom de classe & objet )

▪ Prototype pour surcharger l’opérateur <<

ostream &operator << (ostream &, const X &)

33
Exemple avec la classe date
▪ Un flux de sortie est la destination logique pour afficher une telle structure.
▪ Ce code affiche une date à l'aide de l'objet cout :
▪ Date dt(1, 2, 92);
▪ cout <<dt;

▪ Pour que cout accepte un objet Date après l'opérateur d'insertion, surchargez
l'opérateur d'insertion pour reconnaître un objet ostream à gauche et une Date à
droite.
▪ La fonction d'opérateur << surchargée doit alors être déclarée comme amie de la
classe Date afin qu'elle puisse accéder aux données privées dans un objet Date.

34
#include <iostream>
using namespace std;
class Date{
int mo, da, yr;
public:
Date(int m, int d, int y) { mo = m; da = d; yr = y;}
Date() {
mo=1;da=1;yr=1970; }
friend ostream& operator<<(ostream& os, const Date& dt);
friend istream& operator>> (istream& is, Date& dt);
};
ostream& operator<<(ostream& os, const Date& dt){
os << dt.mo << '/' << dt.da << '/' << dt.yr;
return os;}
istream& operator>> (istream& is, Date& dd){
is>> dd.mo>> dd.da>> dd.yr;
return is;}
int main(){
Date dt(5, 6, 92);
Date dd;
cout<<"Saisir une date\n";
cin>> dd;
cout << dt<<endl;
35
cout<<dd;}
Exemple de surdéfinition de l’opérateur >> et <<
class complexe {
double re,im ;
public:
▪ Exemple friend ostream & operator << (ostream & os, const complexe &c) ;
friend istream & operator >> (istream & is, complexe & c) ;
};
ostream & operator << (ostream & os, const complexe &c){
cout << "( " << c.re << " , " << c.im << " ) " ;
return os ;
}
istream & operator >> (istream & is , complexe & c){
cin >> c.re ;
cin >> c.im ;
return is ;
}
int main(void) {
complexe c1 ;
cin >> c1;
int i ;
cout << c1 ;
}
36
#include<iostream>
using namespace std;

class point{

int abs, ord ;

public :
point(int,int); //constructeur
friend ostream& operator<<(ostream&, const point);
friend istream& operator>>(istream&, point&);
};

point::point(int x=0, int y=0)


{
abs=x; ord=y;
cout << "Constr. point " << x << " " << y << endl;
}

ostream& operator<<(ostream &o, const point p) {


return o << '(' << p.abs << ',' << p.ord << ')';
}

istream& operator>>(istream& i, point& p) {

cin >> p.abs >> p.ord;

return i;

} 37
int main()
{
point p(2,3);
cout << "donne un point : ";

cin >> p;
cout << "le point donné est : " << p << "\n";

system("PAUSE") ;
return 0;
}

38

Vous aimerez peut-être aussi