Vous êtes sur la page 1sur 19

Polymorphisme

I - Redéfinition des fonctions


 I.1 Le polymorphisme
 Avec l’encapsulation et l’héritage, le polymorphisme
constitue la troisième et la plus importante
caractéristique des langages orienté Objet
 Le polymorphisme s’applique aux fonctions
membres des classes
 Il utilise une technique permettant de définir un
pointeur vers une classe de base pour stocker
l’adresse d’objets dérivés lors de l’utilisation de
l’héritage

1
Exemple 1 : Utilisation d’un pointeur vers la classe de base
#include <iostream.h> MicroOrdinateur:: MicroOrdinateur(string r, string m, string*p, int d);
#include <string.h> : Materiel(r, m)
{
class Materiel Processeur = p;
{ protected: Disque = d;
string Reference; }
string Marque;
public : void MicroOrdinateur::Affiche()
Materiel(string r, string m); {
void Affiche( ); cout<< " Ref : " <<Reference;
}; cout<< " Marque : " <<Marque;
cout<< " Processeur : " <<Processeur;
class MicroOrdinateur : public Materiel cout<< " Disque : " <<Disque;
{ cout<< " \n ";
protected: }
string Processeur;
int Disque; int main()
{
public : Materiel *pMat;
MicroOrdinateur(string r, string m, string p, int d); pMat = new Materiel (" X01 “,
void affiche( ); " XX “);
}; pMat->Affiche();
delete pMat;
Materiel::Materiel(string r, string m)
{ pMat = new MicroOrdinateur
Reference= r; (" X16 “, " PH “, “DX4-100 “, 200);
Marque = m ; pMat->Affiche();
} delete pMat;

Materiel::Affiche() return 0;
{ }
Ref : X01 Marque : XX RESULTAT
cout<< " Ref : " <<Reference;
cout<< " Marque : " <<Marque; Ref : X16 Marque : PH INVALIDE
cout<< " \n ";
}
2
 Pour résoudre ce type de problème :
 Il faut indiquer au compilateur que la fonction Affiche() est
une fonction polymorphe
 C’est-à-dire ce que l’on nomme en C++ , une fonction
virtuelle

 Une fonction polymorphe(ou virtuelle) est une


méthode qui est appelée en fonction du type d’objet
et non pas en fonction du type de pointeur utilisé
 Déclaration d’une fonction polymorphe :
 Précéder son prototype par le mot clé virtual

 Lorsqu'une classe comporte une fonction


virtuelle, elle doit rendre son destructeur virtuel.

3
Exemple 2 : Définition de fonctions virtuelles
#include <iostream.h> MicroOrdinateur:: MicroOrdinateur(string*r, string*m, string* p, int d);
#include <string.h> : Materiel(r, m)
{
class Materiel strcpy(Processeur, p);
{ protected: Disque = d;
stringReference[20+1]; }
stringMarque[20+1];
public : void MicroOrdinateur::Affiche()
Materiel(string* r, string *m); {
virtual void Affiche( ); cout<< " Ref : " <<Reference;
virtual ~Materiel(){} cout<< " Marque : " <<Marque;
}; cout<< " Processeur : " <<Processeur;
cout<< " Disque : " <<Disque;
class MicroOrdinateur : public Materiel cout<< " \n ";
{ }
protected:
stringProcesseur[20+1]; int main()
int Disque; {
Materiel *pMat;
public : pMat = new Materiel (" X01 “,
MicroOrdinateur(string*r, string*m, string* p, int d); " XX “);
virtual void Affiche( ); pMat->Affiche();
virtual ~MicroOrdimateur(){} delete pMat;
};
pMat = new MicroOrdinateur
Materiel::Materiel(string* r, string* m) (" X16 “, " PH “, “DX4-100 “, 200);
{ pMat->Affiche();
strcpy(Reference, r); delete pMat;
strcpy(Marque, m);
} return 0;
}
Ref : X01 Marque : XX
Materiel::Affiche()
{ Ref : X16 Marque : PH Processeur : DX4-100 Disque : 200
cout<< " Ref : " <<Reference;
cout<< " Marque : " <<Marque; cout<< " \n « ;}
4
• Lorsqu'une méthode virtuelle est appelée, la
méthode à exécuter est choisie en fonction du
type de l'objet.

• L'appel n'est donc résolu qu'à l'exécution, le


type de l'objet ne peut pas être connu à la
compilation.

• Le mot clé virtual, placé devant le prototype de


la fonction, indique au compilateur que la
fonction est redéfinie dans une classe dérivée.
5
 Remarque :
 Seule la fonction de la classe de base doit être déclarer
virtuelle
 Conseil : 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

 Grâce au polymorphisme, deux classes peuvent


réagir différemment au même appel de méthode

 On peut donc constituer des hiérarchies de classe


qui partagent une trame commune et qui se
différencient les unes des autres

6
Exemple 3 : Hiérarchie de classes et fonctions virtuelles
#include <iostream.h> Materiel::Materiel(string r, string m)
#include <string.h> Referencee = r;
Marque = m;
class Materiel }
{ protected:
string Reference; Materiel::Affiche()
stringr Marque; {
public : cout<< " Ref : " <<Reference;
Materiel(string r, string m); cout<< " Marque : " <<Marque;
virtual void Affiche( ); cout<< " \n ";
virtual ~Materiel(){} }
};
MicroOrdinateur:: MicroOrdinateur(string r, string m, string p, int d);
class MicroOrdinateur : public Materiel : Materiel(r, m)
{ { Processeur= p;
protected: Disque = d;
String Processeur; }
int Disque;
void MicroOrdinateur::Affiche()
public : {
MicroOrdinateur( string r, string m, string p, int d); Materiel ::Affiche() ;
virtual void affiche( ); cout<< " Processeur : " <<Processeur;
virtual ~MicroOrdimateur(){} cout<< " Disque : " <<Disque;
}; cout<< " \n ";
}
class Imprimante : public Materiel
{ Imprimante:: Imprimante( string r, string m, string t);
protected: : Materiel(r, m)
string type; {
public : Type= t;
Imprimante(string r, string m, string t); }
virtual void affiche( );
virtual ~Imprimantel(){}
};
7
void Imprimante::Affiche() Choisissez un type de
{ materiel
Materiel ::Affiche() ; (1- Micro, 2 – Imprimante, 0-
cout<< " Type : " <<Type; Quitte) : 1
cout<< " \n "; Ref : X16 Marque : PH Processeur : DX4-100 Disque :
} 200
int main()
{ Choisissez un type de
Materiel *pMat = NULL; materiel
int TypeObjet = 0 ; (1- Micro, 2 – Imprimante, 0-
Quitte) : 2
while(1)
{ Ref : X18 Marque : PH Type : Laser
cout<< “\nChoisissez un type de materiel\n “;
cout<< “(1- Micro, 2 – Imprimante, 0- Quitte) : “; Choisissez un type de
cin>>TypeObjet; materiel
switch(TypeObjet) (1- Micro, 2 – Imprimante, 0-
{ Quitte) : 3
case 1 : pmat = new MicroOrdinateur(“X16 “, “PH”, “DX4-100 “, 200);
break; Choix invalide

case 2 : pmat = new Imprimante(“X18 “, “PH”, “Laser“);


Choisissez un type de
break; materiel
(1- Micro, 2 – Imprimante, 0-
case 0 : if ( pMat !=NULL) delete pMat; Quitte) : 0
return 0;

default : cout << “\nChoix invalide\a\n “;


continue;
}
cout << “\n”;
pMat->Affiche();
delete pMat;
pMat = NULL;
}
}
8
 Cette exemple met en évidence la définition multiple de la
méthode Affiche()
 Chaque classes implémente cette méthode de manière à
effectuer un traitement particulier.
 Ces fonctions membres affichent le contenu des données
associées à chaque type d’objet

 Lorsque vous appelez une fonction virtuelle pour un


objet, le langage C++ cherche cette méthode dans la
classe correspondante. Si cette fonction n’existe pas
dans la classe concernée, C++ remonte la hiérarchie
des classes jusqu’à ce qu’il trouve la fonction
appelé.

9
 I.2 Le polymorphisme , pour quoi faire ?
 On utilise le polymorphisme pour modifier le
comportement d’une classe de base ou la
spécialiser.
 Vous pouvez redéfinir une fonction virtuelle dans
une classe dérivée pour trois raisons :
 Pour la substituer au traitement standard :
 Pour compléter le traitement standard :
 Pour annuler le traitement standard :

10
 I.3 Généralisation de l’appel des fonctions polymorphes ?
 Jusqu’à maintenant , nous avons appelé directement
les fonction polymorphes en désignant l’objet traité.
 Que se passe-t-il lorsque cette méthode est utilisée
par une autre méthode de la classe?

11
Exemple 4 : Généralisation des fonctions virtuelles
#include <iostream.h> Materiel::AfficheTitre()
{
#include <string.h>
cout<< " INFORMATION (DEBUT) \n ";
class Materiel Affiche( );
{ protected: cout<< " INFORMATION (FIN) \n ";
string Reference; }
string Marque]; MicroOrdinateur:: MicroOrdinateur(string r, string m, string p, int d);
public : : Materiel(r, m)
Materiel(string r, string m); {
virtual void Affiche( ); Processeur = p;
void AfficheTitre(); Disque = d;
}; }
void MicroOrdinateur::Affiche()
class MicroOrdinateur : public Materiel {
{ Materiel ::Affiche()
protected: cout<< " Processeur : " <<Processeur;
string Processeur[ cout<< " Disque : " <<Disque;
int Disque; cout<< " \n ";
}
public : int main()
MicroOrdinateur(string r, string m, string p, int d); {
virtual void affiche( ); Matiel*pMic = NULL;
}; pMic = new MicroOrdinateur
(" X16 “, " PH “, “DX4-100 “, 200);
Materiel::Materiel(string r, string m) pMic->AfficheTitre();
{ delete pMic;
Reference=r;
Marque=m; return 0;
} }

Materiel::Affiche()
INFORMATION (DEBUT)
{
cout<< " Ref : " <<Reference; La Reference : x16 La marque : ph Le processeur : dx4 Le disque : 200
cout<< " Marque : " <<Marque;
INFORMATION (DEBUT)
cout<< " \n ";
}
12
L’operateur typeid
Il est possible lors de l’execution de connaitre le
type d’un objet designé par un pointeur
(identification des types à l’execution).
Il existe un operateur à un opérande nommé typeid
fournissant en résultat un objet de type
prédéfini typeinfo
#include <typeinfo>
Cette classe contient une fonction name(), qui
retour une chaine de caractère représentant le
nom du type
compte x;
cout<<typeid(x).name(); //classe compte
13
Opérateur de transtypage
Ce sont des opérateurs de changement de type
(transtypage ou conversion de type)
Ils sont utilisé dans le contexte du polymorphisme
pour convertir un type objet d’une classe de
base en une classe dérivée.
C++ propose 4 operateurs de transtypage
- static_cast
- dymanique_cast
- const_cast
- reinterpret_cast

14
• Exemple : Compte – C Courant- C Epargne - Banque
class Compte class CompteEpargne : public Compte
{ protected: { private:
long RIB; double interet;
double solde; public:
public: CompteEpargne(double interet=0,long num=0,double
Compte(long num=0 ,double solde=0); solde=0) :Compte(num,solde) {this->interet=interet;}
virtual ~Compte(); ~CompteEpargne(){}
void ajouter(double); double get_solde_interet()
double get_solde(){return solde;} { return (solde+((solde*interet)/100)); }
long get_RIB(){return RIB;} bool retirer(double );
virtual bool retirer(double); void ajouter(double );
virtual void afficher(); void afficher();
virtual void saisir_compte(long num,double solde); void saisir_compte(long num,double solde,double interet);
}; };
class CompteCourant : public Compte
{ class Banque1
private: {
//aucun attribue à ajouter private:
Partie
public:
CompteCourant(long num=0,double solde=0 )
vector <Compte *> tab; Dymanique
:Compte(num,solde) {} public:
~CompteCourant(){} Banque1();
bool retirer(double ); bool rechercher(long );
void ajouter(double ); void afficher();
void ajouter(Compte);
void saisir(long num,double solde);
void supprimer(long );
}; ~Banque1();
Banque1(const Banque1& );
Banque1 & operator=(const Banque1&);
};
15
Transtypage - Constructeur par recopie
// Classe banque

Banque1::Banque1 (const Banque1& A)


{
Compte *p;
for (unsigned int i=0;i<A.tab.size();i++)
{
if (typeid(*A.tab[i])==typeid(Compte)) {
p=new Compte(*A.tab[i]);
}
else if (typeid(*A.tab[i])==typeid(CompteEpargne)) {
p=new CompteEpargne(static_cast<const CompteEpargne&>(*A.tab[i]));
}
else if (typeid(*A.tab[i])==typeid(CompteCourant)) {
p=new CompteCourant(static_cast<const CompteCourant&>(*A.tab[i]));
}
tab.push_back(p);
}
}
}

16
Transtypage - Optimisation de la foncion void Banque1::ajouter(Compte & C)
class Banque1
{
private: ajouter {
Compte *p;
vector <Compte *> tab; if (typeid(C)==typeid(Compte))
{
public:
Banque1(); p=new Compte(C);
int rechercher(long ); }
void afficher(); else if (typeid(C)==typeid(CompteEpargne))
//void ajouter(Compte); {
// void ajouter(CompteEpargne);
p=new CompteEpargne(static_cast<const
//void ajouter(CompteCourant);
CompteEpargne&>(C));
void ajouter(Compte & ); //avec la & chaque objet sera consideré selon son type }
// si on enleve & tous les objet sont considérés comme des comptes else if (typeid(C)==typeid(CompteCourant))
// cette methode prend en consieration les objets statique et dynamique
{
void supprimer(long );
~Banque1(); p=new CompteCourant(static_cast<const
Banque1(const Banque1& ); CompteCourant&>(C));
}
}; tab.push_back(p);
}
void Banque1::ajouter(Compte C)
{
Compte *p;
if (typeid(C)==typeid(Compte))
{
p=new Compte(C);
}
else if (typeid(C)==typeid(CompteEpargne))
{
p=new CompteEpargne(static_cast<const
CompteEpargne&>(C));
}
else if (typeid(C)==typeid(CompteCourant))
{
p=new CompteCourant(static_cast<const
CompteCourant&>(C));
}
tab.push_back(p);
}
17
Classes Abstraites
• Une classe contenant au moins une méthode
virtuelle pure est dite abstraite
• On ne doit pas déclarer des objets d’une
classe abstraite
• Une classe abstraite est utilisée uniquement
par héritage

18
Exemple 1 : Figure, Triangle, Ellipse …

19