Vous êtes sur la page 1sur 22

A.U.

2018/2019

Chapitre 3

1 ATEL
En programmation classique, pour demander une
opération sur un ou plusieurs objets, il faudra appeler
une fonction membre et lui passer en paramètres les
noms des objets. L’un d’eux sera l’objet courant et les
autres doivent être passées en paramètres :

Exemple
objet1.add ( objet2, objet3)
pour exprimer l’addition de l’objet2 à l’objet3 et mettre le
résultat dans objet1.
2
Ce type d’appel est contraignant pour l’utilisateur. On aimerait lui
donner la possibilité de continuer à utiliser l’opérateur « + » pour
demander l’addition entre deux objets.

objet1= objet2 + objet3

Exemple
if ( etudiant1 < etudiant2 )….
Il faut définir ce qu’on entend par la relation < entre deux étudiants.

Nous devrons donc surcharger l’opérateur « = » et l’opérateur « + »


qui étaient destinés à agir sur des valeurs numériques pour
additionner en plus des objets.
3
 Pour surcharger un opérateur, il faut veiller à respecter
l’esprit de l’opérateur, c’est à dire faire avec les types
utilisateurs des opérations identiques à celles que fait
l’opérateur avec les types prédéfinis.
 La plupart des opérateurs sont « surchargeables » à
l’exception des opérateurs suivants: :: . .* sizeof
 Il n’est pas possible de changer les propriétés de l’opérateur :
sa priorité, son associativité et sa pluralité (unaire, binaire,
ternaire).
 Il n’est pas possible de créer de nouveaux opérateurs.

 Lesopérateurs = () [ ] -> new delete ne peuvent être


surchargés que comme des fonctions membres.
4
Pour surcharger l’opérateur + (par exemple), il suffit de créer une fonction
(membre ou globale) nommée :
operator+

A chaque fois que l’opérateur + est rencontré, le compilateur génèrera un appel


à la fonction operator+.

Ainsi, l’instruction :

b+c est équivalente à b.operator+(c)


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

Remarque :
 la fonction operator+ a un seul paramètre de même type que l’objet
 la fonction operator+ renvoie une valeur de même type que l’objet
 Sa signature devrait être : classe operator+ ( const classe & )
5
 Surcharge par une fonction membre
Par exemple, la surcharge des opérateurs + et = par des fonctions membres
de la classe Matrice s’écrit :

const int dim1= 2, dim2 = 3; // dimensions de la Matrice


class Matrice // matrice dim1 x dim2 d’entiers
{ int Tab[dim1][dim2];
// ...
public:
// ...
Matrice &operator=(const Matrice &n2);
Matrice operator+(const Matrice &n2);
friend Matrice operator+(const Matrice & N1, const Matrice & N2);
// ...
};
// … 6
int main()
{
Matrice b, c;
b + c ; // appel à : b.operator+( c );
a = b + c; // appel à : a.operator=( b.operator+( c ) );
}

Quand on a le choix, l’utilisation d’une fonction membre


pour surcharger un opérateur est préférable. Une
fonction membre renforce l’encapsulation. Les
opérateurs surchargés par des fonctions membres se
transmettent aussi par héritage (sauf l’affectation).
7
 Surcharge par une fonction globale
Cette façon de procéder est plus adaptée à la surcharge des
opérateurs binaires. En effet, elle permet d’appliquer des conversions
implicites au premier membre de l’expression.
Exemple
Class Nombre
{
friend Nombre operator+(const Nombre &, const Nombre &);
public:
Nombre(int n = 0) { nbre = n; }
//....
private:
int nbre;
};
8
Nombre operator+(const Nombre &nbr1, const Nombre &nbr2)
{
Nombre n;
n.nbre = nbr1.nbre + nbr2.nbre;
return n;
}
int main()
{
Nombre n1(10);
n1 + 20; // OK appel à : operator+( n1, Nombre(20) );
30 + n1; // OK appel à : operator+( Nombre(30) , n1 );
}

9
La surcharge de l’opérateur + se fait de la manière
suivante. Remarquer que la fonction renvoie un
objet par valeur, et qu’elle déclare un objet interne
de travail. Le paramètre est passé par référence
pour éviter de faire une copie de l’objet.
Matrice Matrice::operator+(const Matrice &c)
{
Matrice m;
for(int i = 0; i < dim1; i++)
for(int j = 0; j < dim2; j++)
m.matrice[i][j] = matrice[i][j] + c.matrice[i][j];
return m;
}

10
 Le compilateur C++ construit par défaut un opérateur
d’affectation ‘‘bête’’. Pour disposer d’un opérateur
d’affectation particulier, il vaut mieux en définir un.
 L’opérateur d’affectation est obligatoirement une
fonction membre et il doit fonctionner correctement
dans les deux cas suivants :

Matrice x1, x2, x3; // 3 instances de la classe Matrice


x1 = x2;
x1 = x2 = x3; // Affectation multiple

 classe &operator= (const classe &)


11
Exemple
Opérateur d’affectation de la classe Matrice :

Matrice &Matrice::operator=(const Matrice &m)


{
if ( &m != this ) // traitement du cas : x1 = x2
{
for(int i = 0; i < dim1; i++) // copie de la matrice
for(int j = 0; j < dim2; j++)
matrice[i][j] = m.matrice[i][j];
}
return *this; // traitement du cas : x1 = x2 = x3
}
12
Exemple
Nombre Complexe
On voudrait implémenter une classe « complexe » pour
répondre aux instructions du programme suivant :
int main()
{ complexe z1(5.0,25.5),z2, z3;
z2= z1;
z3=z2=z1 ;
z2.affiche ();
z3= z1 + z2;
z3.affiche();
}
13
class complexe
{
public:
double r,m;
complexe (double x=0. , double y=0.) // Constructeur
{ r=x; m=y;}
complexe &operator= (const complexe &z);
complexe operator+ (const complexe &z);
void affiche();
complexe (complexe &a) // Constructeur de copie
{ r = a.r; m = a.m ;}
~complexe (){ } // Destructeur
};
14
complexe &complexe::operator= (const complexe &z)
{ if (&z != this )
{ r=z.r; // traitement du cas z1=z2
m=z.m;
}
return *this;
}
complexe complexe::operator+( const complexe &z)
{ complexe t;
t.r= r + z.r ;
t.m= m + z.m ;
return t;
}
void complexe::affiche()
{ cout << "\nValeur du complexe = "<<r<<"+ i "<<m; }
15
Considérons l’exemple suivant :
Class nombre
{ int a ;
// ……
};
// ……….
int main ()
{ int k ;
nombre x ;
k=x;
x = k ; // est-ce possible ? x et k sont de types différents.
}
16
Réponse : C’est possible mais à condition de définir des
opérateurs de conversion.
 Donc, dans la définition complète d’une classe, il ne faut pas
oublier de définir ces opérateurs de conversions de types. Il
existe deux types de conversions de types :
 la conversion de type prédéfini (ou défini préalablement) vers le
type classe en question. Ceci sera effectué grâce au constructeur de
conversion.
 la conversion du type classe vers un type prédéfini (ou défini
préalablement). Cette conversion sera effectuée par des fonctions
de conversion.
Constructeur de conversion : Type Prédéfini  classe
 Un constructeur avec un seul argument de type T permet de
réaliser une conversion d’une variable de type T vers un objet
de la classe du constructeur.
17
Exemple Dans cet exemple, le
constructeur avec un
class Nombre argument permet donc
{ public: d’effectuer des conversions
Nombre(int n) { nbre = n; } d’entier en Nombre.
private:
int nbre;
};
void f1(Nombre n)
{ /* ... */ }
int main()
{ Nombre n = 2; // idem que : Nombre n(2);
n=125 ;
f1(3); // Appel du constructeur Nombre(int) pour réaliser
// la conversion de l’entier 3 en un Nombre.
// Pas d’appel du constructeur de copie
}
18
Fonction de conversion : Classe  Type prédéfini
 Une fonction de conversion est une méthode qui effectue une
conversion vers un type T.
 Elle est nommé operator T(). Cette méthode n’a pas de type de
retour (comme un constructeur), mais doit cependant bien retourner
une valeur de type T.
class Article
{ public :
Article(double valeur=0.0) {prix = valeur ; }
operator double() const { return prix; }
private :
double prix;
};
int main()
{ double total;
Article coca(17.50);
total = 7 * coca; // utilisation implicite de la conversion Article -> double
}
19
 Pour la surcharge des opérateurs ++ et --, il faut
distinguer les deux types de notation :
 notation préfixée : ++x
 notation postfixée : x++

 La différence réside dans le fait qu’en notation


postfixée, on retourne l’ancienne valeur alors qu’en
notation préfixée, on retourne la nouvelle valeur.
 Pour cela, il faut surcharger la fonction
operator++ en ajoutant un paramètre de type
classe (bidon dans l’exemple) pour faire la
différence :
20
Exemple
const bidon operator++(int) // Notation postfixée x++
{
#include <iostream> bidon obj;
class bidon
{ obj.data=data;
public: data = data+1;
int data; return obj;

bidon (int k=0) }


{ data = k ;} };
const bidon &operator++( ) //Notation préfixée ++x
{
data = data+1;
return *this;
}

21
int main()
{
bidon x (150), y ;
y=x++;
cout << “\ny = “<<y.data << "x = "<< x.data;
y=++x;
cout << “\ny = “<<y.data << "x = "<< x.data;
}
Résultat :
y = 150 x = 151
y = 152 x = 152
22

Vous aimerez peut-être aussi