Correction 20
Polymorphisme
Exercice 1 : Formes polymorphiques (niveau 1)
1.1 Formes :
Définissez une classe Forme en la dotant d'une méthode qui affiche [...]
#include <iostream> // pour cout
using namespace std; // pour ne pas écrire std::cout et std::endl
class Forme {
public:
void description() const {
cout << "Ceci est une forme !" << endl;
}
};
Ajoutez au programme une classe Cercle héritant de la classe Forme, et possédant une méthode void description() qui affiche [...]
class Cercle : public Forme {
public:
void description() const {
cout << "Ceci est un cercle !" << endl;
}
};
[...] Testez ensuite à nouveau votre programme.
Voyez-vous vu la nuance ?
Pourquoi a-t-on ce
fonctionnement ?
La différence vient de ce que c.description(); appelle la méthode description() de la classe Cercle (c'est-à-dire Cercle::description()), alors que f2.description(); appelle celle de la classe Forme (c'est-à-dire Forme::description()), bien que elle ait été construite par une copie d'un cercle.
Le polymorphisme n'opère pas ici car aucune des deux conditions nécessaires n'est remplie : la méthode n'est pas virtuelle et on ne passe par pas par des références ni pointeurs.
[...] Ajoutez encore au programme une fonction
void affichageDesc(Forme& f) [...]
Le résultat vous semble-t-il
satisfaisant ?
Avec cette fonction, nous apportons une solution au second aspect puisqu'en effet nous passons l'argument par référence.
Le résultat n'est cependant toujours pas satisfaisant (c'est toujours la méthode Forme::description() qui est appelée) car le premier problème subsiste : la méthode n'est pas virtuelle.
Modifiez le programme (ajoutez 1 seul mot) pour que le résultat soit plus conforme à ce que l'on pourrait attendre.
Il suffit donc d'ajouter virtual devant le prototype de la méthode description de la classe Forme.
Voici le programme complet :
#include <iostream>
using namespace std;
class Forme {
public:
virtual void description() const {
cout << "Ceci est une forme !" << endl;
}
};
class Cercle : public Forme {
public:
void description() const {
cout << "Ceci est un cercle !" << endl;
}
};
void affichageDesc(Forme& f) { f.description(); }
int main()
{
Forme f;
Cercle c;
// f.description();
// c.description();
// Forme f2(c);
// f2.description();
affichageDesc(f);
affichageDesc(c);
return 0;
}
1.2 Formes abstraites
Modifiez la classe Forme de manière à en faire une classe abstraite [...]
class Forme {
public:
virtual void description() const {
cout << "Ceci est une forme !" << endl;
}
virtual double aire() const = 0;
};
Ce qui en fait une méthode virtuelle pure c'est le =0 derrière qui indique que pour cette classe cette méthode ne sera pas implémentée (i.e. pas de définition, c.-à-d. pas de corps).
Écrivez une classe Triangle et modifiez la classe Cercle existante héritant toutes deux de la classe Forme, et implémentant les méthodes aire() et description(). [...]
class Cercle : public Forme {
public:
Cercle(double x = 0.0) { rayon = x; }
void description() const {
cout << "Ceci est un cercle !" << endl;
}
double aire() const { return 3.141592653 * rayon * rayon; }
private:
double rayon;
};
class Triangle : public Forme {
public:
Triangle(double h = 0.0, double b = 0.0) { base = b; hauteur = h; }
void description() const {
cout << "Ceci est un triangle !" << endl;
}
double aire() const { return 0.5 * base * hauteur; }
private:
double base; double hauteur;
};
Modifiez la fonction affichageDesc pour qu'elle affiche, en plus, l'aire [...]
void affichageDesc(Forme& f) {
f.description();
cout << " son aire est " << f.aire() << endl;
}
et le programme complet :
#include <iostream>
using namespace std;
class Forme {
public:
// void description() const {
virtual void description() const {
cout << "Ceci est une forme !" << endl;
}
virtual double aire() const = 0;
};
class Cercle : public Forme {
public:
Cercle(double x = 0.0) { rayon = x; }
void description() const {
cout << "Ceci est un cercle !" << endl;
}
double aire() const { return 3.141592653 * rayon * rayon; }
private:
double rayon;
};
class Triangle : public Forme {
public:
Triangle(double h = 0.0, double b = 0.0) { base = b; hauteur = h; }
void description() const {
cout << "Ceci est un triangle !" << endl;
}
double aire() const { return 0.5 * base * hauteur; }
private:
double base; double hauteur;
};
void affichageDesc(Forme& f) {
f.description();
cout << " son aire est " << f.aire() << endl;
}
int main()
{
Cercle c(5);
Triangle t(10, 2);
affichageDesc(t);
affichageDesc(c);
return 0;
}
Ceci est un triangle ! son aire est 10 Ceci est un cercle ! son aire est 78.5398
Exercice 2 : encore des vaccins (niveau 1, polymorphisme)
Voici un corrigé possible :
#include <string>
#include <vector>
#include<iostream>
using namespace std;
// prix du conditionnement d'une unité
const double COND_UNITE(0.5);
// prix de base de fabrication d'une unité
const double PRIX_BASE(1.5);
// majoration du prix de fabrication pour vaccin "high tech"
const double MAJORATION_HIGHTECH(0.5);
// reduction du cout du à la delocalisation
const double REDUCTION_DELOC(0.2);
enum Fabrication {Standard, HighTech};
/**************************************
* Un classe pour représenter un vaccin
*************************************/
class Vaccin{
public:
Vaccin(string _nom, double _volume_dose, unsigned int _nb_doses,
Fabrication _fabrication = Standard)
:nom(_nom), volume_dose(_volume_dose), nb_doses(_nb_doses),
mode_fabrication(_fabrication)
{}
virtual ~Vaccin()
{}
// surcharge de l'opérateur << pour afficher les
// données relatives à un vaccin
friend ostream& operator<< (ostream& out, const Vaccin& v)
{
out << v.nom << endl;
out << "volume/dose : " << v.volume_dose << endl;
out << "nombre de doses: " << v.nb_doses << endl;
out << "mode de fabrication ";
if (v.mode_fabrication == HighTech)
out << "haute technologie" << endl;
else out << "standard" << endl;
return out;
}
// méthode du calcul du cout de conditionnement
virtual double conditionnement() const{
return (volume_dose * nb_doses) * COND_UNITE;
}
// méthode du calcul du cout de fabrication
virtual double fabrication() const
{
double prix(volume_dose * nb_doses * PRIX_BASE);
if (mode_fabrication == HighTech)
{
prix += prix * MAJORATION_HIGHTECH;
}
return prix;
}
// méthode du calcul du cout de production
virtual double production() const
{
return fabrication()+conditionnement();
}
private:
// nom du vaccin
string nom;
// volume par dose de vaccin
double volume_dose;
// nombre de doses
unsigned int nb_doses;
// mode de fabrication du vaccin
Fabrication mode_fabrication;
};
/*******************************************
* Une classe pour représenter un vaccin
* pouvant etre produit de façon délocalisée
*******************************************/
class Delocalise: public Vaccin{
public:
Delocalise(string _nom, double _volume_dose,
unsigned int _nb_doses, Fabrication _fabrication,
bool _frontalier)
:Vaccin(_nom,_volume_dose , _nb_doses, _fabrication),
frontalier(_frontalier) {}
virtual ~Delocalise()
{}
// masquage de la méthode héritée de Vaccin
double production() const
{
double prix = Vaccin::production();
if (frontalier)
{
prix -= prix * REDUCTION_DELOC;
}
else
{
prix /= 2;
}
return prix;
}
private:
// indique si la production est délocalisée
// dans un pays frontalier ou non
bool frontalier;
};
// un nouveau type pour représenter un vecteur de Vaccin*
typedef vector<Vaccin*> Stock;
/*************************************************
* Une classe pour modéliser une entreprise
* pharmaceutique
*********************************************/
// on aurait aussi pu faire hériter Compagnie de vector<Vaccin*>
class Compagnie {
public:
Compagnie(string _nom)
:nom(_nom)
{}
// ajoute un vaccin produit au stock
void produire(Vaccin* v) {vaccins.push_back(v); }
// calcule le cout de production de l'ensemble des vaccins
double calculer_cout() const;
//vide le stock de vaccins
void vider_stock() { vaccins.clear();
}
// détruit tous les vaccins
void supprimer_vaccins();
// affiche tous les vaccins
void afficher() const
{
for (int i(0); i < vaccins.size(); ++i)
{
cout << *vaccins[i] << endl;
}
}
private:
Stock vaccins;
string nom;
};
void Compagnie::supprimer_vaccins(){
for(unsigned int v(0); v < vaccins.size(); ++v)
delete vaccins[v];
vider_stock();
}
double Compagnie::calculer_cout() const
{
double prix(0);
for(unsigned int v(0); v < vaccins.size(); ++v){
prix += vaccins[v]->production();
}
return prix;
}
// ======================================================================
// un petit main pour tester tout ca
int main() {
//Test des parties de la serie 8
cout << "test de la partie 4.1 " << endl;
Vaccin v1("Zamiflu", 0.55, 200000, HighTech);
Vaccin v2("Triphas", 0.20 , 10000);
// affichage des vaccins
cout << v1 << endl;
cout << v2 << endl;
cout << "le cout deproduction de v1 et v2 est : ";
cout << v1.production() + v2.production() << endl;
cout << "test des parties suivantes ..." << endl;
Delocalise v3("Zamiflu", 0.55, 15000, HighTech, false);
Delocalise v4("Triphas", 0.20, 15000, Standard, true);
cout << "le cout de production de v3 et v4 est : ";
cout << v3.production() + v4.production() << endl;
// test de la partie de cette semaine
Compagnie c("ICIBA");
c.produire(&v1);
c.produire(&v2);
c.produire(&v3);
c.produire(&v4);
cout << endl;
cout << "Coûts de production de l'ensemble du stock:" << endl;
c.afficher();
cout <<"le cout de production a été de : " << c.calculer_cout() << endl;
return 0;
}