1 conception et programmation à objets cours 6 mikal ziane précisions sur le polymorphisme le...

Post on 03-Apr-2015

110 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

Conception et Programmation à Objets

Cours 6Mikal Ziane

Précisions sur le Polymorphisme

• Le problème à résoudre

• Les fonctions virtuelles

• Comment ça marche ?

• Les méthodes virtuelles pures

• Complément : attributs et méthodes statiques

• Exercice (TD6)

2

Le Polymorphisme

• Idée: associer un même nom de méthode à plusieurs codes de méthode. Personne

afficher()

Enseignant Etudiant afficher()

• Si x est un objet le compilateur C++ peut déterminer à la compilation quelle fonction appeler lors de l'envoi du message x.afficher().• Le problème est plus difficile avec les pointeurs et références.•En effet un pointeur de Personne peut pointer sur un Etudiant sans que le compilateur le sache.

3

int main (){ Personne* tab[2]; tab[0] = new Personne ("Alain", "Dupont"); tab[1] = new Etudiant ("Paul", "Dubois", 2); tab[0]->afficher(); // OK. cout << endl; tab[1]->afficher(); // n'affiche pas l'année // si afficher() pas virtuelle ! cout << endl; return 0;}Un pointeur sur une super-classe a un type statique (ici Personne*) et un type dynamique (Etudiant*, ou Enseignant*) selon le type de l'objet pointé.

Exemple

4

Fonctions virtuelles

• Solution : on déclarera qu'afficher est une fonction virtuelle grâce au mot virtual.

• => mécanisme spécial pour appeler les méthodes : la liaison dynamique (dynamic binding, runtime dispatch, late binding).

• Le lien entre l'identificateur de la méthode et le code correspondant est fait dynamiquement (i.e. à l'exécution et non pas à la compilation).

• Une expression du genre p->afficher() déclenchera donc l'exécution de la méthode correspondant au type dynamique du pointeur p.

5

Fonctions virtuelles (suite)

• Par prudence on déclarera toutes les méthodes virtual si une classe peut avoir des sous-classes.

• Ainsi avec les pointeurs et les références, mais pas avec les objets, c'est la méthode correspondant au code de l'objet pointé qui sera appelée.

• Piège: si dans une version on change la signature de la fonction virtuelle le mécanisme de virtual ne marche plus ! Le compilateur reconnaît les différentes versions grâce à leur signature (prototype) qui doit être identique.

6

personne.hpp#include "chaine.hpp"class Personne {private: Chaine prenom_, nom_;public: Personne (char *p ="inconnu", char *n

="inconnu"); virtual void afficher() const; virtual const Chaine& prenom() const; virtual const Chaine& nom() const;};

• Si on met un const il faut le mettre dans les sous-classes aussi sinon le compilateur ne reconnaît pas la méthode !

7

etudiant.hpp

#include "personne.hpp"

class Etudiant : public Personne {public:

int annee () const;Etudiant (char *p="inconnu", char *n="inconnu",

int annee =1);virtual void afficher () const;

private:int annee_;

};• Ici il faut absolument que le const soit présent (car il est présent pour Personne::afficher) sinon la signature d'afficher sera différente et le polymorphisme ne marchera pas !!

8

Comment ca marche ?

void Personne::afficher () const

Alain

Dupont

void Etudiant::afficher () const

......

Paul

Dubois

2

9

Comment ca marche ? (bis)

• Si une fonction est virtuelle dans une classe, les objets de cette classe (et des sous-classes) ont un champ supplémentaire.

• Ce champ pointe sur un tableau de pointeurs de méthodes de la classe de l'objet.

• Les versions de la même fonction virtuelle ont bien sûr le même numéro de poste dans tous les tableaux.

• Avec ce numéro il est alors facile d'appeler la bonne version de la fonction.

• Ainsi pe->afficher(); devient pe->vir[0]();

10

Les méthodes virtuelles pures

• Il est possible de ne pas implémenter certaines méthodes d'une classe, en supposant que ce code sera défini dans les sous-classes !

• On dit alors que la méthode est virtuelle pure.

• Si une classe contient au moins une méthode virtuelle pure il est interdit de créer des objets de cette classe !

• Une classe qui n'aura jamais d'instance est dite abstraite sinon elle est dite concrète.

• Par contre rien n'interdit de définir des pointeurs vers une classe abstraite qui pointeront sur des objets des sous-classes.

11

personne.hpp

#include "chaine.hpp"

class Personne {private: Chaine prenom_, nom_;public: virtual void afficher() const =0; virtual const Chaine& prenom() const; virtual const Chaine& nom() const;protected: Personne (char *p = "inconnu", char *n ="inconnu");};

12

Création virtuelle• L'opérateur new et les constructeurs ne peuvent pas être virtuels.

• En effet on ne peut pas utiliser le type dynamique d'un objet qui n'existe pas encore !

• => Utiliser le pattern prototype quand c'est possible :

– Ajouter une fonction virtuelle clone()

– Créer à l'avance un prototype de chaque classe concrète

– Pour créer un objet : cloner le prototype de sa classe

Personne clone()

Enseignantclone()

Etudiantclone()

13

Méthodes et champs statiques

• Un champ statique n'est pas stocké dans chaque objet mais une seule fois par classe. Sa durée de vie est la même que celles des variables globales.

• On ne peut donc pas initialiser un champs statique avec un constructeur: il y a une syntaxe spéciale à utiliser dans le .cpp.

• Un méthode statique n'a pas de pointeur this, elle ne peut donc utiliser que les champs statiques.

• Par contre elle n'a pas besoin d'un objet pour pouvoir être appelée ce qui est parfois indispensable.

• Exemple: on veut savoir combien il y a d'objets Personne qui existent à un instant donné.

14

main.cpp (bis)

#include <iostream>using namespace std;

void main (){ Etudiant e ("Paul", "Dubois", 2); Personne p ("Alain", "Legoff"); Personne* pp = new Etudiant (); cout << "Il y a " << Personne::combien()

<< " personnes." << endl; delete pp; cout << "Il y a " << Personne::combien()

<< " personnes." << endl;}

15

personne.hpp (bis)#include "chaine.hpp"

class Personne {private: Chaine prenom_, nom_; static int combien_;public: Personne (char *p = "nom inconnu",

char *n ="nom inconnu"); virtual ~Personne(); // oui virtual ! Virtual void afficher() const; virtual const Chaine& prenom() const; virtual const Chaine& nom() const; static int combien();};

16

personnes.cpp (modifications)

int Personne::combien_ = 0;

Personne::Personne (char *p, char *n) : nom_ (n), prenom_ (p){ combien_++;}

Personne::~Personne (){ combien_--;}

int Personne::combien (){ return combien_; }

17

Exercice (TD6)

• On veut à terme écrire un programme simulant le comportement de robots dans un plan (coordonnées x,y). Le décor dans lequel les robots évolueront sera constitué d'objets fixes ou eux-mêmes mobiles comme les robots.

• On commencera par un prototype extrêmement simple avec un robot, un trésor et une bombe, seul le robot étant mobile.

18

• La simulation consiste à afficher à chaque tic d'une horloge imaginaire la position des objets mobiles, ici seulement le robot.

• A chaque tic de cette horloge les objets mobiles se déplacent en sautant selon leur vecteur vitesse (dx,dy par unité de temps).

19

• Lorsqu'un objet mobile rencontre un objet fixe il se produit une action dépendant, pour ce prototype, uniquement de l'objet fixe.

• Cette action sera constituée de l'affichage d'un message ("boom !" pour la bombe, "bingo !" pour le trésor) ainsi que l'affichage de l'objet fixe responsable.

20

• Une action peut aussi se poursuivre en fonction du comportement souhaité pour l'objet fixe.

• Par exemple une bombe pourra interrompre la simulation alors qu'un trésor laissera la simulation continuer.

• Pour afficher un objet, fixe ou mobile, on affichera le symbole de l'objet (un caractère quelconque) et ses coordonnées.

top related