Choisissez votre style : colorisé, impression

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;
}
qui donne comme résultat :
 
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;
}

Dernière mise à jour : 2025/03/27 19:25