-->
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; |
} |