Conversion implicite d'un objet d'une classe dérivée
point a;
pointforme b;
a = b;
b = a;
point *pa;
pointforme *pb;
pa = pb;
pb = pa;
|
Typage statique des objets
point a, *pa;
pointforme b, *pb;
pa = &a;
pb = &b;
a.afficher ();
pa->afficher ();
b.afficher ();
pb->afficher ();
pa = pb;
pa->afficher ();
|
Fonction virtuelle et typage dynamique
class point
{
private :
...
public :
virtual void afficher ();
};
class pointforme : public point
{
private :
...
public :
void afficher ();
}
|
Grâce à la fonction virtuelle
afficher() de la classe
point, le
dernier appel
pa->afficher() de l'exemple précédent utilisera la fonction afficher de la classe
pointforme.
point a, *pa;
pointforme b, *pb;
pa = &a;
pb = &b;
a.afficher ();
pa->afficher ();
b.afficher ();
pb->afficher ();
pa = pb;
pa->afficher ();
|
Fonction virtuelle pour éviter des redondances de code
Jusqu'à présent nous déclarons les méthodes
afficher() de chaque classe comme ceci :
void point::afficher ()
{
cout << abscisse << "," << ordonnee << "\n";
}
void pointforme::afficher ()
{
point::afficher ();
cout << forme << "\n";
}
void pointcolore::afficher ()
{
point::afficher ();
cout << couleur << "\n";
}
|
Il est donc nécessaire de répéter à chaque fois l'appel à la méthode
afficher() de
la classe de base
point en utilisant l'opérateur de résolution de portée ::
Les fonctions virtuelles permettent d'éviter cette répétition de code :
class point
{
private:
...
public :
void afficher ();
virtual void identifier ();
};
void point::afficher ()
{
cout << abscisse << "," << ordonnee << "\n";
identifier ();
}
void point::identifier ()
{
}
class pointforme : public point
{
private :
...
public :
void identifier ();
};
void pointforme::identifier ()
{
cout << forme << "\n";
}
class pointcolore : public point
{
private :
...
public :
void identifier ();
};
void pointcolore::identifier ()
{
cout << couleur << "\n";
}
point p1;
pointcolore p2;
pointforme p3;
p1.afficher ();
p2.afficher ();
p3.afficher ();
|
Fonction virtuelle pure et classe abstraite
class classe_abstraite
{
public :
virtual void afficher () = 0;
};
|
Si l'on a une méthode virtuelle pure dans une classe, la classe est dite abstraite. Une classe
abstraite ne peut jamais être instanciée. Les classes dérivées doivent définir le corps de la méthode virtuelle
pure.
class point : public classe_abstraite
{
private :
float abscisse, ordonnee;
public :
...
void afficher () { cout << abscisse << "," << ordonnee; }
};
class vecteur3 : public classe_abstraite
{
private :
float x, y, z;
public :
...
void afficher () { cout << x << "," << y << "," << z; }
}
class matrice2 : public classe_abstraite
{
private :
float m[2][2];
public :
...
void afficher () { cout << m[0][0] << "," << m[0][1] << "," << m[1][0] << "," << m[1][1]; }
}
|
Utilisation :
void main ()
{
classe_abstraite *t[3];
t[0] = new point(3.5, 5.2);
t[1] = new vecteur3(3.5, 6.2, 7.0);
t[2] = new matrice2(5.0, 5.0, 5.0, 5.0);
for (int i = 0; i < 3; i++)
{
t[i]->afficher ();
}
}
|
Polymorphisme
1) Polymorphisme d'objet
On parle de
polymorphisme d'objet lorsque tout objet instance d'une classe ancêtre
peut être remplacé par un objet d'une classe descendante de la classe ancêtre.
Exemple :
class polygone
{
private :
...
public :
...
};
class rectangle : public polygone
{
private :
...
public :
...
};
class triangle : public polygone
{
private :
...
public :
...
};
|
Soit
tableauPolygones un tableau d'objet
polygone :
polygone tableauPolygones[10];
|
Dans le tableau
tableauPolygones on peut mémoriser des polygones, mais aussi des
triangles et des rectangles. Nous avons donc plusieurs formes possibles pour
tableauPolygones[i].
Il s'agit donc ici de polymorphisme d'objets.
2) Polymorphisme de méthode
De façon similaire, le
polymorphisme de méthode apparaît lorsque l'on est confronté
à plusieurs défintions d'une même méthode. Chaque méthode étant spécifique à l'objet (nous avons déjà rencontré
ce cas pour la fonction
identifier de la classe
point) ...
Exemple :
class polygone
{
private :
...
public :
virtual float perimetre ();
...
};
...
class rectangle : public polygone
{
private :
float longueur, largeur;
...
public :
float perimetre () { return (2*(longueur + largeur)); }
...
};
class triangle : public polygone
{
private :
float base, adjacent, oppose;
...
public :
float perimetre () { return (base + adjacent + oppose); }
...
};
|
En reprenant l'exemple de
tableauPolygones nous obtiendrons pour
tableauPolygones[i]
le calcul du périmètre du polygone correspondant à l'objet mémorisé. Nous avons plusieurs méthodes utilisées dans
le tableau
tableauPolygones. Il s'agit donc de polymorphisme de méthode.