Partie 12: Polymorphisme — Programmation orientée objet en C++
Upcoming SlideShare
Loading in...5
×
 

Partie 12: Polymorphisme — Programmation orientée objet en C++

on

  • 3,356 views

Support material for a continued education course "Introduction to object oriented programming in C++".

Support material for a continued education course "Introduction to object oriented programming in C++".
In French.

Statistics

Views

Total Views
3,356
Views on SlideShare
3,356
Embed Views
0

Actions

Likes
2
Downloads
98
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Partie 12: Polymorphisme — Programmation orientée objet en C++ Partie 12: Polymorphisme — Programmation orientée objet en C++ Presentation Transcript

  • Programmation Orientée Objet en C++ 12ème Partie: Polymorphisme Fabio Hernandez Fabio.Hernandez@in2p3.fr
  • Vue dEnsemble Notions de base Types, variables, opérateurs Contrôle dexécution Fonctions Mémoire dynamique Qualité du logiciel Evolution du modèle objet Objets et classes Fonctions membres Classes génériques Héritage Polymorphisme Héritage multiple Entrée/sortiePOO en C++: Polymorphisme 401 © 1997-2003 Fabio HERNANDEZ
  • Table des Matières Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 402 © 1997-2003 Fabio HERNANDEZ
  • Motivation Le mécanisme dhéritage permet aux sous-classes dutiliser limplémentation des méthodes de la classe de base Nous allons étudier un mécanisme étroitement lié à lhéritage appelé polymorphisme Polymorphisme signifie la possibilité d ’un objet de prendre plusieurs formes Dans le contexte du modèle objet cela signifie quune "entité" du langage peut être attachée en temps dexécution à des objets de classes différentes Dans le cas de C++, cette "entité" ne peut être quun pointeur ou une référencePOO en C++: Polymorphisme 403 © 1997-2003 Fabio HERNANDEZ
  • Motivation (suite) Ce mécanisme permet de manipuler dune façon uniforme un ensemble dobjets appartenant à une même hiérarchie de classesPOO en C++: Polymorphisme 404 © 1997-2003 Fabio HERNANDEZ
  • Contrôle dAvancement Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 405 © 1997-2003 Fabio HERNANDEZ
  • Affectation Polymorphe Figure OpenFigure ClosedFigure Segment Polyline Polygon Ellipse Triangle Rectangle ... Circle SquarePOO en C++: Polymorphisme 406 © 1997-2003 Fabio HERNANDEZ
  • Affectation Polymorphe (suite) Si nous déclarons les objets Polygon aPolygon; Triangle aTriangle; Square aSquare; Nous pouvons déclarer le pointeur Polygon* polygonPtr; Et les affectations suivantes sont valides polygonPtr = &aTriangle; // aTriangle is-a Polygon polygonPtr = &aSquare; // aSquare is-a Polygon polygonPtr = new Rectangle; // a Rectangle is-a Polygon Le mécanisme dhéritage nous permet de traiter une instance de la classe Triangle ou Square comme une instance de PolygonPOO en C++: Polymorphisme 407 © 1997-2003 Fabio HERNANDEZ
  • Affectation Polymorphe (suite) Notez quil ny a aucune transformation des objets aTriangle et aSquare une fois crée un objet ne change pas son type Les pointeurs et références peuvent être "attachés" à des objets de types différents descendants dun ancêtre commun Pour le passage de paramètres nous pouvons utiliser le même principe soit la fonction void inspect(const Polygon& aPolygon) { // Do something with the parameter object }POO en C++: Polymorphisme 408 © 1997-2003 Fabio HERNANDEZ
  • Affectation Polymorphe (suite) Nous pouvons appeler cette fonction avec comme argument un objet descendant de Polygon Square aSquare; Triangle aTriangle; inspect(aSquare); // OK: aSquare is a Polygon inspect(aTriangle); // OK: aTriangle is a Polygon Circle aCircle; inspect(aCircle); // COMPILATION ERROR: aCircle is // not a kind of PolygonPOO en C++: Polymorphisme 409 © 1997-2003 Fabio HERNANDEZ
  • Contrôle dAvancement Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 410 © 1997-2003 Fabio HERNANDEZ
  • Structures de Données Polymorphes Soit le tableau Polygon* polygonArray[4]; polygonArray[0] = new Rectangle; polygonArray[1] = new Square; polygonArray[2] = new Triangle; polygonArray[3] = new Polygon; Nous pouvons le visualiser comme 0 1 2 3 polygonArrayPOO en C++: Polymorphisme 411 © 1997-2003 Fabio HERNANDEZ
  • Structures de Données Polymorphes (suite) Une structure polymorphe est une structure qui contient des objets de types différents descendants dune classe commune Tous les conteneurs que nous avons étudiés peuvent être des structures polymorphes (List, Queue, Set, Bag, Stack, ...) Lintérêt des conteneurs polymorphes cest quils offrent la possibilité de traiter dune façon uniforme tous les objets contenus Supposons par exemple que nous voulons calculer la somme des périmètres des polygones contenus dans notre tableau Une façon naturelle serait de faire une boucle pour parcourir chacune des positions du tableau en calculant le périmètre du polygone correspondant et den faire ladditionPOO en C++: Polymorphisme 412 © 1997-2003 Fabio HERNANDEZ
  • Structures de Données Polymorphes (suite) Calcul du périmètre (suite) float total = 0.0; for (int pos=0; pos < MaxPositions; pos++) { total += Perimeter of polygonArray[pos]; } Quelle méthode faudrait-il appeler sur lobjet pointé par polygonArray[pos] pour obtenir son périmètre? Regardons la définition de la classe PolygonPOO en C++: Polymorphisme 413 © 1997-2003 Fabio HERNANDEZ
  • Classe Polygon #include "Point.h" #include "List.h" class Polygon { public: // Constructors/Destructor Polygon(); ~Polygon(); // Modifiers void translate(float horizontal, float vertical); void rotate(float angle); ...POO en C++: Polymorphisme 414 © 1997-2003 Fabio HERNANDEZ
  • Classe Polygon (suite) // Selectors float perimeter() const; float area() const; ... private: // Data members List<Point> vertexList_; };POO en C++: Polymorphisme 415 © 1997-2003 Fabio HERNANDEZ
  • Classe Polygon (suite) Limplémentation de la fonction membre Polygon::perimeter pourrait être float Polygon::perimeter() const { int numVertices = vertexList_.length(); float result = 0.0; for (int i=1; i < numVertices; i++) { const Point& previous = vertexList_.itemAt(i-1); const Point& current = vertexList_.itemAt(i); result += current.distanceTo(previous); } const Point& first = vertexList_.first(); const Point& last = vertexList_.last(); return result + first.distanceTo(last); }POO en C++: Polymorphisme 416 © 1997-2003 Fabio HERNANDEZ
  • Classe Rectangle #include "Point.h" #include "Polygon.h" class Rectangle: public Polygon { public: side2 // Constructors/Destructor Rectangle(const Point& origin, float side1, float side2); side1 ~Rectangle(); origin // Modifiers ...POO en C++: Polymorphisme 417 © 1997-2003 Fabio HERNANDEZ
  • Classe Rectangle (suite) // Selectors float perimeter() const; float area() const; float diagonal() const; ... Fonctions et données membres private: spécifiques à la // Data members classe Rectangle float side1_; float side2_; Point origin_; };POO en C++: Polymorphisme 418 © 1997-2003 Fabio HERNANDEZ
  • Classe Rectangle (suite) Limplémentation de la méthode Rectangle::perimeter est plus simple que Polygon::perimeter float Rectangle::perimeter() const { return 2*(side1_ + side2_); } Rectangle est donc une spécialisation de la classe Polygon et Rectangle::perimeter est une redéfinition de Polygon::perimeter De façon similaire pour la méthode Rectangle::areaPOO en C++: Polymorphisme 419 © 1997-2003 Fabio HERNANDEZ
  • Contrôle dAvancement Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 420 © 1997-2003 Fabio HERNANDEZ
  • Liaison Statique Static Binding La liaison est le mécanisme utilisé par le compilateur pour déterminer quelle fonction membre appeler sur un objet qui appartient à une hiérarchie de classes lorsquil y a redéfinition de méthodes Exemple Rectangle rect(Point(0.0, 1.0), 10.0, 15.0); Polygon poly; float perimeter; perimeter = rect.perimeter(); // Rectangle::perimeter() is called perimeter = poly.perimeter(); // Polygon::perimeter() is calledPOO en C++: Polymorphisme 421 © 1997-2003 Fabio HERNANDEZ
  • Liaison Statique (suite) Exemple (suite) Polygon* polyPtr = &poly; perimeter = polyPtr->perimeter(); // Polygon::perimeter() is called Rectangle* rectPtr = &rect; perimeter = rectPtr->perimeter(); // Rectangle::perimeter() is called polyPtr = &rect; perimeter = polyPtr->perimeter(); // Rectangle::perimeter() or Polygon::perimeter()?POO en C++: Polymorphisme 422 © 1997-2003 Fabio HERNANDEZ
  • Liaison Statique (suite) Exemple (suite) La fonction membre appelée est Polygon::perimeter() Le principe de liaison statique établit que le type de lobjet sur lequel la méthode est appliquée détermine statiquement la méthode appelée Dans lexemple précédent, le pointeur polyPtr pointe vers un objet de la classe Polygon; en conséquence, linstruction polyPtr->perimeter() se traduit par une invocation à la méthode Polygon::perimeter()POO en C++: Polymorphisme 423 © 1997-2003 Fabio HERNANDEZ
  • Liaison Statique (suite) De façon similaire linstruction float diagonal = polyPtr->diagonal(); // ERROR est marquée par une erreur de compilation: polyPtr est défini comme un pointeur à Polygon et la méthode Polygon::diagonal nest pas définie Par contre avec les instructions Rectangle* rectPtr = &rect; float diagonal = rectPtr->diagonal(); // OK on obtient le résultat souhaité Ce principe de liaison (binding) est appelé statique parce que le choix de la méthode à appeler est fait en temps de compilationPOO en C++: Polymorphisme 424 © 1997-2003 Fabio HERNANDEZ
  • Contrôle dAvancement Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 425 © 1997-2003 Fabio HERNANDEZ
  • Liaison Dynamique Dans lexemple précédant du calcul du périmètre float total = 0.0; for (int pos=0; pos < MaxPositions; pos++) total += polygonArray[pos]->perimeter(); la méthode qui sera appelée pour chaque objet du tableau est Polygon::perimeter() Supposons que nous disposons dune méthode pour connaître en temps dexécution la classe dun objet On pourrait écrire par exemple if (type of polygonArray[pos] == Rectangle) // WARNING: this is pseudo-code pour déterminer si un objet est de type RectanglePOO en C++: Polymorphisme 426 © 1997-2003 Fabio HERNANDEZ
  • Liaison Dynamique (suite) Une façon de résoudre ce problème et dappeler la bonne méthode serait float total = 0.0; for (int pos=0; pos < MaxPositions; pos++) { // WARNING: this is pseudo-code if (type of polygonArray[pos] == Rectangle) total += ((Rectangle*)polygonArray[pos])->perimeter(); else if (type of polygonArray[pos] == Triangle) total += ((Triangle*)polygonArray[pos])->perimeter(); .... }POO en C++: Polymorphisme 427 © 1997-2003 Fabio HERNANDEZ
  • Liaison Dynamique (suite) Linconvénient de cette technique cest quelle rend difficile les modifications Si une nouvelle sous-classe de Polygon est rajoutée ou une sous-classe existante est supprimée de la hiérarchie, cette boucle doit être modifiée Le modèle objet propose une technique pour résoudre ce problème appelée "Liaison Dynamique" (dynamic binding) Par opposition au principe de liaison statique, avec la liaison dynamique le compilateur ne peut décider en temps de compilation quelle méthode appeler. Cette décision est prise en temps dexécution, par rapport à la classe de lobjet en question (Rectangle, Triangle, Polygon, ...)POO en C++: Polymorphisme 428 © 1997-2003 Fabio HERNANDEZ
  • Liaison Dynamique (suite) Contrairement à dautres langages OO, C++ utilise par défaut la liaison statique Le programmeur est donc responsable dinformer le compilateur que pour une ou plusieurs méthodes dune classe il souhaite utiliser la liaison dynamique Le mot clé du langage pour exprimer ce concept est virtual Nous devons en conséquence modifier linterface de notre classe Polygon pour indiquer que la fonction membre Polygon::perimeter sera virtualPOO en C++: Polymorphisme 429 © 1997-2003 Fabio HERNANDEZ
  • Classe Polygon class Polygon { public: // Constructors/Destructor ... // Modifiers ... // Selectors Définition des virtual float perimeter() const; fonctions membres virtual float area() const; Perimeter et area ... comme ayant liaison dynamique private: // Data members ... };POO en C++: Polymorphisme 430 © 1997-2003 Fabio HERNANDEZ
  • Classe Polygon (suite) Notez que limplémentation des fonctions Polygon::perimeter et Polygon:: area reste inchangée Les interfaces des sous-classes de Polygon (Rectangle, Triangle, ...) peuvent rester inchangées. Néanmoins, pour clarté nous allons propager la modification de linterface de Polygon à toutes ses sous-classes Regardons le cas de la classe RectanglePOO en C++: Polymorphisme 431 © 1997-2003 Fabio HERNANDEZ
  • Classe Rectangle class Rectangle: public Polygon { public: Propagation pour // Constructors/Destructor clarté de la ... définition des // Modifiers fonctions membres ... Perimeter et area // Selectors comme virtual. virtual float perimeter() const; virtual float area() const; Définition de la virtual float diagonal() const; méthode diagonal ... comme virtual. private: Affecte toutes les // Data members sous-classes de ... Rectangle };POO en C++: Polymorphisme 432 © 1997-2003 Fabio HERNANDEZ
  • Calcul du périmètre Dans lexemple du tableau polymorphe 0 1 2 3 lalgorithme float total = 0.0; for (int pos=0; pos < MaxPositions; pos++) total += polygonArray[pos]->perimeter(); appellera Rectangle::perimeter(), Square::perimeter(), Triangle::perimeter() et Polygon::perimeter()POO en C++: Polymorphisme 433 © 1997-2003 Fabio HERNANDEZ
  • Destructeur Virtuel Lors de la destruction dune structure (conteneur) polymorphe (List, Queue, Stack, Set, Bag, Tree, ...) les objets contenus seront eux aussi probablement détruits Le destructeur de chacun des objets sera utilisé for (int pos=0; pos < MaxPositions; pos++) delete polygonArray[pos]; Cependant, avec le destructeur nous avons le même problème que avec la fonction membre perimeter dans ce cas particulier, à cause de la liaison statique uniquement le destructeur Polygon::~Polygon() sera appelé La solution est la même que pour les autres fonctions membres Le destructeur de la classe de base doit être défini virtualPOO en C++: Polymorphisme 434 © 1997-2003 Fabio HERNANDEZ
  • Destructeur Virtuel (suite) class Polygon { public: // Constructors/Destructor Polygon(); virtual ~Polygon(); Le destructeur doit être déclaré // Modifiers virtual. ... // Selectors ... private: // Data members ... };POO en C++: Polymorphisme 435 © 1997-2003 Fabio HERNANDEZ
  • Destructeur Virtuel (suite) De façon similaire, pour des raisons de clarté nous déclarerons virtual le destructeur de toutes les sous-classes de Polygon Dune façon générale, on doit déclarer virtual le destructeur de toute classe contenant au moins une fonction membre virtuellePOO en C++: Polymorphisme 436 © 1997-2003 Fabio HERNANDEZ
  • Contrôle dAvancement Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 437 © 1997-2003 Fabio HERNANDEZ
  • Méthodes Abstraites Supposons que nous voulons ajouter une méthode à la classe Polygon pour déterminer si un point (x,y) se trouve à lintérieur Le prototype de cette méthode pourrait être bool Polygon::isInside(const Point& aPoint) const Un tel service est facilement implémenté pour certaines sous- classes de Polygon (Triangle, Rectangle, Square) Limplémentation est plus difficile pour un polygone générique une implémentation par défaut nest pas souhaitable Il est néanmoins nécessaire que tous les polygones, cest à dire toutes les sous-classes de Polygon fournissent sa propre implémentation de ce servicePOO en C++: Polymorphisme 438 © 1997-2003 Fabio HERNANDEZ
  • Méthodes Abstraites (suite) Une façon de faire cest dimplémenter le service dans la classe de base avec une implémentation par défaut "vide" bool Polygon::isInside(const Point& aPoint) const { cerr << "You must implement this routine" << endl; return false; } Une autre façon de faire cest de forcer chaque sous-classe à fournir ce service en déclarant la méthode comme abstraite dans la classe de base Une méthode abstraite est une méthode pour laquelle la classe de base ne fournit pas dimplémentationPOO en C++: Polymorphisme 439 © 1997-2003 Fabio HERNANDEZ
  • Méthodes Abstraites (suite) Nous pouvons définir la méthode Polygon::isInside comme abstraite Une méthode abstraite en C++ est aussi appelée virtuelle purePOO en C++: Polymorphisme 440 © 1997-2003 Fabio HERNANDEZ
  • Méthodes Abstraites (suite) class Polygon { public: // Constructors/Destructor Méthode Abstraite ... ou virtuelle pure // Modifiers ... // Selectors virtual bool isInside(const Point& aPoint) const = 0; ... private: // Data members ... };POO en C++: Polymorphisme 441 © 1997-2003 Fabio HERNANDEZ
  • Contrôle dAvancement Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 442 © 1997-2003 Fabio HERNANDEZ
  • Classe Abstraite Une classe ayant au moins une méthode abstraite est appelée classe abstraite Il est impossible de créer une instance dune classe abstraite Cette vérification est effectuée par le compilateur Polygon aPolygon; // ERROR: Polygon has at least one pure virtual // member fonction Les sous-classes (instanciables) de Polygon doivent fournir une implémentation de cette méthodePOO en C++: Polymorphisme 443 © 1997-2003 Fabio HERNANDEZ
  • Classe Abstraite (suite) class Rectangle: public Polygon { public: // Constructors/Destructor ... // Modifiers ... // Selectors virtual bool isInside(const Point& aPoint) const; ... private: // Data members ... };POO en C++: Polymorphisme 444 © 1997-2003 Fabio HERNANDEZ
  • Classe Abstraite (suite) bool Rectangle::isInside(const Point& aPoint) const { if ((origin_.getX() <= aPoint. getX()) && (aPoint. getX() <= (origin_. getX() + side1_)) && (origin_.getY() <= aPoint. getY()) && (aPoint. getY() <= (origin_. getY() + side2_))) return true; return false; }POO en C++: Polymorphisme 445 © 1997-2003 Fabio HERNANDEZ
  • Contrôle dAvancement Motivation Affectation polymorphe Structures de données polymorphes Liaison statique Liaison dynamique Méthodes abstraites Classes abstraites RésuméPOO en C++: Polymorphisme 446 © 1997-2003 Fabio HERNANDEZ
  • Résumé Le polymorphisme permet à une référence ou à un pointeur dêtre associé en temps dexécution à des instances de classes différentes La liaison dynamique est le mécanisme qui permet de déterminer en temps dexécution lutilisation de la redéfinition correcte dune méthode Une méthode abstraite ou virtuelle pure est une méthode pour laquelle la classe de base ne fournit pas dimplémentation Une classe avec une ou plusieurs méthodes abstraites est elle aussi abstraite Il est impossible de créer une instance dune classe abstraitePOO en C++: Polymorphisme 447 © 1997-2003 Fabio HERNANDEZ