Héritage [he] Exercices résolus Karine Zampieri, Stéphane Rivière, Béatrice Amerein-Soltner Unisciel algoprog Version 29 avril 2015 Table des matières 1 Comptes bancaires 1 1.1 Classe CBancaire............................... 1 1.2 Extension de la classe CBancaire...................... 2 1.3 Classe CAvecDecouvert............................ 2 1.4 Classe CRemunere.............................. 3 1.5 Classe CRemunereAvecDecouvert...................... 4 1.6 Transtypage.................................. 5 1.7 Classe déclarée et classe d exécution..................... 6 1 Comptes bancaires 1.1 Classe CBancaire Décrivons la classe permettant de représenter un compte bancaire. Au minimum il faut connaître : Le numéro du compte (que l on représentera par une chaîne de caractères). La somme disponible sur le compte (représentée par un réel). Pour les opérations sur un compte, on se limite aux opérations : De retrait (on décrémente si possible le compte d un montant donné). Le dépôt (on augmente le compte d un montant donné). La consultation (on retourne le solde disponible sur un compte). Dans le cas où un retrait est impossible, on affichera un message et on laissera le compte inchangé. En plus du constructeur par défaut, on fournit également un constructeur permettant de construire un compte en fixant le numéro et le solde initial. Enfin on propose également une méthode qui effectue un virement d un compte vers un autre. Soit donc la définition de cette classe CBancaire définie dans le module @[Classes, objets, instances]. C++ @[hecbancairec1.hpp] @[hecbancairec1.cpp] 1
Unisciel algoprog he00acxres-texte, April 29, 2015 2 Soit le programme ci-après qui permet de tester la classe. C++ @[pg-hecomptec1a.cpp] Testez. 1.2 Extension de la classe CBancaire Supposons que l on souhaite prendre en considération la possibilité d avoir un découvert sur un compte (un retrait conduit à un solde négatif) ou la possibilité d associer une rémunération des dépôts sur un compte (compte rémunéré). Pour ce, on va construire deux classes dérivées : La première permettra de représenter des comptes bancaires avec découvert autorisé. La seconde prendra en compte une possible rémunération du compte. Pour le premier type de compte, il faut préciser quel est le découvert maximum autorisé. Et pour le second type de compte, quel est la rémunération (taux) et, par exemple, quel est le seuil minimal à partir duquel la rémunération s applique. Lors de la construction d une nouvelle classe par extension d une classe existante, on distingue trois sortes de méthodes (ou d attributs). Lesquelles et décrivez-les. Les méthodes (et les attributs) qui sont propres à la nouvelle classe ; il s agit là d extension. Ces méthodes (données) n existent que pour les objets de la nouvelle classe et portent un nom qui n est pas utilisé dans la classe mère ou, un nom déjà utilisé mais avec des paramètres en nombre ou de type différents (il y a alors une surcharge du nom de la méthode). Les méthodes (et les attributs) qui sont issues de la classe mère ; il s agit là d héritage. Ces méthodes (données) sont les mêmes pour les objets de la classe mère et pour les objets de la classe héritée. Par défaut, toute méthode (attribut) est héritée. On notera que lors de l utilisation d une méthode héritée sur un objet de la classe fille il y a une conversion implicite de l objet de la classe fille en un objet de la classe mère. Le code d une méthode (ou la donnée) héritée est soit partagé lorsque la méthode est partagée, soit propre à chaque instance dans le cas contraire (cas par défaut). Les méthodes (ou les attributs, mais cela est plus rare) qui redéfinissent des méthodes (données) existantes dans la classe mère ; il s agit là de masquage. Ces méthodes ont le même nom et le même profil (nombre et type des paramètres, valeur de retour) que les méthodes qu elles redéfinissent. Dans ce cas, la nouvelle méthode se substitue à la méthode de la classe mère. Ceci permet de prendre en compte l enrichissement (ou la spécialisation) que la classe fille apporte par rapport à la classe mère en spécialisant le code de la méthode. Lorsque dans une classe dérivée on souhaite désigner une méthode (ou une donnée) de la classe mère (et en particulier lorsque celle-ci est masquée) on désigne celle-ci en préfixant le nom de la méthode (ou de la variable) par le mot-clé super.
Unisciel algoprog he00acxres-texte, April 29, 2015 3 1.3 Classe CAvecDecouvert Pour cette nouvelle classe nous introduisons une nouvelle donnée : le montant maximum du découvert. Cela nous conduit à modifier la méthode de retrait de telle sorte qu un retrait puisse être effectuer même si le solde n est pas suffisant (il faudra néanmoins que le solde reste plus grand que l opposé du découvert maximal autorisé). Cette méthode de retrait masquera la méthode de même nom de la classe mère. Par ailleurs, on introduira une nouvelle méthode fixerdmax qui permet de modifier le montant du découvert maximum autorisé. Les autres données et méthodes seront reprises telles quelles (par le mécanisme d héritage). Pour la définition du constructeur on utilise le constructeur de la classe mère (par un appel à super). Écrivez une classe CAvecDecouvert qui dérive de la classe CBancaire. Incluez un réel dmax du découvert maximal autorisé. Écrivez le constructeur par défaut. Écrivez un constructeur à trois paramètres initialisant les attributs. Écrivez une méthode fixerdmax(mt) qui fixe le découvert maximal au montant mt (réel). Écrivez une méthode retirer(mt) qui réalise un retrait du montant mt si celui-ci est autorisé, c.-à-d. que le [solde du compte] moins [mt] soit être supérieur à l opposé du découvert maximal autorisé. Dans le cas de la négative, affichez le message : >>> OUPS Provision insuffisante <<< Enfin écrivez une méthode afficher qui affiche les attributs propres à la classe, puis appelle la méthode d affichage de la classe mère pour afficher les attributs hérités. Validez votre classe et vos méthodes avec la solution. C++ @[hecavecdecc1.hpp] @[hecavecdecc1.cpp] Réalisez un copier/coller de la procédure test_decouvert. C++ @[pg-hecomptec1b.cpp] Testez votre classe.
Unisciel algoprog he00acxres-texte, April 29, 2015 4 1.4 Classe CRemunere Pour cette extension, il faut au minimum connaitre le taux de rémunération du compte à partir duquel la rémunération s applique. On suppose que les intérêts sont versés à part et intégrés sur le compte une fois l an. Afin de simplifier l écriture de cette classe, on suppose qu il existe une méthode qui calcule les intérêts (le code est un peu complexe et nécessite la connaissance des dates auxquelles sont faites les opérations afin de calculer les durées pendant lesquels l intérêt s applique). Écrivez une classe CRemunere qui dérive de la classe CBancaire. Incluez un réel taux du taux de rémunération du compte. Écrivez le constructeur par défaut. Écrivez un constructeur à trois paramètres initialisant les attributs. Écrivez une méthode fixertaux(mt) qui fixe le taux au montant mt (réel). Faut-il réécrire la méthode retirer? Non, cela est totalement inutile : c est exactement le même code. Si on redéfinit la méthode, on se contentera de sous-traiter le travail à sa classe mère. Écrivez une méthode calculerinterets() qui cumule les intérêts. Enfin écrivez une méthode afficher qui affiche tous les attributs. Validez votre classe et vos méthodes avec la solution. C++ @[hecremunerec1.hpp] @[hecremunerec1.cpp] 1.5 Classe CRemunereAvecDecouvert On peut alors définir un compte rémunéré avec découvert autorisé. Faites d abord un copier/coller de votre classe CAvecDecouvert en la classe CRemunereAvecDecouvert.
Unisciel algoprog he00acxres-texte, April 29, 2015 5 Modifiez-la de sorte qu elle dérive de la classe CRemunere. Validez votre classe et vos méthodes avec la solution. C++ @[hecrmavecdecc1.hpp] @[hecrmavecdecc1.cpp] Réalisez un copier/coller de la procédure test_remuneredec. C++ @[pg-hecomptec1c.cpp] Testez votre classe. 1.6 Transtypage En programmation fortement typée, le mélange des types n est permis qu avec le respect de règles strictes. La règle liée à la programmation objet est que toute classe est compatible avec ses sous-classes c.-à-d. que si B est une sous-classe de A alors toute variable de type A peut être affectée par une valeur de type B (par une instruction d affectation ou lors d un passage de paramètre). Déclarations Soient les déclarations suivantes : CBancaire c1("cb1", 1000.0); CAvecDecouvert d1("dd1", 6000.0, 0.0); L instruction suivante est-elle valide? Justifiez. c1 = d1 ; Oui, car l objet d1 dérive de l objet c1 : tous les attributs d un CBancaire pourront être initialisés par ceux de CAvecDecouvert. De même, l instruction suivante est-elle valide? Justifiez. d1 = c1 ; Non, elle est incorrecte : les attributs propres à la classe CAvecDecouvert ne peuvent pas être initialisés.
Unisciel algoprog he00acxres-texte, April 29, 2015 6 Que se passe-t-il lors de l instruction : c1.virervers(d1, 100.0) ; CBancaire. Il y aura une conversion implicite de d1 en une valeur de type 1.7 Classe déclarée et classe d exécution Déclarations Soient les déclarations suivantes : CBancaire *c1 = new CBancaire("CB1", 1000.0); CAvecDecouvert *d1 = new CAvecDecouvert("DD1", 6000.0, 0.0); Que se passe-t-il lors des instructions : CBancaire *c2 = d1; c2->afficher(); La variable pointeur c2 pointe vers l objet d1. Mais comme c est un type pointeur de CBancaire, l instruction d affichage appellera la méthode CBancaire::afficher et non pas celle de la classe CAvecDecouvert : l héritage réalise une liaison statique, c.- à-d. une liaison connue à la compilation.