Vous êtes sur la page 1sur 86

Année académique : 2021/2022

EMSI - Tanger

Programmation orientée objet

PROGRAMMATION ORIENTÉE OBJET


Pr. Zaynab El Khattabi
Le concept d’Objet

▪ Apparue au début des années 70, la programmation orientée


objet répond aux nécessités de l’informatique professionnelle.

▪ Elle offre aux concepteurs de logiciels une grande souplesse


de travail, permet une maintenance et une évolution plus aisée
des produits.

▪ Mais sa pratique passe par une approche radicalement


différente des méthodes de programmation traditionnelles.
Objet usuel
Comment décrire un objet usuel ?

Exemple: La notice d’utilisation d’un appareil ménager


La notice a généralement trois parties :
A. Une description physique de l’appareil et de ses principaux
éléments (boutons, voyants lumineux, cadrans etc.), schémas à
l’appui,
B. Une description des fonctions de chaque élément,
C. Un mode d’emploi décrivant la succession des manœuvres à
faire pour utiliser l’appareil.
Objet usuel
Comment décrire un objet usuel ?

Exemple: La notice d’utilisation d’un appareil ménager

▪ Seules les parties A et B sont intrinsèques à l’appareil


▪ La partie C concerne l’utilisateur et rien n’empêche celui-ci de se
servir de l’appareil d’une autre manière, ou à d’autres fins que celles
prévues par le constructeur.

Pour décrire un objet usuel, il faut décrire ses composants, à savoir :

1. les différents éléments qui le constituent,


2. les différentes fonctions associées à ces éléments.
Objet usuel
Comment décrire un objet usuel ?
▪ Les éléments qui constituent l’objet définissent à chaque instant
l’état de l’objet — on peut dire : son aspect spatial.
▪ Les fonctions, quant à elles, définissent le comportement de l’objet
au cours du temps.
▪ Les éléments qui constituent l’objet peuvent se modifier au cours du
temps.
▪ Un objet peut ainsi avoir plusieurs états.
▪ Le nombre d’états possibles d’un objet donne une idée de sa
complexité.

▪ Pour identifier les composants d’un objet usuel, une bonne méthode
consiste à faire de cet objet une description littérale, puis de
souligner les principaux noms communs et verbes. Les noms
communs donnent les éléments constituants, les verbes donnent
les fonctions.
Objet usuel
Comment décrire un objet usuel ?

Exemple 1 : Le cas d’un objet très simple, (un marteau )

“Ce marteau comporte un manche en bois, une extrémité plate en


métal et une extrémité incurvée également en métal. Le manche
permet de saisir le marteau, l’extrémité plate permet de frapper
quelque chose et l’extrémité incurvée permet d’arracher quelque
chose.”
D’où la fiche descriptive :
Objet usuel
Comment décrire un objet usuel ?

Exemple 2: Un chronomètre digital

“Le chronomètre comporte un temps qui s’affiche et deux boutons A et B. Quand on


presse sur A, on déclenche le chronomètre, ou bien on l’arrête. Quand on presse sur B,
on remet à zéro le chronomètre.”
D’où la fiche descriptive:
Objet informatique — Classe

Programmer un ordinateur, c’est lui fournir une série d’instructions


qu’il doit exécuter.

Un langage de programmation évolué doit simplifier le travail du


programmeur en lui offrant la possibilité :

▪ d’écrire son programme sous forme de petits modules autonomes,


▪ de corriger et faire évoluer son programme avec un minimum de
retouches,
▪ d’utiliser des modules tout faits et fiables.
Objet informatique — Classe

▪ Les langages à objets comme le C++ sont supérieurs aux langages classiques
comme le C, car ils font reposer le gros du travail sur des “briques logicielles
intelligentes” : les objets.

▪ Un programme n’est alors qu’une collection d’objets mis ensemble par le


programmeur et qui coopèrent.

▪ Un objet est une structure informatique regroupant :


• des variables, caractérisant l’état de l’objet,
• des fonctions, caractérisant le comportement de l’objet.
Objet informatique — Classe

▪ Les variables (resp. fonctions) s’appellent données-membres


(resp. fonctions-membres ou encore méthodes) de l’objet.

▪ L’originalité dans la notion d’objet, c’est que les variables et les


fonctions sont regroupées dans une même structure.

▪ Un ensemble d’objets de même type s’appelle une classe.

▪ Tout objet appartient à une classe, on dit aussi qu’il est une
instance de cette classe,
Objet informatique — Classe

Pour utiliser les objets, il faut d’abord décrire les classes auxquelles ces objets
appartiennent.

La description d’une classe comporte deux parties :

▪ Une partie déclaration, fiche descriptive des données et fonctions-membres des


objets de cette classe, qui servira d’interface avec le monde extérieur,
▪ Une partie implémentation, contenant la programmation des fonctions-membres.
Encapsulation

Dans la déclaration d’une classe, il est possible de protéger certaines


données-membres ou fonctions-membres en les rendant invisibles de
l’extérieur : c’est ce qu’on appelle l’encapsulation.

Supposons qu’on veuille programmer une classe Cercle avec comme


données membres:
– Un point représentant le centre,
– Un nombre représentant le rayon,
– Un nombre représentant la surface du cercle.

Permettre l’accès direct à la variable surface, c’est s’exposer à ce


qu’elle soit modifiée depuis l’extérieur, et cela serait catastrophique
puisque l’objet risquerait alors de perdre sa cohérence (la surface
dépend en fait du rayon). Il est donc indispensable d’interdire cet
accès, ou au moins permettre à l’objet de le contrôler.
Encapsulation

Données et fonctions-membres d’un objet O seront déclarées publiques


si on autorise leur utilisation en dehors de l’objet O, privées si seul
l’objet O peut y faire référence.

▪ Une approche simple et sûre consiste à déclarer systématiquement


les données-membres privées et les fonctions-membres publiques.
▪ On peut alors autoriser l’accès aux données-membres (pour
consultation ou modification) par des fonctions prévues à cet effet,
appelées fonctions d’accès.
▪ Ainsi, la déclaration de la classe Cercle pourrait ressembler à :
Stratégie D.D.U

En C++, la programmation d’une classe se fait en trois phases :


déclaration, définition, utilisation (en abrégé : D.D.U).
1. Déclaration : c’est la partie interface de la classe. Elle se fait
dans un fichier dont le nom se termine par .h. Ce fichier se
présente de la façon suivante :

class Maclasse
{
public:
déclarations des données et fonctions-membres publiques
private:
déclarations des données et fonctions-membres privées
};
Stratégie D.D.U

2. Définition :
▪ C’est la partie implémentation de la classe. Elle se fait dans un fichier dont le nom se
termine par .cpp.
▪ Ce fichier contient les définitions des fonctions-membres de la classe, c’est-à-dire
le code complet de chaque fonction.

3. Utilisation :
▪ elle se fait dans un fichier dont le nom se termine par .cpp
Stratégie D.D.U
Structure d’un programme en C++

Nos programmes sont généralement composés d’un nombre impair de fichiers :


– pour chaque classe :
▪ Un fichier .h contenant sa déclaration,
▪ Un fichier .cpp contenant sa définition,
▪ Un fichier .cpp contenant le traitement principal.

Ce dernier fichier contient la fonction main, et c’est par cette fonction que commence
l’exécution du programme.
Stratégie D.D.U
Structure d’un programme en C++
Stratégie D.D.U
Structure d’un programme en C++

Remarque:
Rappelons que la directive d’inclusion #include permet d’inclure un fichier de
déclarations dans un autre fichier :

On écrira:
▪ #include <biblio.h> s’il s’agit d’un fichier standard livré avec le compilateur C++,
▪ #include "biblio.h" s’il s’agit d’un fichier écrit par nous-mêmes.
Stratégie D.D.U
Mise en œuvre

Exemple: un programme complet afin d’illustrer les principes de la stratégie D.D.U. Ce


programme simule le fonctionnement d’un parcmètre.

Le programme se compose de trois fichiers :

▪ parcmetre.h qui contient la déclaration de la classe Parcmetre,


▪ parcmetre.cpp qui contient la définition de la classe Parcmetre,
▪ simul.cpp qui contient l’utilisation de la classe Parcmetre.
Stratégie D.D.U
Mise en œuvre (1)
Stratégie D.D.U
Mise en œuvre (2)
Stratégie D.D.U
Mise en œuvre (3)
Stratégie D.D.U
Mise en œuvre (4)
Stratégie D.D.U - Mise en œuvre (4)
Stratégie D.D.U

▪ Dans une expression, on accède aux données et fonctions-


membres d’un objet grâce à la notation pointée (: )
▪ Si mon_objet est une instance de Ma_classe, on écrit
mon_objet.donnee (à condition que donnee figure dans la
déclaration de Ma_classe, et que l’accès en soit possible)

▪ D’autre part, dans la définition d’une fonction-membre, on doit


ajouter <nom de la classe>:: devant le nom de la fonction.
▪ Par exemple, la définition d’une fonction-membre fonction() de
la classe Ma_classe aura la forme suivante :

<type> Ma_classe::fonction(<déclaration de paramètres formels>)


<instruction-bloc>
Stratégie D.D.U

▪ L’appel se fait avec la notation pointée, par exemple :


mon_obj.fonction() ;
▪ En programmation-objet, on dit parfois qu’on envoie le message
fonction() à l’objet destinataire mon_obj.

Exceptions : certaines fonctions-membres sont déclarées sans type


de résultat et ont le même nom que celui de la classe : ce sont les
constructeurs.
▪ Ces constructeurs permettent notamment d’initialiser les
objets dès leur déclaration.
Stratégie D.D.U
Réalisation pratique du programme

1. création des fichiers sources parcmetr.h, parcmetr.cpp et


simul.cpp.
2. compilation des fichiers .cpp, à savoir parcmetr.cpp et simul.cpp,
ce qui crée deux fichiers objets parcmetr.obj et simul.obj (ces
fichiers sont la traduction en langage machine des fichiers .cpp
correspondants),
3. édition des liens entre les fichiers objets, pour produire finalement
un fichier exécutable dont le nom se termine par .exe.
▪ Remarque:
▪ On peut ajouter directement dans un projet un fichier .obj:
▪ Il n’est pas nécessaire de disposer du fichier source .cpp
correspondant. On pourra donc travailler avec des classes déjà
compilées.
Stratégie D.D.U
Réalisation pratique du programme

Exemple () :

Réaliser une classe Point permettant de manipuler un point d’un plan. La classe
comporte:
▪ Deux constructeurs :
▪ Un reçoit les arguments ( coordonnées du Point).
▪ Un sans paramètres (constructeurs par défaut).
▪ Une fonction initialiser ( int, int) qui initialise les coordonnées du point.
▪ Une fonction pour afficher les coordonnées du point.
▪ Une fonction deplacer( int, int) qui prend deux paramètres, permettant de
faire une transition par multiplier les coordonnées du point par les
paramètres de la fonction.
Ecrire un petit programme d’essai (main) déclarant deux point et testant les
fonctions.
Constructeurs, destructeurs, initialisation et
recopie

Durée de vie d'un objet:

▪ Un objet a une vie

Création Vie Mort

▪ Création
▪ déclaration (objets statiques ou automatiques)
▪ new (objets dynamiques)
▪ Mort
▪ fin de la portée (objets statiques ou automatiques)
▪ delete (objets dynamiques)
Initialisation des attributs

Première solution : affecter individuellement une valeur à chaque


attribut

Ceci est une mauvaise solution dans le cas général :


▪ si le nombre d’attributs est élevé, ou si le nombre d’objets créés est
grand (rectangles r[0], r[1], ..., r[99]) elle est fastidieuse et source
d’erreurs (oublis)
▪ elle implique que tous les attributs fassent partie de l’interface
(public) ou soient assortis d’un manipulateur (set).
Initialisation des attributs

Deuxième solution : définir une méthode dédiée à l’initialisation


des attributs

▪ En fait, C++ fait déjà le travail pour vous en fournissant des


méthodes particulières appelées constructeurs
▪ Un constructeur réalise toutes les opérations requises en « début
de vie » de l’objet.
Construction d'un objet

Un constructeur est une méthode :


• Invoquée automatiquement lors de la déclaration d’un objet
(instanciation d’une classe)
• Assurant l’initialisation des attributs.

Syntaxe de base :

Exemple
Construction d'un objet

Les constructeurs sont donc des méthodes (presque) comme les


autres:
▪ Que l’on peut surcharger
▪ Une classe peut donc avoir plusieurs constructeurs, pour que
leur liste d’arguments soient différentes ;
▪ Aux arguments desquels on peut donner des valeurs par défaut

Ce qu’il faut noter de particulier sur la syntaxe des constructeurs :


▪ Pas d’indication de type de retour (pas même void)
▪ Doit avoir le même nom que la classe pour laquelle ils sont
définis
Initialisation par constructeur

La déclaration avec initialisation d’un objet se fait comme pour une


variable ordinaire.

Syntaxe :
NomClasse instance(valarg1, ..., valargN);
où valarg1, ..., valargN sont les valeurs des arguments du
constructeur.

Exemple :
Rectangle r1(18.0, 5.3); // invocation du constructeur
Construction des attributs

Que se passe-t-il si les attributs sont eux-mêmes des objets ?


Exemple :

Le constructeur d’un rectangleColore devrait faire appel au


constructeur de Rectangle, ce qui n’est pas possible directement. On
peut alors imaginer passer par une instance anonyme intermédiaire :

Mais c’est une très mauvaise solution !


☞ il faut initialiser directement les attributs en faisant appel à leurs
constructeurs (propres) !
Appel aux constructeurs des attributs

▪ Un constructeur devrait normalement contenir une section d’appel


aux constructeurs des attributs.
▪ Ceci est également valable pour l’initialisation des attributs de type
de base.
▪ Il s’agit de la « section deux-points » des constructeurs :
Syntaxe générale :

Exemple:
Appel aux constructeurs des attributs

Cette section, qui est introduite par :, est optionnelle mais


recommandée.
Par ailleurs :
▪ les attributs non-initialisés dans cette section:
▪ prennent une valeur par défaut si ce sont des objets ;
▪ restent indéfinis s’ils sont de type de base ;
▪ les attributs initialisés dans cette section peuvent (bien sûr) être
changés dans le corps du constructeur.
▪ Exemple:
Constructeur par défaut

Un constructeur par défaut est un constructeur qui n’a pas


d’argument ou dont tous les arguments ont des valeurs par défaut.
Exemples :

Autre façon de faire : regrouper les 2 premiers constructeurs en


utilisant les valeurs par défaut des arguments :
Constructeur par défaut

Si aucun constructeur n’est spécifié, le compilateur génère


automatiquement une version minimale du constructeur par
défaut
(c’est donc un constructeur par défaut par défaut) qui :
▪ appelle le constructeur par défaut des attributs objets ;
▪ laisse non initialisés les attributs de type de base.

Dès qu’au moins un constructeur a été spécifié, ce constructeur par


défaut par défaut n’est plus fourni.

Si donc on spécifie un constructeur sans spécifier de constructeur par


défaut, on ne peut plus construire d’objet de cette classe sans les
initialiser (ce qui est voulu !) puisqu’il n’y a plus de constructeur par
défaut.
Constructeur par défaut : exemples
Constructeur par défaut : exemples
Constructeur de recopie

▪ C++ fournit également un moyen de créer la copie d’une instance :


le constructeur de recopie
▪ Ce constructeur permet d’initialiser une instance en utilisant les
attributs d’une autre instance du même type.

Syntaxe :

Exemple:
Constructeur de recopie

▪ De la même manière que l'affectation (par défaut), le


constructeur de recopie par défaut effectue la copie membre à
membre de la source vers la destination.

▪ Il est appelé dans trois situations:

- Initialisation d'un objet


- Paramètre passé par valeur
- Retour de fonction par valeur
Constructeur de recopie

1. Initialisation d'un objet


- Création d'un nouvel objet initialisé comme étant une copie d'un
objet existant:

compte C(280.98);
// constructeur de recopie: création de l'objet B
// et son initialisation avec les données de C.
compte B(C);

- Ou bien:
// constructeur de recopie: création de l'objet B
// et son initialisation avec les données de C.
compte B = C;
Constructeur de recopie

1. Initialisation d'un objet

Attention!!
▪ il faudra différencier entre recopie et affectation.

compte B; // création de l'objet.


B = C; // pas de recopie mais uniquement l'affectation
// car l’objet est déjà créé.
Constructeur de recopie

2. Paramètre passé par valeur:

Transmission d'une valeur à une fonction

compte C(290.77);
double fonction(compte);
double z = fonction(C); // passage par valeur de C.
Constructeur de recopie

3. Retour de fonction par valeur:

compte C;
compte fonction(int);

compte fonction(int i) {
compte X;
return X; // retour par valeur de X
}
Constructeur de recopie
Utilité d'un constructeur de recopie

class test {
int *ptr; // on suppose que nous avons un ptr sur un seul élément.
void alloc_test(){
if (ptr==NULL) {
cerr << "allocation de la mémoire a échoué!\n";
exit(1);
}}
public:
test(int d=1000) {
ptr = new int(d); // allocation et initialisation.
alloc_test();
}
~test(){
delete ptr; // libération.
}
void affiche() {
cout << "valeur: " << *ptr << endl;
} };
Constructeur de recopie
Utilité d'un constructeur de recopie

int main() {
// appel du constructeur
// déclaration permise car par défaut: d=1000.
test x;
// appel du constructeur de recopie dans ce cas, par
// défaut fourni par le langage, création de l'objet y
// puis recopie membre à membre de x vers y.
test y = x;
y.affiche();
return 0;
}
Constructeur de recopie
Utilité d'un constructeur de recopie

Le constructeur de recopie par défaut va effectuer une copie membre à


membre.
▪ Copier membre à membre un pointeur signifie que ptr de l'objet y
pointe au même endroit que ptr de l'objet x (une recopie d'adresse).
▪ À la fin du programme, le destructeur va être appelé pour détruire les
objets x et y.
▪ Détruire x revient à libérer la mémoire allouée pour le pointeur ptr de
x.
▪ Détruire y revient à libérer la mémoire allouée pour le pointeur ptr de
y.
▪ Or, comme il a été mentionné précédemment, les deux pointeurs
pointent le même endroit. De ce fait, le même endroit va être détruit
deux fois!
▪ C'est une erreur fatale, classique quand il y a violation de la
mémoire.
▪ Une tentative d'accéder à quelque chose qui n'existe pas.
▪ Pour corriger cette erreur, il faut définir le constructeur de recopie afin
de masquer le constructeur de recopie par défaut fourni par le
langage et redéfinir le nôtre.
Constructeur de recopie
Utilité d'un constructeur de recopie

class test {
int *ptr; test(const test & T) {

void alloc_test(){ ptr = new int(*T.ptr);

if (ptr==NULL) { alloc_test();

cerr << "allocation de la mémoire a échoué!\n"; }

exit(1); ~test(){

}} delete ptr; // libération.

public: }

test(int d=1000) { void affiche() {

ptr = new int(d); // allocation et initialisation. cout << "valeur: " << *ptr << endl;

alloc_test(); }};

}
Constructeur de recopie
Utilité d'un constructeur de recopie

int main() {
test x;
test y = x; // appel du constructeur de recopie.
y.affiche();
return 0;
}

▪ La sortie dans ce cas:


valeur: 1000
Destructeur

La syntaxe de déclaration d’un destructeur pour une classe


NomClasse est :

▪ Le destructeur d’une classe est une méthode sans arguments


▪ pas de surcharge possible

▪ Son nom est celui de la classe, précédé du signe ˜ (tilda).


▪ Si le destructeur n’est pas défini explicitement par le
programmeur, le compilateur en génère automatiquement une
version minimale.
Exercice

Exemple (3) :

1. Ecrire un programme permettant de créer des objets ayant


chacun :
▪ un tableau de 5 éléments de type entier en tant que donnée ;
▪ une fonction pour remplir le tableau, une fonction pour trier le
tableau et une fonction pour afficher le contenu du tableau en tant
que méthodes.

2. Reprendre le même programme en remplaçant le tableau de 5


éléments par un tableau dynamique de ‘ne’ éléments et
instancier des objets ayant des tableaux dynamiques de
différentes tailles.
Exemple (3) :
Exemple (3) :
Exemple (3) :
Exercice

Exemple (4) :
1. Réaliser une classe nommée ‘set_int’ permettant de manipuler
des ensembles de nombres entiers. On devra pouvoir réaliser
sur un ensemble les opérations classiques suivantes : lui
ajouter un nouvel élément, connaître son cardinal (nombre
d’éléments), savoir si un entier donné lui appartient.
Ici, on conservera les différents éléments de l’ensemble dans un
tableau alloué dynamiquement par le constructeur. Un argument
(auquel on pourra prévoir une valeur par défaut) lui précisera le
nombre maximal d’éléments de l’ensemble.
2. Écrire, en outre, un programme (main) utilisant la classe set_int
pour déterminer le nombre d’entiers différents contenus dans 20
entiers lus en données.
3. Que faudrait-il faire pour qu’un objet du type set_int puisse être
transmis par valeur, soit comme argument d’appel, soit comme
valeur de retour d’une fonction ?
Exemple (4) :
Exemple (4) :
Membres statiques

Lorsqu’on crée différents objets d’une même classe, chaque objet possède ces propres
données membres.

Exemple:

class point {
int x ;
int y ;
… };
Membres statiques

▪ Une déclaration telle que : point p1, p2; provoquera :

Pour pouvoir partager des données entre objets de la même


classe, on les déclare statiques.
Membres statiques

Exemple
class point {
static int x;
int y;
….};
▪ Une déclaration telle que : point p1, p2; provoquera :
▪ p1.x est identique à p2.x mais p1.y ≠ p2.y.
Membres statiques
▪ Les membres statiques sont utilisées pour calculer le nombre
d’instances (Objets) crées.
▪ Les membres statiques sont toujours initialisés par 0.
class cpt_obj{
static int c;
public :
cpt_obj();
~cpt_obj();
};
int cpt_obj::c=0;
cpt_obj()::cpt_obj() {cout<<″Construction, il y a maintenant : ″<<++c<<″
Objet\n″;}
cpt_obj::~cpt_obj() {cout<<″Destruction, il reste : ″ <<--c<<″ Objet\n″;}
void f(){ cpt_obj a, b; }
main() {
cpt_obj O1; f(); cpt_obj O2; }
Membres statiques

Résultat de l’exécution:
Membres statiques
Exemple:

▪ Créer une classe Livre qui comporte un titre, un auteur, un genre


et un membre statique nombre de livres. Les fonctions membres
de la classe sont: un constructeur paramétré, getTitre, getAuteur,
getGenre, afficher, et modifierGenre.

▪ Ecrire un programme principal permettant de créer des livres,


les afficher, afficher le nombre des livres.

▪ Ecrire un programme principal permettant de créer un tableau


de livres, le remplir, afficher ses éléments, modifier le genre
d’un livre du tableau.
Autoréférence : le mot clé ‘this’

Le mot clé ‘this’ utilisé uniquement au sein d’une fonction membre désigne un pointeur
sur l’objet l’ayant appelé.
Autoréférence : le mot clé ‘this’

Résultat de l’exécution:
Surdéfinition des opérateurs

▪ C++ autorise la surdéfinition des fonctions membres ou


indépendantes en fonction du nombre et du type d’arguments.

▪ C++ autorise également la surdéfinition des opérateurs portant au


moins sur un objet, tel que l’addition (+), la soustraction (-) ou
l’affectation (=) entre objets.

▪ Le mécanisme de la surdéfinition des opérateurs:


▪ Pour surdéfinir un opérateur ‘op’, il faut définir une fonction de
nom : ‘operator op’.

▪ Exemple: point operator + (point,point);


Surdéfinition des opérateurs

▪ 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)
Surdéfinition des opérateurs
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘-’

▪ Nous voulons surcharger l’opérateur unaire ‘-’ pour qu’il calcule


l’opposé d’un nombre complexe.
▪ Dans la classe Complexe, nous déclarons la fonction-membre
publique suivante que nous définissons ensuite en utilisant le
constructeur paramétré de la classe :

Complexe Complexe::operator-() {
return Complexe(-re, -im); }

▪ Par la suite, si z est une variable de type Complexe, on pourra


écrire tout simplement l’expression –z pour désigner l’opposé de z,
(cette expression est équivalente à l’expression z.operator-()).
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘-’

▪ Nous voulons surcharger l’opérateur binaire ‘-‘ pour qu’il calcule la


différence de deux nombres complexes. Dans la même classe
Complexe, nous déclarons la fonction-membre publique suivante :

Complexe operator-(Complexe u);


que nous définissons ensuite en utilisant également le constructeur
paramétré de la classe :

Complexe Complexe::operator- (Complexe u)


{
return Complexe(re - u.re, im - u.im);
}
▪ Par la suite, si z1 et z2 sont deux variables de type Complexe, on
pourra écrire tout simplement l’expression z1 - z2 pour désigner le
nombre complexe obtenu en soustrayant z2 de z1, (cette expression
est équivalente à l’expression z1.operator-(z2) ).
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘+’

▪ Nous voulons surcharger l’opérateur binaire ‘+‘ pour qu’il calcule la


somme de deux nombres complexes. Dans la même classe Complexe,
nous déclarons la fonction-membre publique suivante :

Complexe operator+(Complexe u);


que nous définissons ensuite en utilisant également le constructeur
paramétré de la classe :

Complexe Complexe::operator+ (Complexe u)


{
return Complexe(re + u.re, im + u.im);
}
▪ Par la suite, si z1 et z2 sont deux variables de type Complexe, on pourra
écrire tout simplement l’expression z1 + z2 pour désigner le nombre
complexe obtenu en ajoutant z2 à z1, (cette expression est équivalente à
l’expression z1.operator+(z2) ).
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘+’

▪ Cette fois, nous désirons définir un opérateur qui, appliqué à deux


objets d’une même classe, donne une valeur d’un type différent.

▪ Nous voulons surcharger l’opérateur + pour qu’en écrivant par


exemple poulet + fromage, cela donne le prix total des deux plats
(poulet et fromage supposés de type Plat).
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘+’

Nous commençons par déclarer la fonction-membre :


float operator+(Plat p);

que nous définissons par :


float Plat::operator+(Plat p) {
return prix + p.Getprix(); }

et que nous pouvons ensuite utiliser en écrivant par exemple


poulet + fromage. Nous définissons ainsi une loi d’addition + :
(Plat , Plat) → float.
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘+’

▪ Mais que se passe-t-il si nous voulons calculer salade + poulet +


fromage ? Par associativité, cette expression peut également
s’écrire :
salade + (poulet + fromage)
(salade + poulet) + fromage
donc il nous faut définir deux autres lois :
• une loi + : (Plat, float) → float,
• une loi + : (float, Plat) → float.
▪ La première se programme en déclarant une nouvelle fonction-
membre :
float Plat::operator+(float u)
{ return prix + u; }
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘+’

▪ La deuxième ne peut pas se programmer avec une fonction-membre de la classe Plat


puisqu’elle s’adresse à un float.

▪ Nous sommes contraints de déclarer une fonction libre (c’est-à-dire hors de toute
classe) :
float operator+(float u, Plat p);
que nous définissons par :
float operator+(float u, Plat p)
{ return u + p.Getprix();}
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘[ ]’

Surdéfinir l’opérateur ‘[ ]’ de manière à ce que ‘o[i]’ désigne


l’élément du tableau dynamique d’emplacement ‘i’ de l’objet ‘o’ de
la class ‘tableau’.
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘[ ]’

▪ La seule précaution à prendre consiste à faire en sorte que


cette notation puisse être utilisée non seulement dans une
expression, mais également à gauche d’une affectation.
▪ Il est donc nécessaire que la valeur de retour fournie par
l’opérateur ‘[ ]’ soit transmise par référence :
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘[ ]’
Surdéfinition des opérateurs
surdéfinition de l’opérateur ‘=’

Reprenons le cas de la classe ‘tableau’ :


class tableau {
int ne;
int *p;
public :
............; };
Surdéfinition des opérateurs
Surdéfinition de l’opérateur ‘=’

Une affectation t2=t1 ; pourrait être traitée de la façon suivante :

▪ Libération de l’emplacement pointé par le pointeur p de t2.


▪ Création dynamique d’un nouvel emplacement dans lequel on
recopie les valeurs de l’emplacement pointé par t1.
▪ Mise en place des valeurs des membres données de t2.
▪ Il faut décider de la valeur de retour fournie par l’opérateur
d’affectation en fonction de l’utilisation que l’on souhaite faire (void
ou autre).
▪ Dans l’affectation t2=t1; t2 est le premier opérande (ici this car
l’opérateur ‘=’ est une fonction membre) et t1 devient le second
opérande (ici t).
Surdéfinition des opérateurs
Surdéfinition de l’opérateur ‘=’
Surdéfinition des opérateurs
Surdéfinition de l’opérateur ‘=’
Surdéfinition des opérateurs
Surdéfinition de l’opérateur ‘=’

▪ Créer une classe Livre qui comporte un titre, un auteur, un genre,


un prix et un membre statique nombre de livres. Les fonctions
membres de la classe sont: un constructeur paramétré, getTitre,
getAuteur, getGenre, afficher, et modifierGenre.
▪ Ecrire un programme principal permettant de créer des livres, les
afficher, afficher le nombre des livres.

▪ Ecrire un programme principal permettant de créer un tableau de


livres, le remplir, afficher ses éléments, modifier le genre d’un
livre du tableau.
▪ Surcharger l’opérateur ‘==‘ qui permet de comparer le prix de
deux livres, en écrivant ( L1==L2).

Vous aimerez peut-être aussi