Telechargé par BENZID Jamil

Support de cours de POO en C%2B%2B M ELWAFIQ Version 2017 (1)

publicité
Support de cours
Programmation Orientée Objet
en Langage C++
Mohamed EL WAFIQ
Version 2017
Avant-propos
Ce cours a été développé et amélioré au fil des années afin de donner un support résumé
et simplifié aux étudiants ayant un bon niveau en programmation structurée en langage
de programmation C.
Structure du cours
Ce support de cours est structuré pédagogiquement selon une progression simpliste en
expliquant les concepts, en donnant des exemples d’application et en proposant des
exercices de renforcement dont les solutions sont présentées à titre concis.
Compilation des programmes sources
Tous les programmes sources de ce cours sont compilés sous Dev-C++, Version 4.9.9.2,
en incluant les fichiers entête correspondants.
Programmation Orientée Objet en Langage C++
2
M.E
Table des matières
Chapitre 0 : Spécificités du Langage C++ ...........................................................................5
1. Commentaire en fin de ligne ........................................................................................5
2. Emplacement des déclarations .....................................................................................5
3. Notion de référence ......................................................................................................5
3.1. Transmission des arguments par valeur .................................................................5
3.2. Transmission des arguments par adresse ...............................................................6
3.3. Transmission des arguments par référence ............................................................6
4. Les arguments par défaut .............................................................................................6
5. Surdéfinition de fonction (overloading : surcharge) ......................................................8
6. Les opérateurs ‘new’ et ‘delete’ ...................................................................................9
6.1. L’opérateur ‘new’ .................................................................................................9
6.2. L’opérateur ‘delete’ ............................................................................................ 10
7. Utilisation des fonctions ‘en ligne’ (inline)................................................................. 10
Chapitre 1 : Notions de Classe et Objet ............................................................................. 11
1. Exemple du type classe .............................................................................................. 11
2. Affectation d’objets ................................................................................................... 12
3. Notion de constructeur et de destructeur..................................................................... 12
3.1. Introduction ........................................................................................................ 12
3.2. Construction et destruction des objets ................................................................. 13
3.3. Rôle de constructeur et de destructeur ................................................................. 14
4. Membres statiques ..................................................................................................... 15
Chapitre 2 : Propriétés des fonctions membres................................................................. 20
1. Surdéfinition des fonctions membres.......................................................................... 20
2. Arguments par défaut ................................................................................................. 21
3. Les fonctions membres en ligne ................................................................................. 21
4. Cas des objets transmis en argument d’une fonction membre ..................................... 22
5. Mode de transmission des objets, arguments d’une fonction....................................... 22
5.1. Transmission de l’adresse d’un objet................................................................... 22
5.2. Transmission par référence ................................................................................. 23
6. Autoréférence : le mot clé ‘this’ ................................................................................. 24
Chapitre 3 : Construction, destruction et initialisation des objets ................................... 25
1. Objets automatiques et statiques................................................................................. 25
1.1. Durée de vie d’allocation mémoire...................................................................... 25
1.2. Appel des constructeurs et des destructeurs ......................................................... 25
2. Les objets temporaires ............................................................................................... 25
3. Les objets dynamiques ............................................................................................... 26
4. Tableaux d’objets....................................................................................................... 26
5. Objets d’objets ........................................................................................................... 27
6. Initialisation d’un objet lors de sa déclaration............................................................. 28
6.1. Un premier exemple............................................................................................ 28
6.2. Constructeur par recopie ..................................................................................... 29
6.3. Exemple d’utilisation du constructeur par recopie ............................................... 29
Chapitre 4 : Les fonctions amies ........................................................................................ 32
1. Exemple de fonction indépendante amie d’une classe ................................................ 32
2. Les différentes situations d’amitié .............................................................................. 33
2.1. Fonction membre d’une classe, amie d’une autre classe ...................................... 33
2.2. Fonction amie de plusieurs classes ...................................................................... 33
2.3. Toutes les fonctions d’une classe sont amies d’une autre classe........................... 34
Programmation Orientée Objet en Langage C++
3
M.E
Chapitre 5 : Surdéfinition des opérateurs ......................................................................... 36
1. Le mécanisme de la surdéfinition des opérateurs ........................................................ 36
1.1. Surdéfinition d’opérateur avec une fonction amie................................................ 36
1.2. Surdéfinition d’opérateur avec une fonction membre .......................................... 37
2. Les possibilités et les limites de la surdéfinition des opérateurs en C++...................... 38
2.1. Il faut se limiter aux opérateurs existants............................................................. 38
2.2. Tableau d’opérateurs surdéfinissabes, classés par priorité décroissante ............... 38
2.3. Choix entre fonction membre et fonction amie .................................................... 38
3. Exemple de surdéfinition de l’opérateur ‘[ ]’ .............................................................. 39
4. Exemple de surdéfinition de l’opérateur ‘=’ ............................................................... 40
Chapitre 6 : La technique de l'héritage ............................................................................. 43
1. Mise en œuvre de l'héritage ........................................................................................ 43
1.1. Exemple simple sans constructeur ni destructeur................................................. 43
1.2. Commentaire ...................................................................................................... 43
2. Utilisation, dans une classe dérivée, des membres de la classe de base ....................... 44
3. Redéfinition des fonctions membres........................................................................... 45
4. Appel des constructeurs et des destructeurs ................................................................ 46
5. Contrôle des accès ..................................................................................................... 47
5.1. L’héritage privé .................................................................................................. 47
5.2. Les membres protégés d’une classe ..................................................................... 48
6. L'héritage en général .................................................................................................. 49
7. Conversion d'un objet dérivé dans un objet d'un type de base ..................................... 49
Chapitre 7 : L’héritage multiple ........................................................................................ 50
1. Mise en œuvre de l’héritage multiple ......................................................................... 50
2. Les classes virtuelles .................................................................................................. 51
3. Appel des constructeurs et des destructeurs dans le cas des classes virtuelles ............. 52
Chapitre 8 : Le polymorphisme ......................................................................................... 57
1. Redéfinition des fonctions.......................................................................................... 57
2. Fonction virtuelle pure et classe abstraite ................................................................... 60
2.1. Fonction virtuelle pure ........................................................................................ 60
2.2. Classes abstraites ................................................................................................ 60
Chapitre 9 : Gestion des flux .............................................................................................. 62
1. Généralités sur les flux............................................................................................... 62
2. Afficher sur l’écran avec ‘cout’ .................................................................................. 63
3. Saisir au clavier avec ‘cin’ ......................................................................................... 65
4. Redéfinir les opérateurs de flux .................................................................................. 67
5. Lire à partir d’un fichier ou écrire dans un fichier....................................................... 69
Chapitre 10 : Les templates................................................................................................ 72
1. Les fonctions templates .............................................................................................. 72
2. Les classes templates ................................................................................................. 73
Chapitre 11 : Gestion des exceptions ................................................................................. 76
1. Gestion des erreurs en utilisant les valeurs de retour des fonctions ............................. 76
2. Mise en œuvre des exceptions .................................................................................... 77
2.1. Définir une classe d’exception ............................................................................ 77
2.2. Lancer l’exception .............................................................................................. 78
2.3. Intercepter l’exception ........................................................................................ 79
3. Hiérarchie des classes d’exception ............................................................................. 84
Références bibliographiques .............................................................................................. 87
Programmation Orientée Objet en Langage C++
4
M.E
Chapitre 0 : Spécificités du Langage C++
C++ dispose d’un certain nombre de spécificités qui ne sont pas obligatoirement
relatives à la programmation orientée objet.
1. Commentaire en fin de ligne
Exemple
//ceci est un commentaire.
int a; // déclaration de a.
2. Emplacement des déclarations
La déclaration des variables doit s’effectuer avant leur utilisation n’importe où dans un
bloc ou dans une fonction.
Exemple
main()
{
int a=7, b;
b=a;
float x, y;
x=2*a+y;
}
Exemple
for(int i=0; i<7; i++)
3. Notion de référence
3.1. Transmission des arguments par valeur
Exemple
main()
{
void echange(int,int);
int a=2, b=5;
cout<<”Avant appel : ”<<a<<” - ”<<b<<” \n”;
echange(a,b);
cout<<”Après appel : ”<<a<<” - ”<<b<<” \n”;
}
//------------------------------------------------------void echange(int m,int n)
{
int z; z=m; m=n; n=z;
}
Programmation Orientée Objet en Langage C++
5
M.E
Exécution
3.2. Transmission des arguments par adresse
main()
{
void echange(int *,int *);
int a=2, b=5;
cout<<”Avant appel : ″<<a<<″ - ″<<b<< ” \n ”;
echange(&a,&b);
cout<<”Après appel : ”<<a<<” - “<<b<< ” \n ”;
}
//-------------------------------------------------------void echange(int *x,int *y)
{
int z; z=*x; *x=*y; *y=z;
}
Exécution
3.3. Transmission des arguments par référence
En C++, la transmission par référence est une forme simplifiée de la transmission par
adresse.
main()
{
void echange(int &,int &);
int a=2, b=5;
cout<<″Avant appel : ″<<a<<″ - ″<<b<<″\n ″;
echange(a,b);
cout<<″Apres appel : ″<<a<<″ - ″<<b<<″\n ″;
}
//---------------------------------------------------------void echange (int & x,int & y)
{
int z; z=x; x=y; y=z;
}
4. Les arguments par défaut
En C, il est indispensable que le nombre d’arguments passés correspond au nombre
d’arguments déclarés. C++ peut ne pas respecter cette règle.
Programmation Orientée Objet en Langage C++
6
M.E
Exemple 1
main()
{
int m=1, n=5;
void f(int,int=7);
f(3,5);
f(4);
}
//----------------------------------------------void f(int a,int b)
{
cout<<″Valeur 1 : ″<<a<<″ - Valeur 2 : ″<<b<<″\n″;
}
Exécution
NB :
- La fonction f est déclarée avec un deuxième argument initialisé par défaut par la
valeur 7.
- Pendant l’appel de la fonction f, si le deuxième argument n’est pas précisé, il est alors
égal à la valeur 7.
- Un appel du genre f() sera rejeté par le compilateur.
Exemple2
main()
{
void f(int=33,int=77);
f(99,55);
f(44);
f();
}
//----------------------------------void f(int a,int b)
{
cout<<″Valeur 1 : ″<<a<<″ - Valeur 2 : ″<<a<<″\n″;
}
Exécution
Remarque
Lorsqu’une déclaration prévoit des valeurs par défaut, les arguments concernés doivent
obligatoirement être les derniers de la liste.
Programmation Orientée Objet en Langage C++
7
M.E
Exemple
La déclaration : int f (int=2, int, int=7) ; est interdite, car un appel du genre f(3, 4);
peut être interprété comme : f(2, 3, 4); ou f(3, 4, 7);
5. Surdéfinition de fonction (overloading : surcharge)
On parle de surdéfinition ou de surcharge lorsqu’un même symbole possède plusieurs
significations différentes, le choix de l’une des significations se faisant en fonction du
contexte. Pour pouvoir employer plusieurs fonctions du même nom, il faut un critère
permettant de choisir la bonne fonction. En C++, ce choix est basé sur le type des
arguments.
Exemple
void f(int x)
{ cout<<″fonction numéro 1 : ″<<x<<″\n″; }
void f(double x)
{ cout<<″fonction numéro 2 : ″<<x<<″\n″; }
main()
{
int a=2; double b=5.7;
f(a); f(b); f(‘A’);
}
Exécution
La valeur 65 représente le code ASCII de la lettre A.
Remarque
Le C++ a choisi donc la bonne fonction en fonction de ses arguments.
Cas 1
void f(int); //f1
void f(double); //f2
char c;
float b;
- f(c); appellera la fonction f1 après conversion de la valeur de c en int.
- f(b); appellera la fonction f2 après conversion de b en double.
Cas 2
void f(char *); //f1
void f(void *); //f2
char
*p1;
double
*p2;
- f(p1); appellera la fonction f1.
- f(p2); appellera la fonction f2 après conversion de p2 en void *.
Programmation Orientée Objet en Langage C++
8
M.E
Cas 3
void f(int, double) ; // f1
void f(double, int) ; // f2
int a, b;
double x;
char c ;
- f(a, x); appellera la fonction f1.
- f(c, x); appellera la fonction f1 après conversion de c en int.
- f(a, b); conduira à une erreur de compilation (convertir a en double ou b en double).
Cas 4
void f(int a=0 ; double c=0) ; // f1
void f(double y=0 ; int b=0) ; //f2
int m;
double z ;
-
f(m, z); appellera la fonction f1.
f(z, m); appellera la fonction f2.
f (m); appellera la fonction f1.
f(z); appellera la fonction f2.
f(); conduira à une erreur de compilation.
6. Les opérateurs new et delete
En langage C, la gestion dynamique de la mémoire a été assurée par les fonctions
malloc(…) et free(…). En C++, elle est assurée par les opérateurs new et delete.
6.1. L’opérateur new
Exemple
int *p;
p=new int;
ou
int *p=new int; // Allocation dynamique d’un entier.
int *p2=new int[5]; // Allocation dynamique de 5 entiers.
char *t;
t=new char[30];
ou
char *t=new char [30];
Remarque
new fournit comme résultat :
- Un pointeur sur l’emplacement correspondant, lorsque l’allocation réussie.
- Un pointeur NULL dans le cas contraire.
Programmation Orientée Objet en Langage C++
9
M.E
6.2. L’opérateur delete
delete possède deux syntaxes :
- delete p ;
- delete [ ]p ;
Où p est une variable devant avoir comme valeur un pointeur sur un emplacement
alloué par new.
7. Utilisation des fonctions en ligne (inline)
Une fonction en ligne se définit et s’utilise comme une fonction ordinaire, avec la seule
différence qu’on fait précéder son en-tête de la spécification inline.
Exemple
inline double norme(double vec[3])
{
for(int i=0,double s=0; i<3; i++) s=s+vec[i]*vec[i];
return sqrt(s);
}
//--------------------------------------------------------main()
{
double V1[3], V2[3];
for (int i=0; i<3; i++) { V1[i]=i; V2[i]=i*3; }
cout<<″Norme de V1 est : ″<<norme(v1);
cout<<″ - Norme de V2 est : ″<<norme(v2);
}
Commentaire
-
La fonction norme a pour but de calculer la norme d’un vecteur passé comme
argument.
-
La présence du mot inline demande au compilateur de traiter la fonction norme
d’une manière différente d’une fonction ordinaire, à chaque appel de norme, il devra
incorporer au sein du programme, les instructions correspondantes (en langage
machine). Le mécanisme habituel de gestion de l’appel est de retour n’existe plus, ce
qui réalise une économie de temps.
Remarque
Une fonction en ligne doit être définie dans le même fichier source que celui utilisé. Elle
ne peut être compilée séparément.
Programmation Orientée Objet en Langage C++
10
M.E
Chapitre 1 : Notions de Classe et Objet
Une classe est la généralisation de la notion de type défini par l’utilisateur, dont lequel se
trouvent associées à la fois des données (données membres) et des méthodes (fonctions
membres).
En programmation orientée objet pure, les données sont encapsulées et leur accès ne
peut se faire que par le biais des méthodes.
1. Exemple du type classe
class point // déclaration de la classe point
{
int x;
int y;
public :
void initialise(int,int);
void affiche();
void deplace(int,int);
};
//----Définition des fonctions membres----void point::initialise(int a,int b)
{ x=a; y=b; }
//----------------------------------------void point::affiche()
{ cout<<″on est à : ″<<x<<″ - ″<<y<<endl; }
//----------------------------------------void point::deplace(int a,int b)
{ x=x+a; y=y+b; }
Commentaire
Le mot clé ‘public’ précise que tout ce qui le suit (données membres ou fonctions
membres) sera public, le reste étant privé. Ainsi :
- x et y sont deux membre privés.
- ‘initialise’, ‘deplace’ et ‘affiche’ sont trois fonctions membres publics.
- La classe ‘point’ ci-dessus peut être définie et utilisée comme dans l’exemple
suivant :
Suite du programme (exemple du type classe)
………
main()
{
point p1, p2, p3;
p1.initialise(1,3); p1.affiche();
p1.deplace(2,4);
p1.affiche();
p2.initialise(5,5); p2.affiche();
}
Programmation Orientée Objet en Langage C++
11
M.E
-
On dit que p1 et p2 sont des instances de la classe ‘point’ ou encore que se sont des
objets de type ‘point’.
Tous les membres données de ‘point’ sont privés ou encapsulés. Ainsi, on ne peut
pas accéder à x ou à y.
Toutefois, les membres données ou les fonctions membres peuvent être privées en
utilisant le mot clé ‘private’ ou publiques en utilisant le mot clé ‘public’.
Exemple
class
C
{
public :
……………………………….
……………………………..
private :
……………………………….
……………………………….
};
;
;
;
;
2. Affectation d’objets
Elle correspond à une recopie de valeurs des membres donnés (publics ou privés).
Ainsi, avec les déclarations :
class point
{
int x, y;
public :
………………………… ;
};
point p1, p2;
L’affectation p2=p1 ; provoquera la recopie des valeurs x et y de p1 dans les membres
correspondants de p2.
3. Notion de constructeur et de destructeur
3.1. Introduction
Un constructeur est une fonction qui sera appelée automatiquement après la création
d’un objet. Ceci aura lieu quelque soit la classe d’allocation de l’objet : statique,
automatique ou dynamique.
- De la même façon, un objet pourra posséder un destructeur, il s’agit également d’une
fonction membre qui est appelée automatiquement au moment de la destruction de
l’objet correspondant.
- Par convention, le constructeur se reconnaît à ce qu’il porte le même nom que la classe.
Quand au destructeur, il porte le même nom que la classe précédé du symbole ~.
Exemple
Reprendre l’exemple utilisant la classe ‘point’ définie avec son constructeur.
Programmation Orientée Objet en Langage C++
12
M.E
class point
{
int x ;
int y ;
public :
point(int,int);
void affiche();
void déplace();
};
//----------------------------------------------------point::point(int a , int b)
{ x=a; y=b; }
//---------------------------------------------------void point::affiche()
{ cout<<″on est à : ″<<x<<″ - ″<<y<<″\n″ ;}
//----------------------------------------------------void point::deplace (int a, int b)
{ x=x+a; y=y+b; }
//-------------------------------main()
{
point p1(1,7), p2(2,5);
p1.affiche();
p2.affiche();
p1.deplace(-1,5);
p1.affiche();
p2.deplace(3,3);
p2.afficxhe();
}
3.2. Construction et destruction des objets
Suivre la trace des objets automatiques créés dans le programme suivant en affichant les
moments de leur construction et leur destruction.
class demo
{
int num ;
public :
demo(int);
~demo();
};
//-----------------demo::demo(int n)
{
num=n;
cout<<″Appel constr numéro : ″<<num<<endl;
}
//----------------------------------------------demo::~demo()
{
cout<<″Appel destr numéro : ″<<num<<endl;
}
//-------------------------------------Programmation Orientée Objet en Langage C++
13
M.E
main()
{
void f(int);
demo obj(7);
for (int i=0; i<4; i++)
f(i);
}
//--------------------------------------void f(int m)
{ demo obj(m) ; }
Exécution
3.3. Rôle de constructeur et de destructeur
Le rôle d’un constructeur ou d’un destructeur peut dépasser celui d’initialisation ou de
libération.
Exemple
Construction d’un tableau de 10 valeurs entières prises au hasard, tel que l’argument
passé au constructeur est la valeur entière maximum à ne pas dépasser.
Ajouter une fonction membre appelée : ‘affiche’ pour afficher le contenu du tableau.
class tableau
{
int t[10];
public :
tableau();
void affiche();
};
//--------------------tableau::tableau(int max)
{
for(int i=0;i<10;i++) t[i]=i*2;
}
//-------------------------------------------------void tableau::affiche()
{
for(int i=0;i<10;i++) cout<<t[i]<<endl;
}
Programmation Orientée Objet en Langage C++
14
M.E
Règles
-
Un constructeur peut ou non comporter quelques arguments.
par définition, un constructeur ne renvoie pas de valeur et la présence de void (dans
ce cas précis) est une erreur.
Un destructeur, par définition, ne peut pas disposer d’arguments et ne renvoie pas
de valeur.
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
calss point
{
int x ;
int y ;
……………….
……………….
…………………..
};
- Une déclaration telle que : point p1, p2; provoquera :
Objet p1
Objet p2
p1.x
p2.x
p1.y
p2.y
- Pour pouvoir partager des données entre objets de la même classe, on les déclare
statiques.
Exemple
class
point
{
static
int x;
int y;
………………….
…………………
……………..
};
Programmation Orientée Objet en Langage C++
15
M.E
Une déclaration telle que : point p1, p2; provoquera :
p1.x
p2.x
Objet p1
Objet p2
p1.y
p2.y
p1.x est identique à p2.x mais p1.y ≠ p2.y.
Commentaire
-
-
Les membres statiques existent en un seul exemplaire quelque soit le nombre
d’objets de la classe correspondante, et même si aucun objet de la même classe n’a
été créé.
Les membres statiques sont toujours initialisés par 0.
Exemple
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″;}
//----------------------------------------------------main()
{
void f();
cpt_obj O1; f(); cpt_obj O2;
}
//------------void f(){ cpt_obj a, b; }
Programmation Orientée Objet en Langage C++
16
M.E
Exécution
Exercice 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.
Solution (sous Dev-C++ 4.9.9.2)
class
{
tableau
int t[5];
public :
tableau(){ for(int i=0;i<5;i++) t[i]=0; }
void remplir();
void afficher();
void trier();
};
void tableau::remplir()
{
cout<<"Veuillez remlir le tableau avec 5 entiers :"<<endl;
for(int i=0;i<5;i++) cin>>t[i];
}
void tableau::afficher()
{
for(int i=0;i<5;i++) cout<<t[i]<<"\t"; cout<<endl;
}
void tableau::trier()
{
int a;
for(int i=0;i<4;i++)
for(int j=i+1;j<5;j++)
if(t[i]<t[j]){ a=t[i]; t[i]=t[j]; t[j]=a; }
}
//--------------------------------------------------------main()
{
tableau t1;
t1.remplir();
cout<<"Avant tri : "<<endl; t1.afficher();
t1.trier();
cout<<"Apres tri : "<<endl; t1.afficher();
getch();
}
Programmation Orientée Objet en Langage C++
17
M.E
Exécution
Exercice 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.
Solution (sous Dev-C++ 4.9.9.2)
class
{
tableau
int *t;
int ne;
public :
tableau(int n)
{ ne=n; t=new int[ne]; for(int i=0;i<ne;i++) t[i]=0;}
void remplir();
void afficher();
void trier();
~tableau(){ delete []t;}
};
//----------------------------------------void tableau::remplir()
{ cout<<"Veuillez remplir le tableau avec "<<ne<<" entiers
:"<<endl;
for(int i=0;i<ne;i++) cin>>t[i];
}
//----------------------------------------void tableau::afficher()
{ for(int i=0;i<ne;i++) cout<<t[i]<<"\t"; cout<<endl; }
//------------------------------------------------------void tableau::trier()
{
int a;
for(int i=0;i<ne-1;i++)
for(int j=i+1;j<ne;j++)
if(t[i]>t[j]){a=t[i]; t[i]=t[j]; t[j]=a;}
}
//---------------------------Programmation Orientée Objet en Langage C++
18
M.E
main()
{
tableau t1(3);
t1.remplir();
cout<<"Avant tri : "<<endl; t1.afficher();
t1.trier();
cout<<"Apres tri : "<<endl; t1.afficher();
//----------------------------------------------------tableau t2(5);
t2.remplir();
cout<<"Avant tri : "<<endl; t2.afficher();
t2.trier();
cout<<"Apres tri : "<<endl; t2.afficher();
getch();
}
Exécution
Programmation Orientée Objet en Langage C++
19
M.E
Chapitre 2 : Propriétés des fonctions membres
1. Surdéfinition des fonctions membres
La surdéfinition des fonctions s’applique également aux fonctions membres d’une classe,
y compris au constructeur (mais pas au destructeur puisqu’il ne possède pas
d’arguments).
Exemple
Surdéfinir les fonctions membres ‘point’ et ‘affiche’ de la classe ‘point’.
class point
{
int x, y;
public :
point();
point(int);
point(int,int);
void affiche();
void affiche(char *);
};
//-------------point::point()
{ x=0; y=0; }
//----------------------point::point(int a)
{ x=y=a; }
//----------------------point::point(int a,int b)
{ x=a; y=b; }
//------------------------void point::affiche()
{
cout<<″on est a : ″<<x<<″ - ″<<y<<endl;
}
//-------------------------------------------void point::affiche(char *t)
{
cout<<t;
affiche();
}
//---------------------------main()
{
point p1;
p1.affiche();
point p2(7);
p2.affiche();
point p3(44,52);
p3.affiche();
p3.affiche(″Troisième point : ″);
}
Programmation Orientée Objet en Langage C++
20
M.E
Exécution
2. Arguments par défaut
Les fonctions membres, et les fonctions ordinaires, peuvent disposer d’arguments par
défaut.
Exemple
Modifier l’exemple précédent de telle façon à ce qu’on remplace les deux fonctions
‘affiche’ par une seule, à un argument de type chaîne : le texte à afficher avant le
message : ″on est à : x – y ″. Sa valeur par défaut est la chaîne de caractères vide.
3. Les fonctions membres en ligne
Pour rendre ‘en ligne’ une fonction membre, on l’a défini dans la déclaration de la classe
même (au lieu de la déclarer dans la classe et de la définir ailleurs). Le mot clé ‘inline’
n’est plus utilisé.
Exemple
Reprendre le dernier exemple en définissant les trois constructeurs en ligne.
class point
{
int x, y;
public :
point(){ x=0; y=0; }
point(int a){ x=y=a; }
point(int a,int b){ x=a; int b; }
void affiche(char *);
};
//--------------------------void point::affiche(char *t)
{
cout<<t<<″on est à : ″<<x<<″-″<<y<<endl;
}
//--------------------------------------------main()
{
………………….. ;
………….. ;
}
Programmation Orientée Objet en Langage C++
21
M.E
4. Cas des objets transmis en argument d’une fonction membre
Une fonction membre peut recevoir un ou plusieurs arguments du type de sa classe.
Exemple
class point
{
int x, y;
public :
point(int a,int b){ x=a; y=b; }
int coincide(point);
};
//---------------------------int point::coincide(point O)
{
if(x==O.x && y==O.y) return 1;
return 0;
}
//----------main()
{
point p1(5,7), p2(5,7), p3(6,6);
cout<<″p1 et p2 : ″<<p1.coincide(p2)<<endl;
cout<<″p2 et p3 : ″<<p3.coincide(p2)<<endl;
cout<<″p1 et p3 : ″<<p1.coincide(p3)<<endl;
}
Exécution
5. Mode de transmission des objets, arguments d’une fonction
Dans l’exemple ci-dessus, le mode de transmission utilisé, était par valeur.
5.1. Transmission de l’adresse d’un objet
Reprendre le programme précédent en faisant un passage d’objets par adresse.
class point
{
int x, y;
public :
point (int a=0,int b=0){ x=a; y=b; }
int coincide(point *);
};
//----------------------------
Programmation Orientée Objet en Langage C++
22
M.E
int point::coincide(point *O)
{
if(x==O->x) && (y==O->y) return 1;
return 0;
}
//-----------------------------------------------main()
{
point p1,
cout<<″p1
cout<<″p2
cout<<″p1
}
p2(57),
et p2 :
et p3 :
et p3 :
p3(57,0);
″<<p1.coincide(&p2)<<endl;
″<<p3.coincide(&p2)<<endl;
″<<p1.coincide(&p3)<<endl;
5.2. Transmission par référence
L’emploi des références permet de mettre en place une transmission par adresse, sans
avoir à prendre en charge soi même la gestion.
Exemple
Reprendre le dernier exemple en adaptant la fonction ‘coincide’ de telle façon à ce que
son argument soit transmis par référence.
class
{
point
int x,y ;
public :
point(int a=0,int b=0){ x=a; y=b; }
int coincide(point &);
};
//--------------------------------int point::coincide(point & O)
{
return (x==O.x && y==O.y) ? 1 : 0;
}
//---------------------------------------main()
{
point p1, p2(57), p3(57,0);
cout<<″p1 et p2 : ″<<p1.coincide(p2)<<endl;
cout<<″p2 et p3 : ″<<p3.coincide(p2)<<endl;
cout<<″p1 et p3 : ″<<p1.coincide(p3)<<endl;
}
Exécution
Programmation Orientée Objet en Langage C++
23
M.E
6. 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é.
Exemple
class point
{
int x, y;
public :
point(int a=0,int b=0){ x=a; y=b; }
void affiche(){ cout<<″Point : ″<<x<<″ - ″<<y<<″de
l’objet dont l’adresse est : ″<<this<<endl; }
};
//-----------------------------------------------------------main()
{
point p1, p2(5,3), p3(6,70);
p1.affiche(); p2.affiche(); p3.affiche();
}
Exécution
Programmation Orientée Objet en Langage C++
24
M.E
Chapitre 3 : Construction, destruction et initialisation des objets
1. Objets automatiques et statiques
1.1. Durée de vie d’allocation mémoire
Les objets automatiques sont créés par une déclaration :
- Dans une fonction.
- Dans un bloc.
Les objets statiques créés par une déclaration :
- En dehors de toute fonction.
- Dans une fonction, mais ‘static’.
Remarque
Les objets statiques sont créés avant le début de l’exécution de la fonction ‘main’ et ils
sont détruits après la fin de son exécution.
1.2. Appel des constructeurs et des destructeurs
Exemple
class point
{
int x,y;
public :
point(int a,int b){ x=a; y=b; }
...
};
-
point
point
p1(2, 7) ; est une déclaration correcte.
p2 ; et point p3(17) ; sont des déclarations incorrectes.
Remarque
-
Le constructeur est appelé après la création d’un objet.
Le destructeur est appelé avant la destruction d’un objet.
2. Les objets temporaires
Lorsqu’une classe dispose d’un constructeur, ce dernier peut être appelé explicitement ;
dans ce cas, il y a alors création d’un objet temporaire.
Exemple
class point
{
int x,y;
public :
point(int a,int b){ x=a; y=b; }
...
};
Programmation Orientée Objet en Langage C++
25
M.E
Supposons que ‘p’ est un objet de la classe ‘point’ avec les paramètres (1,1) :
point
p(1,1);
On peut écrire une affectation telle que :
p=point(2,7);
L’évaluation de l’expression point(2,7) ; entraîne :
- La création d’un objet temporaire de type ‘point’ (qui n’a pas de nom).
- L’appel du constructeur ‘point’, pour cet objet temporaire, avec transmission des
arguments spécifiés.
- La recopie de cet objet temporaire dans l’objet p.
Exercice
Ecrire un programme permettant de créer un objet automatique dans la fonction ‘main’,
deux autres objets temporaires affectés à cet objet tout en affichant le moment de leur
création et leurs adresses.
……………….
……………………….
main()
{
point
p(1,1);
p=point(5,2); p.affiche();
p=point(7,3); p.affiche();
}
3. Les objets dynamiques
Exemple
………………………
main()
{
point *p;
p=new point(7,2);
p->affiche(); ou (*p).affiche();
p=new point(8,4);
p->affiche();
delete p;
}
4. Tableaux d’objets
Un tableau d’objet est déclaré sous la forme :
Exemple
point courbe[3];
Programmation Orientée Objet en Langage C++
26
M.E
5. Objets d’objets
Une classe peut contenir des membres données de type quelconque y compris le type
‘class’.
Exemple
Ecrire un programme permettant de définir une classe appelée ‘point_coul’ à partir de la
classe ‘point’ définie précédemment et ayant comme données : x, y et couleur.
class point
{
int x,y;
public :
point (int a=0,int b=0)
{
x=a; y=b;
cout<<″Construction du point : ″<<x<<″ - ″
<<y<<endl;
}
~point()
{
cout<<″Destruction du point : ″<<x<<″ - ″
<<y<<endl;
}
};
//-------------------------------------class point_coul
{
point p;
int couleur;
public :
point_coul(int,int,int);
~point_coul()
{
cout<<"Destruction du point colore En couleur : "
<<couleur<<endl; getch();
}
};
point_coul::point_coul(int a,int b,int c):p(a,b)
{
couleur=c;
cout<<″Construction de point_coul en couleur : ″
<<couleur<<endl;
}
//---------------------------main()
{
point_coul pc(3,7,8);
}
Programmation Orientée Objet en Langage C++
27
M.E
-
L’entête de point_coul spécifie, après les deux points (:), la liste des arguments qui
seront transmis au constructeur ‘point’.
Les constructeurs seront appelés dans l’ordre suivant ‘point’, ‘point_coul’.
S’il existe des destructeurs, ils seront appelés dans l’ordre inverse.
Exécution
6. Initialisation d’un objet lors de sa déclaration
En plus d’une éventuelle initialisation par défaut (réservée aux variables statiques), une
variable peut être initialisée explicitement lors de sa déclaration.
Exemple
int
int
int
n=2;
m=3*n-7;
t[3]={5,12,43};
Remarque
La partie suivant le signe ‘=’ porte le nom d’initialiseur, il ne s’agit pas d’un opérateur
d’affectation.
C++ garantie l’appel d’un constructeur pour un objet créé par une déclaration sans
initialisation (ou par ‘new’). Mais, il est également possible d’associer un initialiseur à la
déclaration d’un objet.
6.1. Un premier exemple
class point
{
int x,y;
public :
point(int a)
{ x=a; y=0;}
};
- point p1(3) ; est une déclaration ordinaire d’un objet ‘p1’ aux coordonnées 3 et 0.
- point p2=7 ; entraîne :
 La création d’un objet appelé ‘p2’.
 L’appel du constructeur auquel on transmet en argument la valeur de
l’initialiseur ‘7’.
En fin, les deux déclarations :
‘point p1(3) ;’ et ‘point p2=7 ;’ sont équivalentes.
Programmation Orientée Objet en Langage C++
28
M.E
6.2. Constructeur par recopie
L’initialiseur d’un objet peut être d’un type quelconque, en particulier, il peut s’agir du
type de l’objet lui-même.
Exemple
point p1(33);
Il est possible de déclarer un nouvel objet ‘p3’ tel que :
point
p3=p1;
// équivalente à : point
p3(p1);
Cette situation est traitée par C++, selon qu’il existe un constructeur ou il n’existe pas de
constructeur correspondant à ce cas.
a. Il n’existe pas de constructeur approprié
Cela signifie que, dans la classe ‘point’, il n’existe aucun constructeur à un seul argument
de type ‘point’. Dans ce cas, C++ considère que l’on souhaite initialiser l’objet ‘p3’ après
sa déclaration avec les valeurs de l’objet ‘p1’. Le compilateur va donc mettre en place
une recopie de ces valeurs. (Analogue à celle qui est mise en place lors d’une affectation
entre objets de même type).
Ce cas est le seul ou C++ accepte qu’il n’existe pas de constructeur.
Une déclaration telle que : ‘point p(x);’ sera rejetée si ‘x’ n’est pas de type ‘point’.
b. Il existe un constructeur approprié
Cela signifie qu’il doit exister un constructeur de la forme : ‘point (point &);’.
Dans ce cas, ce constructeur est appelé de manière habituelle, après la création de
l’objet, sans aucune recopie.
Remarque
C++ impose au constructeur en question que son unique argument soit transmis par
référence.
La forme ‘point (point) ;’ serait rejetée par le compilateur.
6.3. Exemple d’utilisation du constructeur par recopie
6.3.1. Traitement par défaut
class tableau
{
int
ne;
double *p;
public :
tableau(int n)
{
p=new double[ne=n];
cout<<″Constructeur ordinaire : ″
<<this<<″avec son tableau : ″ <<p<<endl;
}
Programmation Orientée Objet en Langage C++
29
M.E
~tableau()
{
delete p;
cout<<″Destruction objet : ″<<this
<<″avec son tableau : ″<<p<<endl;
}
};
//--------------------------------------main()
{
tableau t1(3);
tableau t2=t1; // équivalente à ‘tableau
}
t2(t1);’
Exécution
Commentaire
La déclaration : ‘tableau t1 ;’ a créé un nouvel objet sans faire appel au constructeur,
dans lequel on a recopié les valeurs des membres ‘ne’ et ‘p’ de l’objet t1.
A la fin de l’exécution de ‘main’, il y a appel du destructeur pour ‘t1’ et pour ‘t2’, pour
libérer le même emplacement.
6.3.2. Définition d’un constructeur par recopie
On peut éviter le problème posé ci-dessus de telle façon à ce que la déclaration
‘tableau t2=t1;’ conduise à créer un nouvel objet de type ‘tableau’ avec non
seulement ses membres données ‘ne’ et ‘p’ mais également son propre tableau
dynamique.
Pour ce faire, on définit un constructeur par recopie de la forme :
tableau (tableau &);
Programme (avec remplissage du tableau dynamique)
class tableau
{
int
ne;
double *p;
public :
tableau(int n)
{
p=new double[ne=n];
cout<<"Constructeur ordinaire : "<<this<<
" avec son tableau dynamique : "<<p<<endl;
for(int i=0;i<ne;i++) p[i]=(i+1)*10;
}
tableau(tableau & t)
Programmation Orientée Objet en Langage C++
30
M.E
{
ne=t.ne; p=new double[ne];
cout<<"Constructeur par recopie : "<<this<<
" avec son tableau dynamique : "<<p<<endl;
for(int i=0;i<ne;i++) p[i]=t.p[i];
}
~tableau()
{
delete []p;
cout<<"Destruction objet : "<<this<<
" avec son tableau : dynamique"<<p<<endl;getch();
}
};
//--------------------------------------main()
{
tableau t1(3);
tableau t2=t1; // équivalente à : tableau t2(t1);
getch();
}
Exécution
Programmation Orientée Objet en Langage C++
31
M.E
Chapitre 4 : Les fonctions amies
En principe, l’encapsulation interdit à une fonction membre d’une classe ou toute
fonction d’accéder à des données privées d’une autre classe.
Mais grâce à la notion d’amitié entre fonction et classe, il est possible, lors de la
définition de cette classe d’y déclarer une ou plusieurs fonctions (extérieurs de la classe)
amies de cette classe.
Une telle déclaration d’amitié les autorise alors à accéder aux données privées, au même
titre que n’importe quelle fonction membre.
Il existe plusieurs situations d’amitiés :
1. Fonction indépendante, amie d’une classe.
2. Fonction membre d’une classe, amie d’une autre classe.
3. Fonction amie de plusieurs classes.
4. Toutes les fonctions membres d’une classe, amies d’une autre classe.
1. Exemple de fonction indépendante amie d’une classe
Pour déclarer une fonction amie d’une classe, il suffit de la déclarer dans cette classe en
la précédent par le mot clé ‘friend’.
class point
{
int x,y;
public :
point(int a=0,int b=0) {x=a; y=b;}
friend int coincide(point,point);
};
//-----------------------------------------int coincide(point p1,point p2)
{
if(p1.x==p2.x && p1.y==p2.y) return 1; else return 0;
}
//-------------------------main()
{
point o1(15,2), o2(15,2), o3(13,25);
if(coincide(o1,o2)) cout<<″les objets coïncident\n″;
else cout<<″les objets sont différents\n″;
if(coincide(o1,o3)) cout<<″les objets coïncident\n″;
else cout<<″les objets sont différents\n″;
}
Programmation Orientée Objet en Langage C++
32
M.E
Exécution
Remarques
-L’emplacement de la déclaration d’amitié dans la classe est quelconque.
-Généralement, une fonction amie d’une classe possédera 1 ou plusieurs arguments ou
une valeur de retour du type de cette classe.
2. Les différentes situations d’amitié
2.1. Fonction membre d’une classe, amie d’une autre classe
Syntaxe
class
class
{
B;
A
…………………
public :
friend int
B::f(int,A);
};
//-----------------------------------------------class
B
{
…………………
public:
int f(int,A);
};
//----------------------------------------------------int B::f(int,A)
{
…………………
………………
}
Commentaire
1. la fonction membre ‘f’ de la classe ‘B’ peut accéder aux membres privées de
n’importe quel objet de la classe ‘A’.
2. Pour compiler correctement la déclaration de la classe ‘A’, contenant une
déclaration d’une fonction amie, il faut :
- Définir ‘B’ avant ‘A’.
- Déclarer ‘A’ avant ‘B’.
2.2. Fonction amie de plusieurs classes
Toute fonction membre ou indépendante, peut être amie de plusieurs classes.
Programmation Orientée Objet en Langage C++
33
M.E
Syntaxe
class
{
A
………………
public :
friend void f(A,B);
};//-------------------------------class
B
{
………………
public :
friend void f(A,B);
};//---------------------------void f(A,B)
{
………
}
2.3. Toutes les fonctions d’une classe sont amies d’une autre classe
Au lieu de faire autant de déclarations de fonctions amies qu’il y a de fonctions
membres, on peut résumer toutes ces déclarations en une seule.
Exemple
‘friend class B;’ déclarée dans la classe ‘A’ signifie que toutes les fonctions
membres de la classe ‘B’ sont amies de la classe ‘A’.
Remarque
Pour compiler la déclaration de la classe ‘A’, il suffit de la faire précéder de : ‘class B ;’
Ce type de fonction évite d’avoir à déclarer, les entêtes des fonctions concernées par
l’amitié.
Exercice
Ecrire un programme permettant de réaliser le produit d’une matrice par un vecteur à
l’aide d’une fonction indépendante appelée ‘produit’ amie des deux classes ‘matrice’ et
‘vecteur’.
La classe ‘vecteur’ possède :
- comme données : un vecteur de 3 éléments entiers.
- comme fonctions membres :
 Un constructeur à 3 valeurs entiers.
 Une fonction ‘affiche’ pour afficher le contenu du tableau (vecteur).
La classe ‘matrice’ possède :
- comme donnée : une matrice de 9 éléments (3x3).
- comme fonction membre : un constructeur ayant une matrice (3x3) comme paramètre.
La fonction ‘produit’ retourne normalement un objet de type ‘vecteur’ résultat du
produit d’une matrice par un vecteur.
Programmation Orientée Objet en Langage C++
34
M.E
Programme
class vecteur;
class matrice
{
int m[3][3];
public :
matrice(int ma[3][3])
{
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
m[i][j]=ma[i][j];
}
friend vecteur produit(matrice ma,vecteur ve);
};//-----------------------------------------------class vecteur
{
int v[3];
public :
vecteur(int a=0,int b=0,int c=0){v[0]=a; v[1]=b; v[2]=c;}
void affiche() {for(int i=0;i<3;i++) cout<<v[i]<<"\t";}
friend vecteur produit(matrice ma,vecteur ve);
};//---------------------------------------------------------vecteur produit(matrice ma,vecteur ve)
{
int i,j;
vecteur vect;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
vect.v[i]+=ma.m[i][j]*ve.v[j];
return vect;
}//-----------------------------------------main()
{
vecteur v1(1,2,3);
int mat[3][3]={1,2,3,4,5,6,7,8,9};
matrice m1(mat);
vecteur resultat;
resultat=produit(m1,v1);
resultat.affiche();
getch();
}
Exécution
Programmation Orientée Objet en Langage C++
35
M.E
Chapitre 5 : 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.
1. 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);
1.1. Surdéfinition d’opérateur avec une fonction amie
class point
{
int x,y;
public:
point(int a=0,int b=0) {x=a; y=b;}
void affiche()
{cout<<″Point : ″<<x<<″ - ″ <<y<<endl;}
friend point operator + (point,point);
};
//----------------------------------------point operator + (point p1,point p2)
{
point p;
p.x=p1.x+p2.x;
p.y=p1.y+p2.y;
return p;
}
//-------------------------main()
{
point o1(10,20);
o1.affiche();
point o2(45,50);
o2.affiche();
point o3;
o3.affiche();
o3=o1+o2;
o3.affiche();
o3=operator+(o1,o2);
o3.affiche();
o3=o1+o2+o3;
o3.affiche();
o3=operator+(operator+(o1,o2),o3); o3.affiche();
}
Programmation Orientée Objet en Langage C++
36
M.E
Exécution
1.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)’ .
Exemple
class point
{
int x,y;
public :
point(int a=0,int b=0) {x=a; y=b;}
void affiche()
{ cout<<″Point : ″<<x<<″ - ″<<y<<endl; }
point operator + (point);
};
//---------------------------------------------point point::operator+(point p1)
{
point p;
p.x=x+p1.x; p.y=y+p1.y;
return p;
}
//--------------------------main()
{
point
o1(10,20);
point
o2(40,50);
point
o3;
o3=o1+o2;
o3=o3+o1+o2;
}
Programmation Orientée Objet en Langage C++
o1.affiche();
o2.affiche();
o3.affiche();
o3.affiche();
o3.affiche();
37
M.E
Exécution
2. Les possibilités et les limites de la surdéfinition des opérateurs en C++
2.1. Il faut se limiter aux opérateurs existants
Le symbole suivant le mot clé ‘operator’ doit obligatoirement être un opérateur déjà
défini pour les types de base, sauf l’opérateur point ‘.’. Il n’est donc pas possible de créer
de nouveaux symboles.
Il faut conserver la pluralité (unaire, binaire) de l’opérateur initial.
Lorsque plusieurs opérateurs sont combinés au sein d’une même expression, ils
conservent leurs priorités relatives et leurs associativités.
2.2. Tableau d’opérateurs surdéfinissabes, classés par priorité décroissante
Pluralité
Binaire
Unaire
Binaire
Binaire
Binaire
Binaire
Binaire
Binaire
Binaire
Binaire
Binaire
Binaire
Binaire
Binaire
◊:
Opérateur
Associativité














( )◊ [ ] ◊ ◊
+ - ++ -- ! & new◊ delete◊
* / %
+ << >>
< <= > >=
== !=
& (niveau bit)
^ (ou exclusif)
||
&&
| (niveau bit)
=◊ += -= *= /= %= &= ^= |= <<= >>=
,
opérateur devant être surdéfini en tant que fonction membre.
2.3. Choix entre fonction membre et fonction amie
Si un opérateur doit absolument recevoir un type de base en premier argument, il ne
peut pas être défini comme fonction membre (laquelle reçoit implicitement un premier
argument du type de sa classe).
Programmation Orientée Objet en Langage C++
38
M.E
3. Exemple de 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’. Le premier opérande
de ‘o[i]’ étant ‘o’.
class tableau
{
int ne;
int *p;
public :
tableau(int n)
{
p=new int[ne=n]; for(int i=0;i<ne;i++) p[i]=(i+1)*10;
}
void affiche()
{for(int i=0;i<ne;i++) cout<<p[i]<<"\t"; cout<<endl;}
int operator[](int n){ return p[n]; }
~tableau(){delete []p;}
};
//--------------------------------------main()
{
tableau t1(3);
t1.affiche();
cout<<t1[2];
t1.affiche();
}
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 :
class tableau
{
int
ne;
int
*p;
public :
tableau(int n)
{
p=new int[ne=n]; for(int i=0;i<ne;i++) p[i]=(i+1)*10;
}
void affiche()
{for(int i=0;i<ne;i++) cout<<p[i]<<"\t"; cout<<endl;}
int & operator[](int n){ return p[n]; }
~tableau(){delete []p;}
};
Programmation Orientée Objet en Langage C++
39
M.E
main()
{
tableau t1(3);
t1.affiche();
cout<<t1[2];
cout<<endl;
t1[0]=55; cout<<t1[0];
cout<<endl;
t1.affiche();
}
Exécution
Remarque
L’opérateur ‘[]’ n’est pas imposé ici par C++, on aurait pu le remplacer par l’opérateur ‘()’
: ‘o(i)’ au lieu de : ‘o[i]’, ou un autre opérateur.
4. Exemple de surdéfinition de l’opérateur ‘=’
Reprenons le cas de la classe ‘tableau’ :
class tableau
{
int ne;
int *p;
public :
............;
};
Le problème de l’affectation est donc voisin de celui de la construction par recopie, mais
non identique :
 Dans le cas de la construction par recopie (tableau t1(3); tableau t2=t1;),
on a un seul tableau dynamique de 3 entiers pour les deux objets t1 et t2.
 Dans le cas d’affectation d’objets, il existe deux objets complets (avec leurs tableaux
dynamiques). Mais après affectation (t2=t1), t2 et t1 référencent le même
tableau dynamique (celui de t1), le tableau dynamique de t2 n’est plus référencé.
 Ce problème peut être résolu en surdéfinissant l’opérateur d’affectation ; de manière
à ce que chaque objet de type ‘tableau’ possède son propre emplacement
dynamique.
 Dans ce cas, on est sûr qu’il n’est référencé qu’une seule fois, et son éventuel
libération peut se faire sans problèmes.
Programmation Orientée Objet en Langage C++
40
M.E
 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).
class tableau
{
int
ne;
int
*p;
public :
tableau(int n)
{
p=new int[ne=n];
for(int i=0;i<ne;i++) p[i]=(i+1)*10;
}
void affiche(){for(int i=0;i<ne;i++) cout<<p[i]<<"\t";
cout<<endl;
}
tableau & operator=(tableau & t)
{
delete []p;
p=new int[ne=t.ne];
for(int i=0;i<ne;i++) p[i]=t.p[i];
return *this;
}
~tableau()
{
delete []p;
}
};
//--------------------------------------main()
{
tableau t1(3); t1.affiche();
tableau t2(4); t2.affiche();
tableau t3(5); t3.affiche();
t1=t3;
t1.affiche(); t3.affiche();
t1=t2=t3;
t1.affiche();
}
Programmation Orientée Objet en Langage C++
41
M.E
Exécution
class tableau
{
int
ne;
int
*p;
public :
tableau(int n)
{
p=new int[ne=n];
for(int i=0;i<ne;i++) p[i]=(i+1)*10;
}
void affiche(){for(int i=0;i<ne;i++) cout<<p[i]<<"\t";
cout<<endl;}
tableau & operator=(tableau & t)
{
if(this!=&t)
{
delete []p;
p=new int[ne=t.ne];
for(int i=0;i<ne;i++) p[i]=t.p[i];
}
return *this;
}
~tableau()
{
delete []p;
}
};
//--------------------------------------main()
{
tableau t1(3); t1.affiche();
t1=t1;
t1.affiche();
}
Exécution
Exercice
Refaire le même traitement pour des tableaux dynamiques de caractères.
Programmation Orientée Objet en Langage C++
42
M.E
Chapitre 6 : La technique de l'héritage
1. Mise en œuvre de l'héritage
1.1. Exemple simple sans constructeur ni destructeur
1.1.1. La classe de base ‘point’ définie dans le fichier d'entête ‘point.h’
class point
{
int x, y;
public:
void initialise(int,int);
void deplace(int,int);
void affiche();
};
void point::initialise(int a,int b){x=a; y=b;}
void point::deplace(int a,int b){x=x+a; y=y+b;}
void point::affiche(){cout<<"Point : "<<x<<" - "<<y<<endl;}
1.1.2. La classe 'point_colore' derivée de la class 'point'
#include <point.h>
Class point_colore : public point
{
int couleur;
public:
void colorer(int c) {couleur=c;}
};
1.2. Commentaire
- La déclaration ‘class point_colore : public point’ spécifie que la classe 'point_colore' est
dérivée de la classe de base 'point'.
- Le mot clé ‘public’ signifie que les membres publics de la class de base seront des
membres publics de la classe dérivée.
Le programme principal
main()
{
point_colore
p;
p.inisialise(12,27);
p.deplace(1,2);
}
p.colorer(7);
p.affiche();
p.affiche();
Exécution
Programmation Orientée Objet en Langage C++
43
M.E
2. Utilisation, dans une classe dérivée, des membres de la classe de base
Après avoir fait appel à la fonction 'colorer', la fonction ‘affiche’ ne donne aucune
information sur la couleur d'un point. Ce qui nous conduit donc à créer une fonction
'affiche_c' membre de ‘point_colore pour afficher les coordonnées x, y et la couleur c.
void affiche_c()
{
cout<<"Point : "<<x<<" - "<<y;
cout<<"En couleur : "<<couleur<<endl;
}
Or, une classe dérivée n'a pas accès aux membres privés de la classe de base. La solution
est donc :
void affiche_c()
{ affiche(); cout<<" en couleur : "<<couleur<<endl; }
De même on peut initialiser x, y et couleur en même temps avec une fonction
'initialise_c' de la classe dérivée 'point_colore'.
Le programme complet est donc :
class point
{
int x, y;
public:
void initialise(int a,int b){x=a;y=b;}
void deplace(int a,int b){x=x+a; y=y+b;}
void affiche(){cout<<"Point : "<<x<<" - "<<y;}
} ;
//---------------------------------------------------class point_colore:public point
{
int couleur;
public:
void initialise_c(int c)
{couleur=c;}
void colorer(int c)
{couleur=c;}
void affiche_c()
{
affiche();
cout<<" En couleur : "<<couleur<<endl;
}
};
Programmation Orientée Objet en Langage C++
44
M.E
main()
{
point_colore
p;
p.initialise(12,9); p.colorer(7);
p.affiche(); cout<<endl; p.affiche_c();
p.deplace(1,2);p.affiche(); cout<<endl; p.affiche_c();
}
Exécution
3. Redéfinition des fonctions membres
Les méthodes 'affiche' de la classe 'point' et 'affiche_c' de la classe 'point_colore' font un
travail analogue. De même pour les fonctions 'initialise' et 'initialise_c'.
En c++, il est possible de redéfinir la fonction 'affiche' ou la fonction 'inialise’ pour la
classe dérivée.
Exemple
#include <point.h>
class point_colore:public
{
int couleur;
point
public:
void colorer(int c){couleur=c;}
void affiche()
{
point::affiche();
cout<<" en couleur : "<<couleur<<endl;
}
void initialise(int a,int b,int c)
{point::initialise(a,b); couleur=c;}
};
//-------------------------------------------main()
{
point_colore p;
p.initialise(12,27,9);
p.affiche();
p.deplace(10,20);
p.affiche();
p.colorer(7);
p.affiche();
}
Programmation Orientée Objet en Langage C++
45
M.E
Exécution
4. Appel des constructeurs et des destructeurs
Si on a :
class
{
point
int x,y;
public:
point(int,int);
};
//--------------------------------------------class point_colore:public point
{
int couleur;
public:
point_colore(int,int,int);
};
Pour créer un objet de la classe ‘point_colore’, il faut tout d’abord créer un objet de la
classe ‘point’, donc faire appel au constructeur de la classe ‘point’, le compléter par ce
qui est spécifique a la classe ‘point_colore’ et faire appel au constructeur de la classe
‘point_colore’.
Si on souhaite que le constructeur de la classe ’point_clolre’ retransmette au
constructeur de la classe ‘point’ les premières informations reçues, on écrira :
‘point_colore(int a, int b, int c):point(a, b) ;’.
Ainsi, la déclaration : ‘point_colore(2,4,5) ;’ entraînera :
-
l’appel du constructeur ’point’ qui recevra les valeurs 2 et 4.
l’appel du constructeur ’point_colore’ qui recevra les valeurs 2, 4 et 5.
Il est toujours possible de mentionner les valeurs par défaut :
point_colore(int a=0, int b=2, int c=5):point(a,b)
Donc la déclaration ‘point_colore(17) ;’ entraîne :
- appel du constructeur ‘point’ avec les valeurs 17 et 0.
- appel du constructeur ‘point_colore’ avec les valeurs 17, 2 et 5.
Exercice
Reprendre le programme précédent en ajoutant les constructeurs et les destructeurs
correspondants, tout en affichant les moments de constriction et de destruction des
objets. Prévoir aussi des objets dynamiques.
Programmation Orientée Objet en Langage C++
46
M.E
D’une manière générale
Si la classe de base ne possède pas de constructeur, aucun problème particulier ne se
pose. De même si elle ne possède pas de destructeur.
En revanche, si la classe dérivée ne possède pas de constructeur, alors que la classe de
base en comporte, le problème sera posé lors de la transmission des informations
attendues par le constructeur de la classe de base. La seule situation acceptable est celle
où la classe de base dispose d’un constructeur sans arguments.
Lors de la transmission d’information au constructeur de la classe de base, on peut
utiliser des expressions ou des arguments.
Exemple
pointcolore(int a=5, int b=5, int c=4):point(a*2, b*5);
5. Contrôle des accès
5.1. L’héritage privé
Pour que l’utilisateur d’une classe dérivée n’ait pas accès aux membres publics de sa
classe de base, il suffit de remplacer le mot ‘public’ par ‘private’ dans sa déclaration.
Exemple
class
{
point
int
x, y;
public:
void initialise(int,int) {x=a; y=b;}
void deplace(int,int) {x=x+a; y=y+b;}
void affiche(){
……………………… }
};
//---------------------------------------class point_colore : private point
{
int
couleur;
public:
void
colorer(int c)
{couleur=c;}
};
Si on a :
point_colore O(12,4,6);
Les appels suivants sont rejetés :
O.affiche(); ou O.point::affiche();
O.deplace(1,5); ou O.point::depace(1,5);
Programmation Orientée Objet en Langage C++
47
M.E
Remarque
Cette technique de fermeture d’accès à la classe de base ne sera employée que dans des
cas précis, lorsque par exemple toutes les fonctions utiles de la classe de base sont
redéfinies dans la classe dérivée, et qu’il n’y a aucune raison de laisser l’utilisateur
accéder aux anciennes.
5.2. Les membres protégés d’une classe
Les membres protégés restent inaccessibles à l’utilisateur (comme les membres privés).
Mais ils seront accessibles aux membres d'une éventuelle classe dérivée, tout en restant
inaccessibles aux utilisateurs de cette classe.
Exemple
Supposons qu'on a :
class
point
{
protected:
int x,y;
public:
void initialise(int,int);
void deplace(int,int);
void affiche();
};
On peut donc déclarer dans la classe 'point_colore' dérivée de la classe 'point' une
fonction 'affiche' qui accède aux membres protégés x et y.
class
{
point_colore:public point
int
couleur;
public:
void affiche()
{ cout<<"Point coloré " <<x<<" - " <<y<<endl;
cout<<"en couleur : "<<couleur<<endl;
}
};
Remarque
Lorsqu'une classe dérivée possède une classe amie, cette dernière dispose des mêmes
droits d'accès que les fonctions membres de la class dérivée.
Programmation Orientée Objet en Langage C++
48
M.E
6. L'héritage en général
D'une façon générale, l'héritage peut être représenté par les arbres suivants :
A
B
D
E
C
F
G
H
Héritage simple
A
B
C
D
Héritage complexe
7. Conversion d'un objet dérivé dans un objet d'un type de base
Si on a :
point
point_colore
-
o1;
o2;
l'affectation ‘o1=o2 ;’ est juste.
l'affectation ‘o2=o1 ;’ est rejetée (si o2 a des arguments définis par défaut, on
n’aura pas de problème).
Exercice
A. Ecrire un programme écran de veille affichant des points (objets de type 'pointg' à
définir) en couleur à tout endroit de l'écran, et ce, jusqu'a ce que l'utilisateur appuie
sur une touche quelconque.
B. Reprendre le même programme en ajoutant des objets de la classe 'cercle' dérivée
de la classe 'pointg' et ayant en plus, la donnée membre 'rayon' et les méthodes :
- affiche_cercle : pour afficher un cercle aux coordonnées x, y.
- cache_cercle : pour rendre un cercle invisible.
- zoom_cercle : pour afficher une série de cercles concentriques.
- deplace_cercle : pour déplacer un cercle.
- ………
Programmation Orientée Objet en Langage C++
49
M.E
Chapitre 7 : L’héritage multiple
1. Mise en œuvre de l’héritage multiple
L’exemple suivant met en évidence la notion d’héritage multiple à travers la classe
‘point_colore’ héritant des classes ‘point’ et ‘coul’.
point
coul
pointcolore
class
point
{
int x,y;
public:
point(int a,int b)
{
x=a ;y=b ;
cout<<"Constructeur de point ";
}
~point(){cout<<"Destructeur de point ";}
void affiche(){cout<<"point "<<x<<" - "<<y;}
};
//----------------------------class coul
{
int couleur ;
public :
coul(int c)
{
couleur=c ;
cout<<"Construction de coul ";
}
~coul(){cout<<"Destruction de coul ";}
void
affiche()
{cout<<"Couleur : "<<couleur<<endl;}
};
//------------------------------------------------class point_colore:public point,public coul
{
public:
point_colore(int a,int b,int c):point(a,b),coul(c)
{cout<<"construction de pointcolore\n";}
Programmation Orientée Objet en Langage C++
50
M.E
~pointcolore()
{cout<<"destruction de pointcolore\n"; }
void affiche()
{
point::affiche();
coul::affiche();
}
};
//--------------------------------------main()
{
point_colore
o(100,200,3);
o.affiche();
o.point::affiche();
o.coul::affiche();
}
Exécution
2. Les classes virtuelles
Si on a :
A
B
C
D
Donc les déclarations suivantes :
class
A
{
int x,y;
………………
};
class
B:public A
{ ……………… };
class
C:public A
{ ……………… };
class
D:public B, public C
{ ……………… };
Programmation Orientée Objet en Langage C++
51
M.E
Impliquent que la classe ‘D’ hérite deux fois de la classe ‘A’, donc les membres de ‘A’ vont
apparaître deux fois dans ‘D’.
- les fonctions membres ne sont pas réellement dupliquées.
- les données membres seront effectivement dupliquées.
Donc :
- si on veut laisser cette duplication, on utilise :
A::B::x ≠ A::C::x ou B::x ≠ C ::x
- si on ne veut pas de cette duplication, on précisera la classe ‘A’ comme classe virtuelle
dans les déclarations des classes ‘B’ et ‘C’.
class
A
{
int x,y;
…………………..
};
class
B:public virtual A
{
…………………….
};
class
C:public virtual A
{
………..
};
class
D:public B, public C
{
…………….
};
Remarque
- le mot-clé ‘virtual’ apparaît dans la classe ‘B’ et la classe ‘C’.
- le mot-clé ‘virtual’ peut être placé avant ou après le mot-clé ‘public’.
3. Appel des constructeurs et des destructeurs dans le cas des classes virtuelles
A1
A2
B
C
A
B
C

D
D
- Si ‘A’ n’est pas déclarée ‘virtual’ dans les classes ‘B’ et ‘C’, les constructeurs seront
appelés dans l’ordre : ‘A1’, ‘B’, ‘A2’, ‘C’ et ‘D’.
- Si ‘A’ a été déclarée ‘virtual’ dans ‘B’ et ‘C’, on ne construira qu’un seul objet de type de
‘A’ (et non pas deux objets).
Programmation Orientée Objet en Langage C++
52
M.E
Quels arguments faut-il transmettre alors au constructeur ? Ceux prévus par ‘B’ ou ceux
prévus par ‘C’ ?
Le choix des informations à transmettre au constructeur de ‘A’ se fait, non plus dans ‘B’
ou ‘C’, mais dans ‘D’. Pour ce faire, C++ autorise (uniquement dans ce cas) à spécifier,
dans le constructeur de ‘D’, des informations destinées à ‘A’.
Ainsi, on peut avoir :
D(int a, int b, int c) : B(a,
b,
c), A(a, b)
Bien entendu, il sera inutile de préciser des informations pour ‘A’ au niveau des
constructeurs ‘B’ et ‘C’.
En ce qui concerne l’ordre des appels, le constructeur d’une classe virtuelle est
toujours appelé avant les autres. Dans notre cas, on a l’ordre ‘A’, ‘B’, ‘C’ et ‘D’.
Exemple
A
B
C
D
E
L’ordre des appels des constructeurs est : B, A, C, D et E.
Exercice
Interpréter et commenter le programme utilisant l’héritage multiple dans l’exemple
suivant de liste simplement chaînée de points ( objets appartenant à la classe ‘point’).
liste
point
liste_point
Programmation Orientée Objet en Langage C++
53
M.E
struct
element
{
element
*suivant;
void
*contenu;
};
//------------------------------------------class liste
{
element *debut;
element *courant;
public:
liste()
{
debut=NULL;
courant=debut;
}
~liste();
void ajouter();
void *premier()
{
courant=debut;
return(courant->contenu);
}
void *prochain()
{
if(courant!=NULL) courant=courant->suivant;
return(courant->contenu);
}
int finir()
{
return(courant==NULL);
}
};
Solution avec liste simple d’entiers sans objets :
typedef struct sm
{
int don;
sm *suiv;
} MAILLON;
//--------------------typedef MAILLON *LISTE;
//---------------------------------------
Programmation Orientée Objet en Langage C++
54
M.E
void Ajouter(LISTE & l, LISTE & p, int n)
{
if(l==NULL)
{
l=new MAILLON;
l->don=n;
l->suiv=NULL;
p=l;
}
else
{
p->suiv=new MAILLON;
p=p->suiv;
p->don=n;
p->suiv=NULL;
}
}
//----------------void Lire(LISTE l)
{
LISTE p=l;
while(p!=NULL)
{
cout<<p->don<<endl;
p=p->suiv;
}
}
//---------------------------main()
{
LISTE L1=NULL; LISTE C1=NULL;
Ajouter(L1,C1,33);
Ajouter(L1,C1,44);
Ajouter(L1,C1,55);
Ajouter(L1,C1,66);
Ajouter(L1,C1,77);
Lire(L1);
}
Solution avec liste simple avec objets :
typedef struct sm
{
sm *suiv;
int contenu;
} MAILLON;
//-------------------------------
Programmation Orientée Objet en Langage C++
55
M.E
class liste
{
MAILLON *debut;
MAILLON *courant;
public:
liste(){ debut=NULL; courant=debut; }
~liste(){ }
void Ajouter(int n)
{
if(debut==NULL)
{
debut=new MAILLON;
debut->contenu=n;
debut->suiv=NULL;
courant=debut;
}
else
{
courant->suiv=new MAILLON;
courant=courant->suiv;
courant->contenu=n;
courant->suiv=NULL;
}
}
void Afficher()
{
MAILLON *courant=debut;
while(courant!=NULL)
{
cout<<courant->contenu<<endl;
courant=courant->suiv;
}
}
};
main()
{
liste l1;
l1.Ajouter(33); l1.Ajouter(44); l1.Ajouter(55);
l1.Afficher();
cout<<endl;
liste l2;
l2.Ajouter(333); l2.Ajouter(444); l2.Ajouter(555);
l2.Afficher();
}
Exécution
Programmation Orientée Objet en Langage C++
56
M.E
Chapitre 8 : Le polymorphisme
Le polymorphisme forme avec l’encapsulation et l’héritage les trois piliers des langages
orientés objets.
1. Redéfinition des fonctions
Exemple
Utilisation d’un pointeur de base pour manipuler un objet d’une classe dérivée.
class materiel
{
protected :
char ref[20];
char marque[20];
public :
materiel(char *r, char *m)
{
strcpy(ref,r);
strcpy(marque,m);
}
void affiche()
{cout<<"Reference : "<<ref<<"\tMarque : "<<marque<<endl;}
};
//----------------------------------------------------------class micro:public materiel
{
char processeur[20];
int disque;
public :
micro(char *r,char *m,char *p,int d):materiel(r,m)
{
strcpy(processeur,p);
disque=d ;
}
void affiche()
{
cout<<"Reference : "<<ref<<"\tMarque : "<<marque
<<"\tProcesseur : "<<processeur
<<"\tDisque : "<<disque<<endl;
}
};
//------------------------------------
Programmation Orientée Objet en Langage C++
57
M.E
main ()
{
materiel *p;
p=new materiel("HP5010","HP");
p->affiche();
p=new micro("IBM7","IBM","P4",40);
p->affiche();
delete p;
}
Exécution
Commentaire
- Le pointeur ‘p’ est utilisé pour stocker l’adresse d’un objet de la classe ‘materiel’,
appeler la fonction ‘affiche’ et détruire l’objet créé.
- Le pointeur ‘p’ est ensuite utilisé pour réaliser les mêmes opérations sur un objet de la
classe ‘micro’.
-Dans le cas des deux objets créés, c’est la méthode ‘affiche’ de la classe ‘matériel’ qui a
été utilisée. Le compilateur a donc tenu compte du type de pointeur (matériel*) et non
du type d’objet pointé par ‘p’.
- L’idéal serait donc que le compilateur appelle ‘affiche’ de ‘micro’ quand ‘p’ pointe sur
‘micro’ et ‘affiche’ de ‘matériel’ quand ‘p’ pointe sur ‘matériel’.
- Pour obtenir ce résultat, il suffit d’indiquer au compilateur que la fonction ‘affiche’ est
une fonction polymorphe, c.à.d une fonction virtuelle.
Définition
Une fonction polymorphe (ou virtuelle) est une méthode qui est appelée en fonction du
type d’objet et non en fonction du type de pointeur utilisé.
Exemple
Pour que le programme précédent fonctionne correctement, il faut déclarer la
fonction ‘affiche’ une fonction polymorphe ou virtuelle en précédant son prototype par
le mot clé ‘virtual’.
Programmation Orientée Objet en Langage C++
58
M.E
class materiel
{
protected :
char ref [20+1];
char marque [20+1];
public :
materiel (char *r, char *m)
{
strcpy(ref,r);
strcpy(marque,m);
}
virtual void affiche()
{cout<<"Reference : "<<ref<<"\tMarque : "<<marque<<endl;}
};
class micro : public materiel
{
char processeur [20+1];
int disque;
public :
micro(char *r,char *m,char *p,int d): materiel(r,m)
{
strcpy(processeur,p);
disque=d ;
}
void affiche()
{
cout<<"Reference : "<<ref<<"\tMarque : "<<marque
<<"\tProcesseur : "<<processeur
<<"\tDisque : "<<disque<<endl;
}
};
//---------------------------------------main ()
{
materiel *p;
p=new materiel("HP5010","HP");
p->affiche();
p=new micro("IBM7","IBM","P4",40);
p->affiche();
delete p;
}
Exécution
Programmation Orientée Objet en Langage C++
59
M.E
Remarque
Seule la fonction ‘affiche’ de la classe de base ‘matériel’ doit être déclarée virtuelle.
Cependant, il est conseillé d’indiquer le mot clé ‘virtual’ pour toutes les fonctions
concernées par le polymorphisme, et cela, quel que soit leur niveau dans la hiérarchie
des classes.
Exercice
Ajouter une classe ‘imprimante’ et une classe ‘scanner’ dérivées de la classe ‘matériel’ et
écrire un programme global sous forme de menu donnant à l’utilisateur la possibilité de
choisir le type de matériel à afficher.
Remarque
- Lorsqu’on appelle une fonction virtuelle pour un objet, le C++ cherche cette méthode
dans la classe correspondante. Si cette fonction n’existe pas dans la classe concernée, le
C++ remonte la hiérarchie des classes jusqu'à ce qu’il trouve la fonction appelée.
- Une fonction virtuelle ne peut être appelée par une autre méthode de la classe.
- Une fonction virtuelle ne peut être utilisée dans le corps d’un constructeur ou d’un
destructeur.
2. Fonction virtuelle pure et classe abstraite
2.1. Fonction virtuelle pure
- Une fonction virtuelle pure est une fonction telle que par exemple :
virtual void affiche()=0;
- Définir une fonction virtuelle pure entraîne :
 Une classe qui contient la définition d’une fonction virtuelle pure devient une
classe abstraite.
 La redéfinition des fonctions virtuelles pures est obligatoire dans toutes les
classes dérivées. Dans le cas contraire, les classes dérivées deviennent
obligatoirement abstraites.
2.2. Classes abstraites
- Une classe abstraite est une classe qui ne peut être instanciée. Par contre, on peut créer
des objets de ce type via l’héritage.
Programmation Orientée Objet en Langage C++
60
M.E
Le programme complet :
class materiel
{
protected :
char ref [20+1];
char marque [20+1];
public :
materiel (char *r, char *m)
{
strcpy(ref,r);
strcpy(marque,m);
}
virtual void affiche()=0;
};
void materiel::affiche()
{cout<<"Reference : "<<ref<<"\tMarque : "<<marque<<endl;}
//---------------------------------------------------class micro : public materiel
{
char processeur [20+1];
int disque;
public :
micro(char *r,char *m,char *p,int d): materiel(r,m)
{
strcpy(processeur,p);
disque=d ;
}
void affiche()
{
cout<<"Reference : "<<ref<<"\tMarque : "<<marque
<<"\tProcesseur : "<<processeur
<<"\tDisque : "<<disque<<endl;
}
};
//---------------------------------------main()
{
materiel
*p;
//p=new materiel("HP5010","HP");
//p->affiche();
p=new micro("IBM7","IBM","P4",40);
p->affiche();
delete p;
}
Programmation Orientée Objet en Langage C++
61
M.E
Chapitre 9 : Gestion des flux
Pour manipuler les flux d’entrées/sorties, le c++ met à notre disposition des opérateurs
surchargés << et >> qui permettent respectivement d’afficher et de lire des données, ces
opérateurs pourront parfaitement être redéfinis dans le cas de nos classes, ce qui
permettra par exemple d’afficher le contenu des données membres d’une classe à
l’écran, ou d’écrire ces mêmes variables dans un fichier.
1. Généralités sur les flux
Un flux représente un ensemble de données pouvant être manipulés à la fois en lecture
ou à la fois en écriture.
Un flux, aussi appelé canal de données, offre une transparence vis-à-vis de la source ou
de la destination des données :
- Ecran, fichier, mémoire pour les types de flux de sortie.
- Clavier, fichier, mémoire pour les types de flux d’entrée.
En C++, tous les flux sont symbolisés par des classes qui font partie de la librairie
‘iostream.h’.
La classe de base est iostream et regroupe les caractéristiques communes aux flux
d’E/S.
Les deux principales classes dérivées de la classe iostream sont ostream pour les flux
de sortie, et istream pour les flux d’entrées.
Toute les classes de la librairie ‘iostream.h’ disposent des deux opérateurs surchargés
<< et >>. L’opérande de gauche de l’opérateur << doit correspondre à un objet de la
classe ostream, pour l’opérateur >> cet opérande doit être un objet de la classe istream.
Ces deux opérateurs ont été définis pour les types de données suivants : char, short, int,
long, float, double, long double, char*, void*.
C++ fournie quatre flux prédéfinis pour afficher ou lire des informations.
cout : Flux de sortie standard (l’écran par défaut). Cette variable est un objet d’une
classe dérivée de ostream.
cin
: Flux d’entrée standard (le clavier par défaut). Cette variable est un objet d’une
classe dérivée de istream.
cerr : Sortie erreur standard (l’écran par défaut). Cette variable est un objet d’une
classe dérivée de ostream.
clog : Permet à la fois d’envoyer des messages d’erreur vers la sortie erreur standard
(l’écran par défaut) et de remplir un fichier d’alerte. Cette variable est un objet de
la classe ‘ostream’.
Programmation Orientée Objet en Langage C++
62
M.E
2. Afficher sur l’écran avec ‘cout’
Exemple
main()
{
int e=37;
float x=4,5;
cout<<"debut \n";
cout<<"Entier : "<<e<<endl;
cout<<"Reel : "<<x<<endl;
}
Commentaire
- Ce programme utilise 3 fois l’objet ‘cout’ pour afficher du texte à l’écran.
- La librairie ‘iostream.h’ fournit un certain nombre de mots clés qui permettent de
modifier les caractéristiques d’un flux. Ces commandes sont utilisées directement avec
l’opérateur << en respectant la syntaxe : ‘cout<<manipulateur ;’.
Manipulateur
dec
hex
oct
ws
endl
ends
flush
setbase(int a)
setfill(int c)
setprecision(int c)
setw
Rôle
Convertir en base décimale
Convertir en base hexadécimale
Convertir en base octale
Supprimer les espaces
Ajouter un saut de ligne en fin de flux (\n)
Ajouter un caractère de fin de chaîne
Vider un flux de sortie
Choisir la base (0, 8, 10 ou 16) . 0 est la valeur par défaut
Choisir le caractère de remplissage (padding)
Indiquer le nombre de chiffres d’un nombre décimal
Choisir la taille du champ (padding)
Exemple
int e=31;
cout<<e;
cout<<hex<<e;
Remarque
Le padding consiste à compléter généralement avec des espaces ou des zéros, un
élément affiché à l’écran en précisant la taille d’un champ ou d’une colonne (set w). Tout
élément affiché dont la taille est insuffisante sera complété par défaut par des espaces.
De cette manière chaque élément sera affiché sur la même longueur de caractères.
En plus de ces manipulateurs, la classe iostream fournit un ensemble de méthodes.
Méthodes
fill()
fill(char c)
Programmation Orientée Objet en Langage C++
Rôle
Renvoie le caractère de remplissage
modifie le caractère de remplissage
63
M.E
précision()
précision(int n)
setf(long flag)
setf(long flag,long champ)
width()
width(int n)
renvoie la précision pour le nombre décimal
modifie la précision pour le nombre décimal
modifie une propriété de formatage (format)
Modifie une propriété de formatage d’un champ
Renvoie la valeur d’affichage
Renvoie la valeur d’affichage
Exemple
main()
{
int e=15;
cout<<"conversion"<<endl;
cout<<"Entier : "<<e<<endl;
cout<<"Hexadecimal : "<<hex<<e<<endl;
cout<<"Octal : "<<oct<<e<<endl;
cout<<"------------------------------------------\n";
cout<<"Largeur et Padding\n";
float x=3.15;
cout.setf(ios::right,ios::adjustfield);
cout<<"Decimal : "<<setw(10)<<x<<endl;
cout<<"Decimal : "<<setw(10)<<x+1000<<endl;
cout<<"Decimal : "<<setw(10)<<setfill('#') <<x<<endl;
cout<<"-------------------------------------------\n";
cout<<"Nombre de chiffres\n";
double pi=3.14151617;
cout<<"PI : "<<pi<<endl;
cout<<"PI : "<<setprecision(1)<<pi<<endl;
cout<<"PI : "<<setprecision(6)<<pi<<endl;
cout<<"-------------------------------------------\n";
cout<<"Chaînes, Alignement et Padding\n";
char texte[50];
strcpy(texte,"Bonjour tout le monde");
cout<<texte<<endl;
cout.setf(ios::left,ios::adjustfield);
cout.width(50);
cout.fill('-');
cout<<texte<<endl;
cout.width(40);
cout.fill('*');
cout<<texte;
}
Programmation Orientée Objet en Langage C++
64
M.E
Exécution
3. Saisir au clavier avec ‘cin’
Dans l’exemple suivant :
char chaine[10];
cout<<"saisir une chaine : ";
cin.width(sizeof(chaine)); cin>>chaine;
La fonction ‘width’ fixe le nombre de caractères à affecter à la variable ‘chaine’ sans
débordement.
La classe istream contient la fonction membre getline qui permet de saisir des chaînes
de caractères comprenant des espaces non acceptés par l’opérateur >>.
Le prototype de getline est :
istream &getline(char* chaine, int nombre, char fin= ’\n’);
Avec :
chaine
: chaîne à saisir.
nombre
: nombre maximum de caractères de la chaîne.
fin
: caractère de fin de saisie (par défaut ‘\n’).
Programmation Orientée Objet en Langage C++
65
M.E
Exemple
class voiture
{
char marque[20];
char modele[20];
char prix[20];
public:
voiture(char *ma="",char *mo="",char *pr="")
{
strcpy(marque,ma);
strcpy(modele,mo);
strcpy(prix,pr);
}
void saisie();
void affiche();
};
//--------------------------------------------------------void voiture::saisie()
{
cout<<"Marque : "; cin.getline(marque,sizeof(marque));
cout<<"Modele : "; cin.getline(modele,sizeof(modele));
cout<<"Prix : ";
cin.getline(prix,sizeof(prix));
}
//--------------------------------------------------------void voiture::affiche()
{
cout.setf(ios::left,ios::adjustfield);
cout<<"Marque : "; cout.width(15); cout<<marque;
cout<<"Modele : "; cout.width(15); cout<<modele;
cout<<"Prix : ";
cout.width(15); cout<<prix; cout<<endl;
}
//-----------------------------------------------------------main()
{
voiture v1;
v1.saisie();
cout<<"\nAffichage \n";
v1.affiche();
cout<<endl;
voiture v2;
v2.saisie();
cout<<"\nAffichage \n";
v2.affiche();
}
Programmation Orientée Objet en Langage C++
66
M.E
Exécution
4. Redéfinir les opérateurs de flux
Pour redéfinir les opérateurs de flux, on doit respecter une syntaxe telle qu’elle est
définie dans l’exemple suivant :
Exemple
class demo
{
public :
friend ostream& operator<<(osream&,demo&);
friend istream& operator>>(isream&,demo&);
};
Ostream & operator<<(osream& …,demo& …)
{ … }
Istream & operator>>(isream& …,demo& …)
{ … }
Commentaire
-
-
Les deux opérateurs << et >> sont surdéfinis en tant que fonctions amies de la
classe ‘demo’, de cette manière, ils pourront accéder à tous ses membres.
Dès que l’opérateur << sera utilisé avec comme opérande de gauche un objet de
type ‘ostream’ (ou dérivé) et comme opérande de droite, un objet de type ‘demo’
ce sont les instructions de la fonction operator << qui seront exécutées.
L’opérateur >> est utilisé d’une façon analogue à celle de l’opérateur <<.
Les opérateurs << et >> peuvent être surdéfinis pour des objets dynamiques.
Programmation Orientée Objet en Langage C++
67
M.E
Exemple
class voiture
{
char marque[20];
char modele[20];
char prix[20];
public:
voiture(char *ma="",char *mo="",char *pr="")
{
strcpy(marque,ma);
strcpy(modele,mo);
strcpy(prix,pr);
}
friend ostream& operator<<(ostream&,voiture&);
friend istream& operator>>(istream&,voiture&);
};
//-------------------------------------------------------ostream & operator<<(ostream& out,voiture& v)
{
out.setf(ios::left,ios::adjustfield);
out<<"Marque : "<<v.marque;
out<<"\tModèle : "<<v.modele;
out<<"\tPrix : "<<v.prix<<endl;
return out;
}
//-------------------------------------------------------istream & operator>>(istream& in,voiture& v)
{
cout<<"Marque : "; in.getline(v.marque,sizeof(v.marque));
cout<<"Modele : "; in.getline(v.modele,sizeof(v.modele));
cout<<"Prix : ";
in.getline(v.prix,sizeof(v.prix));
return in;
}
//----------------------------------------------------------main()
{
voiture v1("Mercedes","CLK 500","19900DH");
cout<<v1;
cout<<"Saisir la marque, le modele et le prix de voiture\n";
cin>>v1;
cout<<"\nAffichage"<<endl;
cout<<v1;
voiture v2;
cout<<"Saisir la marque, le modele et le prix de voiture\n";
cin>>v2;
cout<<"\nAffichage"<<endl;
cout<<v2;
cout<<v1<<v2;
}
Exécution
Programmation Orientée Objet en Langage C++
68
M.E
Remarque
Dans le cas d’un pointeur vers la classe voiture, il faut redéfinir les opérateurs << et >>
comme par exemple :
ostream& operator<<(ostream& out,voiture *v)
{
out.setf(ios::left,ios::adjustfield);
out<<"\tMarque : "<<v->marque;
out<<"\tModèle : "<<v->modele;
out<<"\tPrix : "<<v-> prix<<endl;
return out;
}
5. Lire à partir d’un fichier ou écrire dans un fichier
Il suffit de créer un objet de type ofstream pour écrire dans un fichier et un objet de
type ifstream pour lire un fichier. Ces deux classes sont déclarées dans le fichier
‘fstream.h’ et elles dérivent respectivement des classes ostream et istream
Exemple 1
Extrait d’un programme qui permet d’écrire dans un fichier.
ofstream fs("c:\\demo.txt");
if(!fs)
{
cout<<"Erreur d'écriture dans ce fichier ! \a\a";
return 1;
}
fs<<"valeur de la donnée: "; fs<<17.12; fs<<"Fin";
fs.close(); …
Commentaire
Programmation Orientée Objet en Langage C++
69
M.E
-
Un objet ‘fs’ de type ostream est créé pour accéder en écriture au fichier
“c:\\demo.txt“.
En cas de succès de l’ouverture du fichier ‘demo.txt’, les données sont écrites vers
le flux de fichier ‘fs’.
Exemple 2
Extrait d’un programme permettant de lire un fichier
ifstream fe("c:\\demo.txt");
if(!fe)
{
cout<<"Erreurs d'ouverture ! \a\a";
return 1;
}
char texte1[30];
double x;
char texte2[30];
fe>>texte1; fe>>x; fe>>texte2;
cout<<texte1<<x<<texte2;
fe.close();
…
Commentaire
-
Un objet ‘fe’ de type ‘ifstream’ est créé pour accéder en lecture au fichier
‘demo.txt’.
Le flux ‘fe’ est utilisé pour récupérer les données qui sont affichées ensuite sur
l’écran.
Remarque
La fonction close, qui permet de fermer un fichier, est appelée automatiquement par le
destructeur des classes ofstream et ifstream.
Exercice
Ecrire un programme permettant de rassembler les deux extraits.
Programmation Orientée Objet en Langage C++
70
M.E
Le programme :
main()
{
// Ecriture dans le fichier
ofstream fs("c:\\Exemple\\demo.txt");
if(!fs)
{
cout<<"Erreur d'écriture dans le fichier ! \a\a";
getch();
return 1;
}
else
{ cout<<"Fichier cree...\n"; }
fs<<"valeur-de-la-donnée-:*"<<endl;
fs<<17.12<<endl;
fs<<"*Fin";
fs.close();
// Lecture du fichier
ifstream fe("c:\\Exemple\\demo.txt");
if(!fe)
{
cout<<"Erreur de lecture du fichier ! \a\a";
getch();
return 1;
}
else
{ cout<<"Fichier ouvert...\n"<<endl; }
char texte1[30];
char texte2[30];
double x;
fe>>texte1;
fe>>x;
fe>>texte2;
cout<<texte1<<x<<texte2;
fe.close();
getch();
}
Exécution
Programmation Orientée Objet en Langage C++
71
M.E
Chapitre 10 : Les templates
Les templates (appelées aussi modèles ou patrons) représentent une technique
favorisant la réutilisation et la spécialisation des fonctions et des classes.
Les templates utilisent un type paramètré (ou fictif) qui représente le type de donnée
qui sera choisi (ou instancié) à l’utilisation du modèle.
1. Les fonctions templates
Une fonction template permet de définir une fonction qui réalisera le même traitement
pour des types de données différents (type de donnée paramétré qui sera connu au
moment de l’appel de la fonction).
Syntaxe
template<arguments du template>
type fonction(arguments)
{
…………………
}
Ou
template<arguments du template> type
{
…………………
}
fonction(arguments)
Description
-
‘arguments du template’ : s’écrit ‘class type1, type2, …’ où type1, type2...
représentent les types paramétrés (par convention on prend la lettre T, U …).
La fonction déclarée peut utiliser ensuite le ou les types fictifs.
Exemple
Les fonctions surchargées suivantes :
void affiche(short v)
{ cout<<"Valeur : "<<v<<endl; }
//---------------------------void affiche (float v)
{ cout <<"Valeur : "<<v<<endl; }
//-------------------------------void affiche (double v)
{ cout <<"Valeur : "<<v<<endl; }
peuvent être remplacées par la fonction modèle suivante :
template <class T>
void affiche (T v)
{ cout <<"Valeur : "<<v<<endl; }
Programmation Orientée Objet en Langage C++
72
M.E
Et on peut faire des appels tels que :
main()
{
short
n=15;
float
x=3.7;
double
y=5.14;
affiche(n);
affiche(34);
affiche(x);
affiche(5.8);
affiche(y);
affiche(‘A’);
affiche("BONJOUR");
getch() ;
}
Exécution
Remarque
Une fonction template peut employer plusieurs arguments :
template <class T,class U>
void affiche(T v1,U v2)
{
cout <<"Valeur 1 : "<<v1<<endl;
cout <<"Valeur 2 : "<<v2<<endl;
}
Exercice
Définir une fonction template ou modèle appelée ‘max’ dont l’objectif est de renvoyer le
plus grand des deux éléments passés en argument.
2. Les classes templates
Syntaxe
template <arguments du template>
class nom_de_la_classe
{
………………;
………………;
};
Programmation Orientée Objet en Langage C++
73
M.E
Description
C++ impose pour définir le corps des fonctions membres d’employer la syntaxe
suivante :
template <arguments du template>
type nom_de_la_classe<arguments>::fonction(arguments)
{
…………………
…………
}
- Une classe modèle ou template peut également contenir des fonctions membres qui
n’utilisent pas les types paramétrés. Cependant, même dans ce cas, le corps de la
fonction doit respecter la contrainte liée au nom complet de la fonction membre.
Exercice 1
Reprendre l’exemple de la classe ‘tableau’ et écrire un programme global à partir des
déclarations suivantes :
template <class T>
class tableau
{
int
ne;
T
*p;
public :
tableau(int n){ p=new T[ne=n];}
T & operator[](int n){ return p[n]; }
~tableau(){delete []p;}
};
//--------------------------------------main()
{
tableau<int> t1(5);
for(int i=0;i<5;i++) t1[i]=i+1;
for(int i=0;i<5;i++) cout<<t1[i]<<"\t"; cout<<endl;
//----------------------------------tableau<float> t2(7);
for(int i=0;i<7;i++)t2[i]=i*2.3;
for(int i=0;i<7;i++)cout<<t2[i]<<"\t"; cout<<endl;
//----------------------------------------------------tableau<char> t3(8);
for(int i=0;i<8;i++)t3[i]='A'+i;
for(int i=0;i<8;i++)cout<<t3[i]<<"\t"; cout<<endl;
getch();
}
Programmation Orientée Objet en Langage C++
74
M.E
Exécution
Exercice 2
Redéfinir la classe ‘point’ pour des coordonnées de type paramétré (short, int ou long) et
donner des exemples d’instanciation de points.
Programme
template <class U>
class point
{
U x;
U y;
public :
point(U a,U b){x=a; y=b;}
void affiche(){cout<<"X="<<x<<" - Y="<<y<<endl;}
};
//----------------------------------------------------------main ()
{
point<int>
p1(10,20);
p1.affiche();
point<double> p2(23.45,20.76);
p2.affiche();
point<float> p3(1.98,2.907);
p3.affiche();
point<char>
p4('F','K');
p4.affiche();
}
Exécution
Programmation Orientée Objet en Langage C++
75
M.E
Chapitre 11 : Gestion des exceptions
De nombreux problèmes peuvent survenir pendant l’exécution d’un programme,
l’insuffisance de mémoire, la perte d’un fichier, la saisie non valide d’une valeur sont
des exemples d’erreurs. Le rôle d’un programme consiste à prévoir ces erreurs, à en
informer les utilisateurs et éventuellement à mettre en œuvre des solutions de reprise et
de correction de ces erreurs d’exécution.
C++ propose, à part l’utilisation de la valeur de retour des fonctions, une nouvelle
solution pour intercepter les erreurs : le mécanisme des exceptions.
1. Gestion des erreurs en utilisant les valeurs de retour des fonctions
int
{
positive(int v)
if(v<0) return 0;
cout<<«Valeur positive \n»;
return 1 ;
}
//--------------------------int inf(int v,int max)
{
if(v>max) return 0;
cout<<"Valeur inférieure à : "<<max<<endl;
return 1;
}
//----------------------------------------------------------int sup(int v,int min)
{
if(v<min) return 0;
cout<<"Valeur supérieure à : "<<min<<endl;
return 1;
}
//-----------------------------------------------------------int main()
{
int minimum=10;
int maximum=100;
int n,retour;
cout<<"Saisir une valeur entière : "; cin>>n;
retour=positive(n);
if(retour==1)
{
retour=inf(n,maximum);
if(retour==1)
{
retour=sup(n,minimum);
if(retour==1)
{
cout<<"Valeur correcte !";
return 1;
}
else
{
Programmation Orientée Objet en Langage C++
76
M.E
cout<<"Valeur inférieure à : "<<minimum;
return 0;
}
}
else
{
cout<<"Valeur supérieure à : "<<maximum<<endl;
return 0;
}
}
else
{
cout<<"Valeur négative !\n";
return 0;
}
}
Remarque


Dans ce programme le contrôle d’erreurs est alourdie par les ‘if’ imbriqués.
Un constructeur ne peut pas renseigner sur sa valeur de retour, qui n’en possède
pas, pour indiquer qu’une erreur s’est produite.
2. Mise en œuvre des exceptions
Pour mettre en œuvre des exceptions sans se baser sur les valeurs de retour des
fonctions, on doit :
-
Définir une classe d’exception.
Lancer l’exception (throw).
Intercepter l’exception.
2.1. Définir une classe d’exception
Une classe d’exception correspond à une classe C++ qui peut fournir des informations
sur une erreur.
Exemple
class erreur
{
………………
};
Remarque
On peut ajouter à la classe ‘erreur’ autant de données et de fonctions membres.
Programmation Orientée Objet en Langage C++
77
M.E
2.2. Lancer l’exception
Toute fonction qui souhaite lancer une exception doit utiliser un nouvel opérateur du
langage C++ throw, suivi par un objet créé à partir d’une classe d’exception, cet
opérateur permet de quitter la fonction qui l’utilise et d’informer la fonction appelante
qu’une exception à été générée.
Exemple
void positive(int v)
{
if(v<0)
{
erreur er;
throw er;
}
cout<<"Valeur positive \n";
}
Remarque
Si ‘v’ est < à 0 la fonction construit un objet statique de la classe d’exception ‘erreur’ et
envoie cet objet avec l’opérateur throw qui ressemble à return.
La fonction précédente peut être simplifiée :
void positive(int v)
{
if(v<0) throw erreur();
cout<<"Valeur positive \n ";
}
Commentaire
Il y a création d’un objet de type ‘erreur’ sans nom, cette solution n’est intéressante que
si on n’a pas besoin d’appeler des fonctions membres de la classe d’exception.
Remarque
Toute fonction susceptible d’envoyer un ou plusieurs exceptions peut l’indiquer dans sa
déclaration juste après la liste de ces arguments.
Exemple
void contrôle(int v)
{
……………
………………………
}
throw (erreur,invalid)
Programmation Orientée Objet en Langage C++
78
M.E
2.3. Intercepter l’exception
Pour intercepter une exception, C++ fournit une syntaxe basée sur l’utilisation des blocs
try et d’un ou plusieurs blocs catch :
try
{
//Appels de fonctions pouvant générer des erreurs
}
catch (classe d’exception)
{
//Ce bloc s’exécute pour une exception de type
//‘classe d’exception’
}
catch(…)
{
//Ce bloc s’exécute pour toutes les exceptions
//en dehors de la classe d’exception
}
Description
Si une exception est envoyée par une de ces fonctions appelées dans le bloc ‘try’, le
mécanisme d’exception entraînera les étapes suivantes :
-
Tous les objets créés dans le bloc ‘try’ sont détruits’
Le programme sort du bloc ‘try’ après la fonction qui a entraîné l’exception et
n’exécute pas les instructions situées après cette fonction.
Le C++ exécute dans l’ordre soit le bloc ‘catch’ correspondant à l’exception
interceptée si elle existe, soit le bloc ‘catch(…)’ si aucune de ces conditions n’est
remplie, cela entraîne la fin de l’exécution du programme, si un des blocs ‘catch’ a
été utilisé, le programme continu à exécuter les instructions situées après ce bloc
s’il y en a.
Remarque
Dans un bloc ‘catch’ on peut par exemple :
-
arrêter le programme avec ou sans message utilisateur.
corriger le problème avec ou sans message utilisateur
uniquement informer l’utilisateur.
Programmation Orientée Objet en Langage C++
79
M.E
Exemple
1.
class
erreur { };
2.
void positive(int v)
{
if(v<0) throw erreur();
cout<<"Valeur positive \n";
}
void inf(int v,int max)
{
if(v>max) throw erreur();
cout<<"Valeur inférieure à : "<<max<<endl;
}
void sup(int v,int min)
{
if(v<min) throw erreur();
cout<<"Valeur supérieure à : "<<min<<endl;
}
//-------------------------------------------------------main()
{
int minimum=10; int maximum=100;
3. try
{
int n;
cout<<"Saisir une valeur entière : "; cin>>n;
positive(n);
inf(n,maximum);
sup(n,minimum);
cout<<"Valeur correcte !\n";
}
catch(erreur er)
{
cout<<"valeur incorrecte! \n";
}
catch(...)
{
cout<<"Erreur inconnue !\n";
}
}
Exercice
Toutes les fonctions de l’exemple précédent utilisent la même classe d’exception
‘erreur’. Proposer plusieurs classes d’exception chacune responsable de l’affichage d’un
message d’erreur.
Programmation Orientée Objet en Langage C++
80
M.E
Solution
class erreur_positive
{ };
class erreur_inf
{ };
class erreur_sup
{ };
void positive(int v)
{
if(v<0) throw erreur_positive();
cout<<"Valeur positive \n";
}
void inf(int v,int max)
{
if(v>max) throw erreur_inf();
cout<<"Valeur inférieure à : "<<max<<endl;
}
void sup(int v,int min)
{
if(v<min) throw erreur_sup();
cout<<"Valeur supérieure à : "<<min<<endl;
}
main()
{
int minimum=10; int maximum=100;
try
{
int n;
cout<<"Saisir une valeur entière : "; cin>>n;
positive(n);
inf(n,maximum);
sup(n,minimum);
cout<<"Valeur correcte !\n";
}
catch(erreur_positive er)
{
cout<<"Erreur ! valeur negative ! \n";
}
catch(erreur_inf er)
{
cout<<"Erreur ! valeur superieure A : "<<maximum<<endl;
}
catch(erreur_sup er)
{
cout<<"Erreur ! valeur inferieure A : "<<minimum<<endl;
}
catch(...)
{
cout<<"Erreur inconnue !\n";
}
}
Programmation Orientée Objet en Langage C++
81
M.E
Exécution
Prolongement
Afficher les messages d’erreurs à l’aide des fonctions membres des classes d’exception.
class erreur_positive
{
public :
void affiche(){cout<<"Erreur ! valeur negative ! \n";}
};
class erreur_inf
{
int maxi;
public:
erreur_inf(int ma){maxi=ma;}
void affiche()
{cout<<"Erreur ! valeur superieure A : "<<maxi<<endl;}
};
class erreur_sup
{
int mini;
public:
erreur_sup(int mi){mini=mi;}
void affiche()
{cout<<"Erreur ! valeur inferieure A : "<<mini<<endl;}
};
void positive(int v)
{
if(v<0) { erreur_positive er; throw er;}
cout<<"Valeur positive \n";
}
Programmation Orientée Objet en Langage C++
82
M.E
void inf(int v,int max)
{
if(v>max) { erreur_inf er(max); throw er;}
cout<<"Valeur inférieure à : "<<max<<endl;
}
void sup(int v,int min)
{
if(v<min) { erreur_sup er(min); throw er;}
cout<<"Valeur supérieure à : "<<min<<endl;
}
//-------------------------------------------------------main()
{
int minimum=10; int maximum=100;
try
{
int n;
cout<<"Saisir une valeur entière : "; cin>>n;
positive(n);
inf(n,maximum);
sup(n,minimum);
cout<<"Valeur correcte !\n";
}
catch(erreur_positive e)
{
e.affiche();
}
catch(erreur_inf e)
{
e.affiche();
}
catch(erreur_sup e)
{
e.affiche();
}
catch(...)
{
cout<<"Erreur inconnue !\n";
}
}
Programmation Orientée Objet en Langage C++
83
M.E
Exécution
Remarque
Les exceptions sont symbolisées par des classes dans lesquelles on peut intégrer les
notions d'héritage et de polymorphisme.
3. Hiérarchie des classes d’exception
Reprendre le programme précédent en tenant compte de l’héritage et du
polymorphisme.
Programme
class erreur
{
public:
virtual void affiche(){cout<<"Erreur !";}
};
class erreur_positive:public erreur
{
public :
void affiche(){cout<<"Erreur ! valeur negative ! \n";}
};
class erreur_inf:public erreur
{
int maxi;
public:
erreur_inf(int ma){maxi=ma;}
void affiche()
{cout<<"Erreur ! valeur superieure A : "<<maxi<<endl;}
};
Programmation Orientée Objet en Langage C++
84
M.E
class erreur_sup:public erreur
{
int mini;
public:
erreur_sup(int mi){mini=mi;}
void affiche()
{cout<<"Erreur ! valeur inferieure A : "<<mini<<endl;}
};
//----------------------------------------------------------void positive(int v)
{
if(v<0)
{ erreur_positive *er; er=new erreur_positive; throw er;}
cout<<"Valeur positive \n";
}
void inf(int v,int max)
{
if(v>max)
{ erreur_inf *er; er=new erreur_inf(max); throw er;}
cout<<"Valeur inférieure à : "<<max<<endl;
}
void sup(int v,int min)
{
if(v<min)
{ erreur_sup *er; er=new erreur_sup(min); throw er;}
cout<<"Valeur supérieure à : "<<min<<endl;
}
//-------------------------------------------------------main()
{
int minimum=10; int maximum=100;
try
{
int n;
cout<<"Saisir une valeur entière : "; cin>>n;
positive(n);
inf(n,maximum);
sup(n,minimum);
cout<<"Valeur correcte !\n";
}
catch(erreur *e)
{
e->affiche(); delete e ;
}
catch(...)
{
cout<<"Erreur inconnue !\n";
}
}
Programmation Orientée Objet en Langage C++
85
M.E
Exécution
Programmation Orientée Objet en Langage C++
86
M.E
Références bibliographiques
- La bible du programmeur C/C++, Kris Jamsa et Lars Klander, Editions G. Reynald, 1999.
- Comment programmer en C++, Deitel et Deitel, Editions G. Reynald, 2001.
- Apprendre le C++, C. Delannoy, Editions Eyrolles, 2007.
- Exercices en langage C++, C. Delannoy, Editions Eyrolles, 2007.
- C++ pour les programmeurs C, C. Delannoy, Editions Eyrolles, 2007.
Programmation Orientée Objet en Langage C++
87
M.E
Téléchargement