--> mécanisme de surcharge.
--> mécanisme de liason ``dynamique''.
| Polymorphisme statique |
| compte c ; rectangle p ; |
| c.afficher() ; p.afficher() ; |
| class figure { |
| public : |
| void afficher(const couleur fond) const ; |
| void afficher(const string message) const ; |
| void afficher(void) const ; |
| figure& operator = (const figure&) ; |
| // ... |
| } ; |
| Polymorphisme dynamique (1) |
--> reculer certaines décisions le plus longtemps
possible.
--> la liaison dynamique est une solution
possible en définissant des services dans des classes de base
et en les implémentant dans les classes dérivées.
| Polymorphisme dynamique (2) |

| figure *f; |
| // ... |
| switch(...) { |
| case ... : |
| f = new rectangle; break; |
| case ... : |
| f = new carre; break; |
| case ... : |
| f = new hexagone; break; |
| } |
| f->afficher(); |
| // On voudrait appeler la bonne version |
| // de afficher selon la valeur de f |
| // Actuellement : appel de |
| // figure::afficher() !!! |
| // .... transformer afficher |
| // en fonction virtuelle |
| Méthode virtuelle (1) |
| class figure { ... |
| public: |
| virtual void afficher(void) const; |
| }; |
| class rectangle : public figure { ... |
| public: |
| virtual void afficher(void) const; |
| }; |
| rectangle r; |
| figure *ptf=&r; |
ptf->afficher() ; // rectangle::afficher() |
| figure& rf=r; |
| rf.afficher(); //rectangle::afficher() |
| Méthode virtuelle (2) |
--> selon les compilateurs, erreur de compilation.
| Méthode virtuelle (3) |
| class A { |
| public : |
| virtual void foo() { cout << "A"; } ; |
| }; |
| class B : public A { |
| public: |
| // foo reste virtuelle |
| void foo() { cout << "B"; } ; |
| }; |
| class C : public B { |
| public: |
| // foo reste virtuelle |
| void foo() {cout << "C"; }; |
| }; |
| int main() { |
| A * a = new C; |
| B * b = new C; |
a->foo(); // foo virtuelle --> C::foo() |
b->foo(); // foo virtuelle --> C::foo()
|
| Table de fonctions virtuelles (1) |
--> Le constructeur initialise les valeurs de
ces vptrs avec les bonnes valeurs des vtables.
--> Le choix de la fonction membre virtuelle adéquate
est un accès
à son adresse stockée dans la table de l'objet référencé ou
pointé lors de l'exécution au moment de l'exécution de la
méthode.
| Table de fonctions virtuelles (2) |
| class rectangle : public figure{ |
| protected: |
| int l,lg; |
| public: |
| rectangle(int x=0, int y=0): l(x),lg(y){} |
| virtual int perimetre(void) const ; |
| int aire(void) const ; |
| }; |
| class carre : public rectangle { |
| public: |
| carre(int l=0) : rectangle(l,l) {} |
| int perimetre(void) const ; |
| int aire(void) const ; |
| }; |
| int main() { |
| rectangle * r = new rectangle(20,30); |
| cout << r->perimetre() << endl; |
| carre * c = new carre(10); |
| r = c; |
| cout << r->perimetre() << endl; |
| cout << r->aire() << endl; |
| } |
| Tables de fonctions virtuelles (3) |
-->

--> carre::aire
| Destructeur virtuel |
| class Base { ... |
| }; |
| class Deriv : public Base { |
| int *pt ; ... |
| public: |
| Deriv() { pt = new int[10]; } |
~Deriv() { delete [] pt; } |
| // ... |
| }; |
| Base *ptB = new Deriv; |
delete ptB;// a priori appel de ~Base() |
// --> espace mémoire non libéré |
| class Base { |
| virtual ~Base(); //... |
| }; |
| Méthode virtuelle et encapsulation |
| class Base {... |
| public: |
| virtual void virtMet() {...} |
| }; |
| class Deriv : public Base {... |
| protected: |
| virtual void virtMet() {...} |
| }; |
| Deriv f; |
| f.virtMet(); // Erreur : Deriv::virtMet() |
| // est protégée |
| Base *ptB=&f; |
ptB->virtMet(); |
| // OK: Base::virtMet publique |
| // MAIS APPEL DE Deriv::virtMet() !!! |
| Fonction virtuelle pure |
| class figure { ... |
| public: |
| virtual int perimetre() const =0; |
| ... |
| }; |
| Classe abstraite |
| Liaison statique vs. liaison dynamique |
| Exemple : Tri d'objets (1) |
| class Sortable { |
| public: |
| // retourne 0 si égaux |
| virtual int compare(Sortable const &) const =0; |
| virtual ~Sortable(); |
| virtual int getsignature() const =0; |
| }; |
| class Personne : public Sortable { |
| protected: |
| char nom[25]; |
| int salaire; |
| public: |
| int compare(Sortable const &) const; |
| int getsignature() const; |
| ~ Personne(); |
| // ... |
| }; |
| Exemple : Tri d'objets (2) |
| int Personne::getsignature() const { |
| // identificateur propre aux personnes |
// static --> adresse de tag est unique |
| static int tag; |
| return (int &tag); |
| } |
| // retourne 0 si égaux |
| int Personne::compare(Sortable const & other) { |
| register int cmp; |
| // Vérif. comparaison de deux Personnes |
| if ((cmp = getsignature() |
| - other.getsignature())) |
| return cmp; |
| // conversion de Sortable en Personne |
| Personne const & o = (Personne const&) other; |
| if ((cmp = strcmp(nom,o.nom)) == 0) |
| return cmp; |
| return 1; |
| } |