Académique Documents
Professionnel Documents
Culture Documents
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 ».
/
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
▪ Exemple
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
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é
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
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[ ]
:: . .* 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).
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)
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
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:
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 &)
23
#include <iostream>
using namespace std;
class algo
{
private:
int a,b,r;
public:
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.
▪ Si T désigne un type classe et que ++ est définit sous la forme d'une fonction membre.
▪ 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.
25
Résumé : comment surcharger ++ et - -
26
Exemple:class Number {
public: Number& operator++ (); // prefix ++
Number operator++ (int); // postfix ++
};
Remarque:
•la différence des types de retour.
27
Exemple de surdéfinition de l’opérateur ‘[]’
▪ 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) ;
28
Exemple de surdéfinition de l’opérateur ‘[]’
Exercices
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
32
Exemple de surdéfinition de l’opérateur >> et <<
▪ Prototype pour surcharger l’opérateur >>
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{
public :
point(int,int); //constructeur
friend ostream& operator<<(ostream&, const point);
friend istream& operator>>(istream&, point&);
};
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