1 2 3 4 5 6 7 8 9 10 11 12
| double calculePerimetre(Forme const & f)
{
return f.perimetre(); // ca sert à rien, mais c'est pour montrer le principe :D
}
int main()
{
Rectangle rect(/*...*/);
Cercle cer(/*...*/);
std::cout<<"Le perimetre du cercle est de "<<calculePerimetre(cer)<<std::endl
<<"et celui du rectangle est de "<<calculePerimetre(rect) <<std::endl;
return 0;
} |
me renvoie une valeur correcte aussi bien pour le périmetre de cer que pour celui de rect.
Ce genre de comportement s'appelle le
polymorphisme, que l'on pourrait définir comme le fait que Hé bien, il y a moyen d'arriver à un tel résultat.
Et si jusqu'à présent je t'ai expliqué "ce que je veux", je vais enfin t'expliquer comment l'obtenir
Le moyen d'obtenir ce genre de résultat est de déclarer (dans la classe Forme, vu que c'est un service que l'on est en droit d'attendre de "toute forme présente et à venir" les fonctions
double perimetre() const et
double superficie() const Et cela suffira pour expliquer au compilateur qu'il devra prendre un certain nombre de mesures pour s'assurer que, si on passe n'importe quel type de forme à la fonction calculePerimetre, ce soit bel et bien la logique qui s'applique au bon type de forme qui sera utilisée.
Je ne vais pas entrer maintenant dans les détails, car cela ne ferait qu'embrouiller les choses, mais saches que le compilateur fera "ce qu'il faut"
Cependant, comme je l'ai signalé plus haut, il faut garder en tete qu'il n'est pas possible de donner un comportement permettant de calculer la superficie ou le périmetre d'une forme si on ne sait pas quelle formule appliquer
On va donc devoir indiquer au compilateur que cela ne sert à rien qu'il cherche l'implémentation pour
Forme::perimetre() const ni pour
Forme::superficie() const en les déclarant
virtuelles pures.
Pour être honnête, il y aurait deux trois trucs à dire sur les fonctions virtuelles pures, mais je ne vais pas en parler maintenant, cela ne ferait que compliquer les choses
Cela se fait très simplement en rajoutant un =0 juste avant le ";" qui termine la déclaration de la fonction.
Nous pourrons donc définir notre classe Forme sous une forme proche de
1 2 3 4 5 6 7
| class Forme
{
public:
virtual ~Forme(){} // obligatoire ;)
virtual double perimetre() const = 0;
virtual double surface() const = 0;
}; |
dont on fera hériter Rectangle et Cercle, pour lesquels nous définirons le comportement de perimetre et surface, sous une forme proche de
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Rectangle : public Forme
{
public:
/* un rectangle a besoin de sa longeur et de sa largeur */
Rectangle(double lon, double larg):long_(lon), larg_(larg){}
/* le périmetre est égal à deux fois la somme de la longeur et de la largeur */
virtual double perimetre() const{return (long_+larg_)*2;}
/* et la superficie est égale à la multiplication des deux */
virtual double surface() const{return long_* large;}
private:
double long_;
double larg_;
};
class Cercle : public Forme
{
public:
/* ce qui nous intéresse pour le cercle, c'est son rayon */
Cercle(double rayon):rayon_(rayon){}
/* son périmetre est égal à 2 PI R */
virtual double perimetre() const{return 2 * 3.1415926 * rayon_;}
/* et sa superficie est égale à Pi * R * R */
virtual double surface() const{return 3.1415926 * rayon_ * rayon_;}
private:
double rayon_;
}; |
et, grace à ce mécanisme, si je complete le code d'exemple de la tantot, sous la forme de
1 2 3 4 5 6 7 8 9 10 11 12
| double calculePerimetre(Forme const & f)
{
return f.perimetre(); // ca sert à rien, mais c'est pour montrer le principe :D
}
int main()
{
Rectangle rect(3.0,4.0);
Cercle cer(2.0);
std::cout<<"Le perimetre du cercle est de "<<calculePerimetre(cer)<<std::endl
<<"et celui du rectangle est de "<<calculePerimetre(rect) <<std::endl;
return 0;
} |
nous obtiendrons bel et bien la sortie à laquelle nous nous attendons à savoir, quelque chose comme
1 2
| Le perimetre du cercle est de 12.5662 (j'ai pas calculé plus loin :? )
et celui du rectangle est de 24.0 |
Ca va, jusque là

Partager