Partie 11: Héritage — Programmation orientée objet en C++

1 621 vues

Publié le

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

Publié dans : Technologie
0 commentaire
3 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
1 621
Sur SlideShare
0
Issues des intégrations
0
Intégrations
3
Actions
Partages
0
Téléchargements
135
Commentaires
0
J’aime
3
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Partie 11: Héritage — Programmation orientée objet en C++

  1. 1. Programmation Orientée Objet en C++ 11ème Partie: Héritage Fabio Hernandez Fabio.Hernandez@in2p3.fr
  2. 2. 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++: Héritage 345 © 1997-2003 Fabio HERNANDEZ
  3. 3. Table des Matières Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 346 © 1997-2003 Fabio HERNANDEZ
  4. 4. Motivation Assez souvent, les nouveaux logiciels sont basés sur des développements précédents Plusieurs approches imitation raffinement combinaison Le modèle objet tient compte de ce fait et offre des mécanismes pour apporter une solution à ce problème Les techniques étudiées jusquà présent ne sont pas suffisantes Les classes constituent une bonne technique de décomposition en modulesPOO en C++: Héritage 347 © 1997-2003 Fabio HERNANDEZ
  5. 5. Motivation (suite) Les classes possèdent plusieurs des qualités demandées aux composants réutilisables modules cohérents séparation entre linterface et limplémentation flexibilité des classes génériques Davantage de qualités sont nécessaires pour atteindre les objectifs de réutilisation et extensibilité Nous avons besoin de mécanismes permettant dexprimer les caractéristiques et le comportement communs existants dans des groupes de structures similaires, mais aussi de tenir compte des différences qui caractérisent les cas particuliersPOO en C++: Héritage 348 © 1997-2003 Fabio HERNANDEZ
  6. 6. Motivation (suite) Une classe peut être une extension, une spécialisation ou une combinaison dautres classes Le modèle objet et les langages orientés objet fournissent des mécanismes offrant des solutions à ces besoins via lhéritage entre classes Lhéritage est un des composants fondamentaux de la technologie objetPOO en C++: Héritage 349 © 1997-2003 Fabio HERNANDEZ
  7. 7. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 350 © 1997-2003 Fabio HERNANDEZ
  8. 8. Classification Nous voulons modéliser les comptes en banque Un compte en banque a plusieurs caractéristiques intéressantes pour notre modèle titulaire numéro didentification solde date de création Quelques opérations sont souhaitables sur un compte obtenir le solde faire un dépôt faire un retrait faire un virement sur un autre compte du même titulairePOO en C++: Héritage 351 © 1997-2003 Fabio HERNANDEZ
  9. 9. Classification (suite) Nous pouvons écrire linterface de la classe compte en banque en C++ comme class BankAccount { public: // Constructors/Destructor BankAccount(const std::string& owner); ~BankAccount(); // Modifiers bool deposit(float amount); bool withdraw(float amount);POO en C++: Héritage 352 © 1997-2003 Fabio HERNANDEZ
  10. 10. Classification (suite) // Selectors float getBalance() const; int getAccountNumber() const; const std::string& getOwner() const; const Date& getCreationDate() const; private: // Data members std::string ownerName_; float balance_; Date creationDate_; int accountNumber_; };POO en C++: Héritage 353 © 1997-2003 Fabio HERNANDEZ
  11. 11. Classification (suite) L’implémentation du constructeur et du destructeur de cette classe serait BankAccount::BankAccount(const std::string& owner) { ownerName_ = owner; balance_ = 0.0; accountNumber_ = . . .; // Do something to assign a // unique account number } BankAccount::~BankAccount() { // Nothing to do }POO en C++: Héritage 354 © 1997-2003 Fabio HERNANDEZ
  12. 12. Classification (suite) Dans le monde réel il existe plusieurs types de comptes en banque compte de chèques compte dépargne plan dépargne logement plan de ... Notre modèle des comptes bancaires devrait refléter cette réalité Nous aurions tendance à modéliser chacun de ces types de comptes comme une classe C++ class CheckingAccount {...}; class SavingAccount{...}; ...POO en C++: Héritage 355 © 1997-2003 Fabio HERNANDEZ
  13. 13. Classification (suite) Comment refléter le fait que tous ces types de comptes ont des caractéristiques communes titulaire solde numéro didentification date de création ... Mais aussi des caractéristiques particulières à chaque type comme la (im)possibilité de retrait taux dintérêt solde minimum ...POO en C++: Héritage 356 © 1997-2003 Fabio HERNANDEZ
  14. 14. Classification (suite) Avec les mécanismes étudiés jusquà présent nous avons deux possibilités: dupliquer le code nécessaire pour modéliser ces caractéristiques communes faire en sorte que la classe modélisant les caractéristiques communes soit contenue dans les autres classes La première possibilité nest pas envisageable parce quelle suppose tous les inconvénients de la duplication de code Considérons la deuxième: la classe SavingAccount contient un attribut de la classe BankAccount la mission de cet attribut est dencapsuler toute linformation relative à un compte bancaire générique (titulaire, solde, ...)POO en C++: Héritage 357 © 1997-2003 Fabio HERNANDEZ
  15. 15. Classification (suite) class SavingAccount { public: // Constructors/Destructor SavingAccount(const std::string& owner); ~SavingAccount(); // Modifiers bool deposit(float amount); bool withdraw(float amount); bool setInterestRate(float newRate);POO en C++: Héritage 358 © 1997-2003 Fabio HERNANDEZ
  16. 16. Classification (suite) // Selectors float getBalance() const; int getAccountNumber() const; const std::string& getOwner() const; const Date& getCreationDate() const; float getInterestRate() const; private: // Data members La classe BankAccount account_; BankAccount est float interestRate_; contenue dans }; SavingAccountPOO en C++: Héritage 359 © 1997-2003 Fabio HERNANDEZ
  17. 17. Classification (suite) Limplémentation des méthodes de la classe SavingAccount serait comme float SavingAccount::getBalance() const { return account_.getBalance(); } Ces méthodes délèguent leur bool SavingAccount::deposit(float amount) implémentation { à lattribut account_ return account_.deposit(amount); }POO en C++: Héritage 360 © 1997-2003 Fabio HERNANDEZ
  18. 18. Classification (suite) Implémentation de la classe SavingAccount (suite) float SavingAccount::getInterestRate() const { return interestRate_; } La classe CheckingAccount pourrait être implémentée dune façon similaire Lavantage de cette approche est la réutilisation sans duplication du code Son principal inconvénient est quune modification dans la classe BankAccount suppose des modifications dans toutes les classes qui utilisent ses services (SavingAccount, CheckingAccount,...)POO en C++: Héritage 361 © 1997-2003 Fabio HERNANDEZ
  19. 19. Classification (suite) Le modèle objet fournit un mécanisme qui permet à une classe dhériter les attributs et méthodes dune autre classe et détendre ses fonctionnalités si nécessaire Dans ce contexte nous pourrions définir la classe SavingAccount comme "une sorte de" BankAccount Ce type de relation entre classes est connu comme une relation est-un (is-a), par opposition à une relation contient-un (has-a) Dans lexemple précédent, la classe SavingAccount contient un BankAccount Regardons maintenant le mécanisme fournit par C++ pour exprimer la relation est-unPOO en C++: Héritage 362 © 1997-2003 Fabio HERNANDEZ
  20. 20. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 363 © 1997-2003 Fabio HERNANDEZ
  21. 21. Spécialisation Nous allons modéliser les classes SavingAccount et CheckingAccount comme une spécialisation de la classe BankAccount BankAccount SavingAccount CheckingAccountPOO en C++: Héritage 364 © 1997-2003 Fabio HERNANDEZ
  22. 22. Spécialisation (suite) class SavingAccount: public BankAccount { public: // Constructors/Destructor Définition de SavingAccount(const char* owner); SavingAccount ~SavingAccount(); comme une // Modifiers spécialisation de BankAccount bool setInterestRate(float newRate); // Selectors float getInterestRate() const; private: // Data members float interestRate_; };POO en C++: Héritage 365 © 1997-2003 Fabio HERNANDEZ
  23. 23. Spécialisation (suite) Un objet de la classe SavingAccount hérite les attributs et services de la classe BankAccount BankAccount SavingAccount ownerName_: std::string balance_: float interestRate_: float creationDate_: Date accountNumber_: int getInterestRate: float deposit: bool setInterestRate: bool withdraw:bool getBalance: float getAccountNumber: int getOwner: std::string getCreationDate: const Date&POO en C++: Héritage 366 © 1997-2003 Fabio HERNANDEZ
  24. 24. Spécialisation (suite) Un objet déclaré comme SavingAccount account; est composé des attributs de la classe BankAccount et de la classe SavingAccount ownerName_: std::string Attributs de la balance_: float partie creationDate_: Date BankAccount accountNumber_: int interestRate_: float Attributs de la partie account SavingAccountPOO en C++: Héritage 367 © 1997-2003 Fabio HERNANDEZ
  25. 25. Spécialisation (suite) De façon similaire, un objet de la classe SavingAccount hérite les services de la classe BankAccount Nous pouvons donc écrire // Create a SavingAccount object SavingAccount account("Jacques Cousteau"); // Deposit an amount into this account account.deposit(500.0); // Print its new balance cout << "The balance is " << account.getBalance(); // Set its interest rate account.setInterestRate(0.03);POO en C++: Héritage 368 © 1997-2003 Fabio HERNANDEZ
  26. 26. Spécialisation (suite) BankAccount deposit: bool Classe de base ou withdraw: bool SuperClasse getBalance: float getAccountNumber: int getOwner: std::string getCreationDate: const Date& SavingAccount Classe dérivée ou setInterestRate: bool Sous-Classe getInterestRate: floatPOO en C++: Héritage 369 © 1997-2003 Fabio HERNANDEZ
  27. 27. Spécialisation (suite) Limplémentation de la classe SavingAccount est composée des fonctions membres particulières à cette classe bool SavingAccount::setInterestRate(float newRate) { interestRate_ = newRate; return true; } // Constructor SavingAccount::SavingAccount(const std::string& owner) : BankAccount(owner) Initialisation de { la partie interestRate_ = 0.0; BankAccount }POO en C++: Héritage 370 © 1997-2003 Fabio HERNANDEZ
  28. 28. Spécialisation (suite) La liste dinitialisation des attributs est utilisée pour passer les arguments nécessaires au constructeur de la classe de base Dans cet exemple BankAccount na pas de constructeur par défaut SavingAccount est une spécialisation de BankAccount Pour créer un objet de la classe SavingAccount il est nécessaire dinitialiser sa partie BankAccount Si la classe de base a un constructeur par défaut et la liste dinitialisation des attributs nest pas spécifiée, cest le constructeur par défaut qui sera utilisé pour créer la partie de lobjet correspondante à la classe de basePOO en C++: Héritage 371 © 1997-2003 Fabio HERNANDEZ
  29. 29. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 372 © 1997-2003 Fabio HERNANDEZ
  30. 30. Redéfinition des fonctions membres Limplémentation de BankAccount::withdraw pourrait être bool BankAccount::withdraw(float amount) { if (balance_ < amount) return false; balance_ -= amount; return true; } Celle-ci est une implémentation générique dune opération de retraitPOO en C++: Héritage 373 © 1997-2003 Fabio HERNANDEZ
  31. 31. Redéfinition des fonctions membres (suite) Certains types de comptes bancaires imposent des restrictions sur le montant du retrait le solde minimum ... Cest le cas de notre compte dépargne: un compte de ce type exige un solde minimum La fonction membre BankAccount::withdraw ne peut pas être utilisée telle quelle par la classe SavingAccount SavingAccount doit définir sa propre opération SavingAccount::withdrawPOO en C++: Héritage 374 © 1997-2003 Fabio HERNANDEZ
  32. 32. Redéfinition des fonctions membres (suite) class SavingAccount: public BankAccount { public: // Constructors/Destructor SavingAccount(const std::string& owner); ~SavingAccount(); // Modifiers bool setInterestRate(float newRate); bool withdraw(float amount); // Selectors Redéfinition de float getInterestRate() const; BankAccount::withdraw private: // Data members float interestRate_; };POO en C++: Héritage 375 © 1997-2003 Fabio HERNANDEZ
  33. 33. Redéfinition des fonctions membres (suite) bool SavingAccount::withdraw(float amount) { const float MinimumBalance = 500.0; if ((getBalance() - MinimumBalance) < amount) return false; return BankAccount::withdraw(amount); } Appel explicite à la fonction membre withdraw de la classe de basePOO en C++: Héritage 376 © 1997-2003 Fabio HERNANDEZ
  34. 34. Redéfinition des fonctions membres (suite) BankAccount deposit: bool withdraw: bool getBalance: float getAccountNumber: int La sous-classe getOwner: const std::string spécialise une des creationDate: const Date& fonctions membres de la classe de base SavingAccount setInterestRate: bool getInterestRate: float withdraw: boolPOO en C++: Héritage 377 © 1997-2003 Fabio HERNANDEZ
  35. 35. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 378 © 1997-2003 Fabio HERNANDEZ
  36. 36. Conversions standards Quelques conversions standards sont appliquées entre un objet dune sous-classe et sa classe de base valable uniquement dans le cas dhéritage avec attribut public Un objet de la sous-classe peut être implicitement traité comme un objet de la classe de base Un pointeur (ou une référence) à un objet de la sous-classe peut être traité comme un pointeur (ou une référence) à un objet de la classe de base SavingAccount savingsAccount("Tantine Riche"); // the savingsAccount object is a kind of BankAccount BankAccount* bankAccountPtr = &savingsAccount; BankAccount& bankAccountRef = &savingsAccount;POO en C++: Héritage 379 © 1997-2003 Fabio HERNANDEZ
  37. 37. Conversions standards (suite) Un objet dune classe dérivée est composé dune partie correspondante à la classe de base dune partie spécifique à la sous-classe Ces conversions implicites sont acceptées parce qu’un objet dune classe dérivée "contient" un objet de la classe de basePOO en C++: Héritage 380 © 1997-2003 Fabio HERNANDEZ
  38. 38. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 381 © 1997-2003 Fabio HERNANDEZ
  39. 39. Contrôle daccès Bien que lattribut BankAccount::balance_ soit un des composants de la classe SavingAccount, aucune des fonctions membres de SavingAccount ny a accès, parce quil a été déclaré privé Si nous ajoutons la fonction membre computeProfit à la classe SavingAccount float SavingAccount::computeProfit() const { // COMPILATION ERROR: balance_ is a private // attribute of BankAccount return interestRate_ * balance_; }POO en C++: Héritage 382 © 1997-2003 Fabio HERNANDEZ
  40. 40. Contrôle daccès (suite) Nous devons écrire float SavingAccount::computeProfit() const { return interestRate_ * getBalance(); } Utilisation de BankAccount::getBalance()POO en C++: Héritage 383 © 1997-2003 Fabio HERNANDEZ
  41. 41. Contrôle daccès (suite) Il est parfois souhaitable quune fonction membre dune sous- classe ait accès directement aux attributs de la classe de base Un attribut ou méthode déclaré protected est accessible uniquement par les sous-classes class BankAccount { public: ... protected: Ce mécanisme donne // Data members accès aux données std::string& ownerName_; membres de float balance_; BankAccount à Date creationDate_; toutes ses sous- int accountNumber_; classes };POO en C++: Héritage 384 © 1997-2003 Fabio HERNANDEZ
  42. 42. Contrôle daccès (suite) Les fonctions membres de SavingAccount ont maintenant accès aux données membres de la partie de l ’objet correspondante à la classe BankAccount float SavingAccount::computeProfit() const { // OK: balance_ is a protected attribute // of BankAccount return interestRate_ * balance_; } Cependant laccès à ces attributs reste toujours restreint BankAccount account; account.balance_ = 200.0; // COMPILATION ERROR: balance_ is protectedPOO en C++: Héritage 385 © 1997-2003 Fabio HERNANDEZ
  43. 43. Contrôle daccès (suite) Un attribut(fonction) membre déclaré(e) protected est accessible par les fonctions membres dune classe dérivée, mais il(elle) reste privé(e) pour le reste du programmePOO en C++: Héritage 386 © 1997-2003 Fabio HERNANDEZ
  44. 44. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 387 © 1997-2003 Fabio HERNANDEZ
  45. 45. Classe abstraite Nous avons créé la classe BankAccount afin de "factoriser" les attributs et le comportement communs de tous les types de comptes en banque dans le but de les réutiliser dans les sous- classes En conséquent, nous ne devrions pas avoir besoin de créer un objet de la classe BankAccount comme dans BankAccount account("Marcel Marceau"); cout << account.getBalance() << endl; puisquil ne représente pas un objet du domaine du problème que nous modélisons Autrement dit, cette classe na lieu dexister quen tant que composante dune classe dérivée comme SavingAccount ou CheckingAccountPOO en C++: Héritage 388 © 1997-2003 Fabio HERNANDEZ
  46. 46. Classe abstraite (suite) Nous pouvons utiliser les mécanismes de contrôle daccès pour empêcher quune instance de la classe BankAccount puisse être créée class BankAccount { public: // Modifiers bool deposit(float amount); bool withdraw(float amount); // Selectors float getBalance() const; int getAccountNumber() const; const std::string& getOwner() const; const Date& getCreationDate() const;POO en C++: Héritage 389 © 1997-2003 Fabio HERNANDEZ
  47. 47. Classe abstraite (suite) protected: // Constructors/Destructor BankAccount(const std::string& owner); ~BankAccount(); Impossible de créer une // Data members instance de cette classe: std::string ownerName_; le constructeur et le float balance_; destructeur sont protégés Date creationDate_; int accountNumber_; };POO en C++: Héritage 390 © 1997-2003 Fabio HERNANDEZ
  48. 48. Classe abstraite (suite) Maintenant, les services de la classe BankAccount ne peuvent être utilisés que par ses sous-classes #include "BankAccount.h" int main() { BankAccount account("Marcel Marceau"); // COMPILATION ERROR: the constructor // of BankAccount is protected return 0; }POO en C++: Héritage 391 © 1997-2003 Fabio HERNANDEZ
  49. 49. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 392 © 1997-2003 Fabio HERNANDEZ
  50. 50. Redéfinition des opérateurs Une sous-classe hérite toutes les fonctions membres de sa classe de base sauf les constructeurs le destructeur les opérateurs Les constructeurs ne sont pas hérités directement mais sont utilisés dans la liste dinitialisation des constructeurs de la sous-classe Le destructeur est utilisé automatiquement à la destruction de lobjet Les opérateurs doivent être redéfinis par la sous-classe en appelant ceux de la classe de basePOO en C++: Héritage 393 © 1997-2003 Fabio HERNANDEZ
  51. 51. Redéfinition des opérateurs (suite) class Base { public: ... bool operator==(const Base& aBase) const; Base& operator=(const Base& aBase); ... private: int data_; };POO en C++: Héritage 394 © 1997-2003 Fabio HERNANDEZ
  52. 52. Redéfinition des opérateurs (suite) bool Base::operator==(const Base& aBase) const { return (data_ == aBase.data_) ? true : false; } Base& Base::operator=(const Base& aBase) { if (this == &aBase) return *this; data_ = aBase.data_; return *this; }POO en C++: Héritage 395 © 1997-2003 Fabio HERNANDEZ
  53. 53. Redéfinition des opérateurs (suite) class Derived: public Base { public: ... bool operator==(const Derived& aDerived) const; Derived& operator=(const Derived& aDerived); ... private: float ratio_; };POO en C++: Héritage 396 © 1997-2003 Fabio HERNANDEZ
  54. 54. Redéfinition des opérateurs (suite) bool Derived::operator==(const Derived& aDerived) const { return ( Base::operator==(aDerived) && (ratio_ == aDerived.ratio_)) ? true : false; } Derived& Derived::operator=(const Derived& aDerived) { if (this == &aDerived) return *this; Utilisation des Base::operator=(aDerived); opérateurs de la ratio_ = aDerived.ratio_; classe de base dans limplémentation des return *this; opérateurs de la sous- } classePOO en C++: Héritage 397 © 1997-2003 Fabio HERNANDEZ
  55. 55. Contrôle davancement Motivation Classification Spécialisation Redéfinition des fonctions membres Conversions standards Contrôle daccès Classe abstraite Redéfinition des opérateurs RésuméPOO en C++: Héritage 398 © 1997-2003 Fabio HERNANDEZ
  56. 56. Résumé Lhéritage permet de définir de nouvelles classes par extension, spécialisation ou combinaison dautres déjà définies Une classe dérivée (ou sous-classe) hérite ses attributs et fonctions membres de la classe de base(ou super-classe) Une sous-classe peut redéfinir les fonctions membres de la classe de base Des mécanismes de contrôle daccès permettent aux sous- classes daccéder aux attributs de la classe de base tout en préservant lencapsulation Une classe abstraite en est une qui ne peut être utilisée que comme classe de base Les opérateurs doivent être redéfinis par les sous-classesPOO en C++: Héritage 399 © 1997-2003 Fabio HERNANDEZ

×