Chapitre 4 • héritage et interfaces
Cartouche
| Champ | Valeur |
|---|---|
| Auteur·e | Élise |
| Édition | 2023-09-15 |
| Durée | une journée |
| Taille des équipes | 1 personne |
| Rendu | via git, dépôt 2023_cpp_c4, droits en lecture à delivery_collector |
Barème
| Critère | Points |
|---|---|
| Pikachu | 2 |
| Infirmière Joëlle | 2 |
| Salamèche | 2 |
| Salamèche et l’infirmière | 1 |
| Interface Pokémon | 4 |
| Pokémon Abstrait | 4 |
| Interface AsciiMap | 5 |
| Total des critères | 20 |
| Note maximale | 20 |
| Fautes de norme | -0,5 par faute |
Règlement
La réalisation de cet exercice est assujettie aux règles en vigueur dans l’école en matière de triche et de normalisation. Tricher vous expose à de graves sanctions.
Vous devez être seul·e auteur·e de votre rendu mais vous êtes autorisés et encouragés à communiquer dans le cadre de ce sujet.
Dépôt de référence et norme
Dépôt de référence avec règles clang format.
Tâches
Pikachu
Fichiers à rendre : pkmn/{Pikachu.{cpp,hpp},main.cpp}
Consignes
Dans un namespace pkmn, écrivez une classe Pikachu, avec les fonctions membres suivantes :
speciesrenvoie l’espèce du pokémon dans une chaîne (ici tout le temps “Pikachu”),typerenvoie le type du pokémon dans une chaîne (ici tout le temps “Electric”),namerenvoie le surnom du pokémon que le dresseur à choisi,healthrenvoie une référence vers la santé du Pokémon (par défaut 100 hp)faintedrenvoie une booléen indiquant si oui ou non Pikachu est KO (lorsque 0 HP).
Toutes les chaînes renvoyées doivent être des références constantes.
health doit renvoyer une référence modifiable vers la santé, regardez comment elle est utilisée dans l’exemple.
Enfin, à la construction, un surnom doit être passé pour le Pikachu.
Exemple
void dump_pika(const pkmn::Pikachu &pika) {
std::cout << pika.species() << " -- of type: "
<< pika.type() << " -- named: "
<< pika.name() << "-- hp " << pika.health()
<< std::endl;
std::string_view given_name{pika.name()};
auto numberof_e{std::count(given_name.begin(),
given_name.end(),
'e')};
std::cout << "its name contains " << numberof_e << " time·s the letter e.";
}
int main(void) {
pkmn::Pikachu pika("sbeeve");
dump_pika(pika);
pika.health() -= 10;
dump_pika(pika);
pika.health() -= 90;
std::cout << "has fainted? " << ((pika.fainted()) ? "yes" : "no") << "\n";
}
Sortie du programme :
Pikachu -- of type: Electric -- named: sbeeve -- hp 100
its name contains 3 time·s the letter e.
Pikachu -- of type: Electric -- named: sbeeve -- hp 90
its name contains 3 time·s the letter e.
has fainted? yes
Infirmière Joëlle
Fichiers à rendre : pkmn/{Nurse.{cpp,hpp},main.cpp}
Dans le namespace pkmn, écrivez une classe Nurse avec les fonctions membres :
healprend un pokémon en paramètre et lui rend toute sa santé,namerenvoie le nom de l’infirmière dans une chaîne.
Toutes les infirmières s’appellent “Joy”.
Toutes les chaînes renvoyées doivent être des références constantes.
La fonction heal affiche les phrases suivante sur la sortie standard :
- “There there
$name, you should feel way better now!”:- si la santé était plus petite ou égale à 50 ;
- “That should do it,
$name!”- si la santé est entre 50 et 100 (exclus)
- “You already are in tip-top shape,
$name!”- si le pokémon est en parfaite santé
Remplacez $name par le surnom du Pikachu.
int main(void) {
pkmn::Pikachu pika("Daniel");
pkmn::Nurse nurse;
pika.health() -= 13;
std::cout << pika.health() << std::endl;
nurse.heal(pika);
std::cout << pika.health() << std::endl;
}
87
That should do it, Daniel!
100
Salamèche
Fichiers à rendre : pkmn/{Charmander.{cpp,hpp},main.cpp}
Consignes
Dans un namespace pkmn, écrivez une classe Charmander, avec les fonctions membres suivantes :
speciesrenvoie l’espèce du pokémon dans une chaîne (ici tout le temps “Charmander”),typerenvoie le type du pokémon dans une chaîne (ici tout le temps “Fire”),namerenvoie le surnom du pokémon que le dresseur à choisi,healthrenvoie une référence vers la santé du Pokémon (par défaut 100 hp)faintedrenvoie une booléen indiquant si oui ou non Pikachu est KO (lorsque 0 HP).
Toutes les chaînes renvoyées doivent être des références constantes.
health doit renvoyer une référence modifiable vers la santé, regardez comment elle est utilisée dans l’exemple.
Exemple
void dump_charm(const pkmn::Charmander &charm) {
std::cout << charm.species() << " -- of type: " << charm.type() << " -- named: " << charm.name() << "-- hp " << charm.health() << std::endl;
}
int main(void) {
pkmn::Char charm("Antoine");
dump_charm(charm);
charm.health() -= 10;
dump_charm(charm);
}
Charmander -- of type: Fire -- named: Antoine -- hp 100
Charmander -- of type: Fire -- named: Antoine -- hp 90
Salamèche et l’infirmière
Fichiers à modifier : pkmn/{Nurse.{cpp,hpp},main.cpp}
Ajoutez une fonction membre heal à votre Nurse qui peut soigner Charmander et affiche les mêmes messages que celle qui soigne Pikachu.
Interface Pokémon
Fichiers à rendre : pkmn/{IPokemon.hpp,Pikachu.{cpp,hpp},Charmander.{cpp,hpp},Nurse.{cpp,hpp}}
Contexte
Vous avez peut-être remarqué que l’on est obligés d’avoir une fonction membre en double chez notre Nurse alors qu’elles font la même chose, avec des fonctions membres appelées pareils sur deux classes différentes.
On est dans une situation de sur-spécificité et on peut faire deux choses pour en sortir :
- transformer
healen une fonction template - fusionner les deux fonctions
healet leur faire prendre une interface en paramètre (ce qui induit créer une interface pour nos deux Pokémon)
Ce qui nous intéresse ici c’est la deuxième méthode.
Consignes
Créez une interface donc les fonctions membres sont toutes virtuelles pures et ont la même signature que dans votre Pikachu et votre Charmander.
Ensuite, faites hériter cette interface à Pikachu et Charmander. Rajoutez le mot clé override aux fonctions membres de ses deux-dernier.
Enfin, fusionnez les deux fonctions membres heal de l’infirmière en une seule dont le paramètre est une référence sur IPokemon.
Pokémon Abstrait
Fichiers à rendre : pkmn/{APokemon.{cpp,hpp},Pikachu.{cpp,hpp},Charmander.{cpp,hpp},Nurse.{cpp,hpp}}
Contexte
Malgré notre interface, même s’il n’y a plus de code qui se répète dans celui l’infirmière, il en reste au sein de Pikachu et Charmander.
Avec une classe abstraite il est possible d’implémenter certaines des fonctions d’une interface tout en laissant les autres virtuelles pures (sans les re-déclarer et les surcharger).
Consignes
Écrivez la classe abstraite APokemon qui hérite de IPokemon et dont Pikachu et Charmander doivent hériter.
Copier le code en commun entre les deux Pokémons pour le mettre dans la classe abstraite, et retirez-le de Pikachu et Charmander.
Il est possible qu’après ça, vous n’ayez plus du tout de code dans Pikachu et Charmander. Auquel cas votre classe APokemon ne serait plus réellement un classe abstraite. Que APokemon soit réellement abstraite ou non, ça n’est pas grave pour avoir les points de cet exercice.
AsciiMap interface
Fichiers à rendre : ami/{IAsciiMap.hpp,AsciiMap.{cpp,hpp},AsciiMapClip.{cpp,hpp},main.cpp}
Contexte

Souvenez-vous lorsque vous avec implémenté votre AsciiMap et votre AsciiMapClip dans le chapitre 2, je vous avais donné des exemples qui étaient capables de dessiner soit sur un AsciiMap, soit sur un AsciiMapClip à l’aide de la fonction memberset_cell.
void mk_line(AsciiMap &map, unsigned int y)
{
auto i{0U};
while (i < map.width()) {
if (map.get_cell(i, y) == '|') {
map.set_cell(i, y, '+');
} else {
map.set_cell(i, y, '-');
}
i += 1;
}
}
void draw_x(AsciiMapClip &clip)
{
clip.set_cell(0, 0, '\\');
clip.set_cell(2, 2, '\\');
clip.set_cell(1, 1, 'X');
clip.set_cell(2, 0, '/');
clip.set_cell(0, 2, '/');
}
Le problème ici c’est que draw_x ne peux que marcher si on lui passe un clip et mk_line ne peux que marcher sur une AsciiMap. Même si on utilise des fonctions membres qui existent sur les deux classes. (set_cell et get_cell)
Consignes
Écrivez l’interface IAsciiMap qui définie les fonctions virtuelles pures set_cell et get_cell avec la même signature qu’elles ont sur vos AsciiMap et AsciiMapClip.
Faites hériter AsciiMap et AsciiMapClip de IAsciiMap.
Adaptez les fonctions mk_line et draw_x de sorte à ce qu’elles puissent fonctionner avec n’importe laquelle des deux classes.
Rendez également un main avec lequel vous les avez testées.