Copy of https://perso.isima.fr/loic/cpp/td_virtual_troncature.php
tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
Institut d'informatique ISIMA
  • twitter
  • linkedin
  • viadeo

[++C] TD : Polymorphisme

 Cette page commence à dater. Son contenu n'est peut-être plus à jour. Contactez-moi si c'est le cas!

Date de première publication : 2012/10/12

Polymorphisme : virtual

  1. Construire une classe Personne avec un attribut privé "nom" de type string

La classe string appartient à l'espace de nommage std. Voici les trois manières d'utiliser le type string :

  • std::string
  • using std::string;
  • using namespace std;
  1. Ajouter une méthode publique afficher() qui affiche le nom sur la sortie standard
  2. Ajouter un constructeur public qui prend en paramètre une chaîne et qui initialise le nom
  3. Instancier et afficher une personne p1
  4. Déclarer une classe Etudiant qui dérive de Personne
  5. Instancier et afficher un étudiant e
  6. Corriger sans modifier la classe Personne

Le compilateur râle d'abord parce qu'il n'y a pas de constructeur par défaut. Si on fournit un constructeur avec paramètre, il faut bien utiliser la liste d'initialisation pour appeler le seul constructeur défini dans la classe Personne.

  1. Ajouter une méthode publique info() dans les deux classes. Dans la classe Personne, la méthode affiche sur la sortie standard "Personne" et pour la classe Etudiant, "Etudiant".
  2. Appeler p1.info() et e.info(). Que remarquez-vous ?
  3. Créer un objet Personne p2 = e;. Appeler info(), que se passe-t'il ?
  4. Instancier une Personne * pp1 = new Etudiant("dd"); Appeler info(), que se passe-t'il ?
  5. Ajouter le mot-clé virtual sur chacune des méthodes info() ? Que remarquez-vous ?

Si vous avez codé proprement, vous avez fait un delete sur pp1. Pour que le destructeur d'Etudiant soit bien appelé, malgré le fait que pp1 est de type Personne *, il faut que les destructeurs soient virtual eux-aussi. C'est très facile à vérifier :

  1. Ajouter les destructeurs aux classes définies avec un simple affichage sur la console.
  2. Vérifier que ~Etudiant() n'est pas appelé lors du delete pp1;
  3. Ajouter virtual à ~Personne() et voir que cela marche bien maintenant

Troncature

  1. Ajouter le code ci-dessous et appelez ces fonctions en passant une instance d'Etudiant. Que remarquez-vous ?
  void afficher1(Personne  p) { p.info(); }
  void afficher2(Personne& p) { p.info(); }
  void afficher3(Personne* p) { p->info(); }

La perte d'informations liée à l'usage d'afficher1() s'appelle une troncature de type. On ne l'observe pas lorsque l'on utilise une référence ou un pointeur.

On aurait pu nommer afficher1() et afficher3() avec le même identifiant. Le compilateur aura fait la différence avec le type du paramètre (surcharge). La différentiation n'est pas possible entre afficher1() et afficher2().