Big Tuto : Apprenez le C++

Chapitre 26 : L'héritage (2)

 

Tutoriel présenté par : Robert Gillard (Gondulzac)
Date de publication : 4 février 2017
Date de révision : -

 

Retrouvez les projets complets de ce chapitre :

  

 

 

  Préliminaires

 

   Après nous être arrêtés aux appels de constructeurs / destructeurs dans les classes de base et classes dérivées, nous poursuivons notre étude sur l'Héritage par la notion de surcharge de constructeurs dans ces mêmes classes. wink

 


   1.0 – L'Héritage simple ( suite)

      1.1 – Surcharge de constructeurs dans les classes de base et classes dérivées

 

   Dans le chapitre 15, § 7.2, nous avons vu que nous pouvions surcharger un constructeur par défaut avec un nombre de paramètres différents.

   Nous avions pris l'exemple d'une classe ''Player'' qui pourrait avoir un constructeur ayant le nom et la race du héros, soit Player(string, string). Un autre constructeur pourrait avoir le nom et l'age du héros, soit Player(string, int). Un autre pourrait recevoir les trois paramètres ou encore un autre avec un seul paramètre. wink

   Avec l'héritage, nous pouvons également utiliser ces fonctionnalités. Nous allons montrer ceci dans un exemple reprenant une classe de base Personnage et une classe dérivée Guerrier dans lesquelles nous allons surcharger le constructeur par défaut avec divers paramètres.

 

   Projet 152HeritageSimple_5

      Fichier : Personnage.h  

 

//Projet 152HeritageSimple_5
//Héritage simple - Constructeurs surchargés de classes de base/dérivées
//fichier Personnage.h
#ifndef DEF_PERSONNAGE
#define DEF_PERSONNAGE
 
#include <string>
 
using uint = unsigned int;
 
//Déclaration de la classe Personnage
class Personnage
{
public:
 
//Constructeur par défaut
Personnage();
 
//Constructeurs surchargés
Personnage(std::string nom);
Personnage(std::string nom, std::string race);
 
~Personnage();
 
//Méthodes membres d'accès publique
std::string get_Race() const { return _race; }
std::string get_Name() const { return _nom; }
uint get_Vie() const { return _qte_Vie; }
 
 
//Autres Fonctions
void recevoirDegats(uint degats) { _qte_Vie -= degats; }
 
void frapperAvecLesPoings(Personnage &autre) const
{
autre.recevoirDegats(2);
}
 
void avancer() { std::cout << "Le personnage " << get_Name() << " avance d'un pas" << std::endl; }
void reculer() { std::cout << "Le personnage " << get_Name() << " recule d'un pas" << std::endl; }
void crier() const { std::cout << "Le Personnage " << get_Name() << " crie : Whooo" << std::endl; }
 
 
protected:
 
uint _qte_Vie;
std::string _nom;
std::string _race;
 
};
 
 
 
Personnage::Personnage()
{
std::cout << "Constructeur par defaut de Personnage..." << std::endl;
}
 
 
Personnage::Personnage(std::string nom) : _nom(nom)
{
std::cout << "Constructeur surcharge de personnage (string)..." << std::endl;
}
 
 
Personnage::Personnage(std::string nom, std::string race) : _nom(nom), _race(race)
{
std::cout << "Constructeur surcharge de personnage (string, string)..." << std::endl;
}
 
 
Personnage::~Personnage() { std::cout << "Destructeur de Personnage..." << std::endl; };
 
#endif 

 

   Dans la classe Personnage, nous créons un constructeur par défaut ainsi que deux constructeurs surchargés. Le premier des constructeurs surchargés prend le nom d'un Personnage en paramètre et l'autre prend le nom et la race d'un Personnage en paramètre.

   Suivent quelques méthodes membres d'accès publique ainsi que quelques autres fonctions habituelles. smiley

   Tous les constructeurs surchargés ainsi que le destructeur sont définis en dehors de la classe. La forme de leur implémentation vous est connue et ne doit pas vous causer de problème (normalement cheeky ).

 

      Fichier : Guerrier.h 

 

//Projet 152HeritageSimple_5
//Héritage simple - Constructeurs surchargés de classes de base/dérivées
//fichier Guerrier.h
#ifndef DEF_GUERRIER
#define DEF_GUERRIER
 
#include <iostream>
using uint = unsigned int;
 
//Déclaration de la classe Guerrier
class Guerrier : public Personnage
{
public:
 
//Constructeur par défaut
Guerrier()
{
std::cout << "Constructeur par defaut de Guerrier..." << std::endl;
}
 
//Constructeurs surchargés
Guerrier(std::string nom);
Guerrier(std::string nom, std::string race);
Guerrier(std::string nom, std::string race, std::string arme);
Guerrier(std::string nom, std::string race, std::string arme, uint vie);
 
//Destructeur de Guerrier
~Guerrier();
 
//Méthode membre d'accès publique
std::string get_Arm() const { return _arme; }
 
//Autre fonction
void coup_d_Epee(Personnage &autre) const
{
autre.recevoirDegats(10);
}
 
 
protected:
 
std::string _arme;
 
};
 
 
Guerrier::Guerrier(std::string nom) : Personnage(nom)
{
std::cout << "Constructeur surcharge de Guerrier (string)..." << std::endl;
}
 
 
Guerrier::Guerrier(std::string nom, std::string race) : Personnage(nom, race)
{
std::cout << "Constructeur surcharge de Guerrier (string, string)..." << std::endl;
}
 
 
Guerrier::Guerrier(std::string nom, std::string race, std::string arme) : Personnage(nomrace)
{
std::cout << "Constructeur surcharge de Guerrier (string, string, string)..." << std::endl;
_arme = arme;
}
 
 
Guerrier::Guerrier(std::string nom, std::string race, std::string arme, uint vie) : Personnage(nom, race)
{
std::cout << "Constructeur surcharge de Guerrier (string, string, string, unsigned int)..." << std::endl;
_arme = arme;
_qte_Vie = vie;
}
 
 
Guerrier::~Guerrier()
{
std::cout << "Destructeur de Personnage..." << std::endl;
}
 
#endif  

 

   La classe Guerrier déclare un constructeur par défaut et quatre constructeurs surchargés. Le premier prend le nom d'un Guerrier en paramètre, le second prend le nom et la race, le troisième prend le nom, la race, le nom de son arme et le quatrième prend le nom, la race, le nom de l'arme et le nombre de points de vie du Guerrier en paramètres.

   Les constructeurs et le destructeur sont également définis en dehors de la classe. wink

   Le constructeur surchargé qui prend un nom de guerrier en paramètre, initialise d'abord sa classe de base en lui passant la variable nom en paramètre.

   Le constructeur surchargé qui prend un nom de guerrier et une race en paramètre initialise premièrement sa classe de base en lui passant les variables nom et race en paramètres.

   Le constructeur surchargé qui prend un nom de guerrier, la race et le nom d'une arme en paramètre initialise d'abord le constructeur de sa classe de base avec le nom et la race en paramètres puis initialise la variable arme de sa classe.

   Pour terminer, le dernier constructeur initialise le constructeur de la a classe de base avec le nom et la race en paramètres puis initialise les variables arme et vie de sa classe.

 


      Fichier : HeritageSimple_5.cpp

 

//Projet 152HeritageSimple_5
//Héritage simple - Constructeurs surchargés de classes de base/dérivées
//fichier HeritageSimple_5.cpp
 
#include <iostream>
 
#include "Personnage.h"
#include "Guerrier.h"
 
using namespace std;
 
 
int main()
{
 
cout << endl;
//Création d'un objet unPersonnage
int vie(0);
Personnage unPersonnage("Elwyn", "ELFE");
cout << "Le personnage " << unPersonnage.get_Name() << " est un " << unPersonnage.get_Race() << endl;
cout << endl;
 
//Création d'un objet Guerrier
Guerrier guerrier_1;
cout << "Creation d'un objet Guerrier" << endl;
cout << endl;
 
//Création d'un objet Guerrier (string)
cout << endl;
Guerrier guerrier_2("Tarek");
cout << "Un guerrier se nomme " << guerrier_2.get_Name() << endl;
cout << endl;
 
//Création d'un objet Guerrier (string, string)
Guerrier guerrier_3("Urak", "ORC");
cout << guerrier_3.get_Name() << " est un guerrier " << guerrier_3.get_Race() << endl;
cout << endl;
 
//Création d'un objet Guerrier (string, string, string)
Guerrier guerrier_4("Raniek", "ORC", "Epee");
cout << guerrier_4.get_Name() << " est un " << "guerrier " << guerrier_4.get_Race();
cout << ", Il se bat avec une " << guerrier_4.get_Arm() << endl;
cout << endl;
 
//Création d'un objet Guerrier (string, string, string unsigned int)
 
Guerrier guerrier_5("Tarek", "ORC", "Epee", 100);
cout << guerrier_5.get_Name() << " est un " << "guerrier " << guerrier_5.get_Race();
cout << ", Il se bat avec une " << guerrier_5.get_Arm();
cout << " et possede " << guerrier_5.get_Vie() << " pdV" << endl;
cout << endl;
 
cin.get();
return 0;
} 

 

   A l'aide du second constructeur surchargé de Personnage, on crée premièrement un objet de type Personnage en lui passant un nom et une race en paramètres. On utilise ensuite les méthodes membres d'accès publique get_Name() et get_Race() pour afficher le nom et la race.

   Pour créer l'objet guerrier_1, le constructeur par défaut de la classe Guerrier appelle en premier le constructeur par défaut de la classe Personnage.

   Pour la création de l'objet guerrier_2, le constructeur surchargé de Personnage est d'abord appelé avec sa variable nom en paramètre. Le constructeur surchargé de la classe Guerrier est ensuite appelé.

   Pour créer l'objet guerrier_3, le constructeur surchargé de Personnage est d'abord appelé avec ses variables nom et race en paramètre. Le constructeur surchargé de la classe Guerrier est ensuite appelé.

   Pour la création de l'objet guerrier_4, le constructeur surchargé de Personnage est d'abord appelé avec ses variables nom et race en paramètres. Le constructeur surchargé de Guerrier initialise ensuite sa variable _arme.

   L'objet guerrier_5 est initialisé avec 4 variables. Les variables nom et race sont premièrement initialisées par le constructeur surchargé de Personnage et ensuite les variables _arme et qteVie sont initialisées par le constructeur surchargé de Guerrier.

   Il est très important de bien comprendre ce processus : Un objet d'une classe dérivée est créé par l'appel du constructeur de sa classe de base qui utilisera ses propres variables de type protectedwink

   L'objet créé pourra donc utiliser les variables (et méthodes) de la classe de base ainsi que ses propres variables et méthodes, initialisées par le constructeur de sa propre classe.

   Ce qui affiche dans la console : 

 

 

 

 

   1.2 – Redéfinir une méthode de classe de base dans une classe dérivée

 

   Reportons-nous quelques instants au chapitre 25, § 1.2 (Manipulation d' objets de classes de bases et de classes dérivées).

   Dans le projet 148HeritageSimple_1 et plus précisément dans la classe Personnage du fichier ''Personnage.h'', nous implémentions la fonction suivante :  

 

void crier() const { std::cout << "Whooo" << std::endl; } 

 

   Cette fonction permettait d'afficher le cri d'un personnage mais également d'un objet ''Guerrier'', la classe Guerrier héritant de la classe Personnage.

   La fonction crier() :

 

cout << "Un personnage crie : ";
unPersonnage.crier();
 
cout << "Un guerrier crie : ";
unGuerrier.crier(); 

     

   ...permettait donc d'afficher un même cri pour le personnage et le guerrier (''Whoo''), ce qui est normal, la classe Guerrier étant une classe dérivée de la classe Personnage, un objet Guerrier a donc accès aux méthodes publiques de sa classe mère.

   Supposons maintenant que le cri d'un guerrier soit différent du cri d'un personnage, comment pouvons nous modifier ce cri ? surprise

   Et bien dans ce cas nous pouvons redéfinir la méthode crier() de la classe Personnage à l'intérieur de la classe dérivée Guerrier. Nous allons le montrer dans l'exemple suivant en ne modifiant que ce qui est nécessaire.

 


   Projet 153HeritageSimple_6

 

   La classe Personnage est identique à celle du projet 148HeritageSimple_1, nous n'écrivons donc ici que le fichier ''Guerrier.h''

   Fichier : Guerrier.h 

 

//Projet 153HeritageSimple_6
//Héritage simple – Redéfinition d'une méthode de classe de base dans une classe dérivée.
//fichier Guerrier.h
 
#ifndef DEF_GUERRIER
#define DEF_GUERRIER
 
#include <iostream>
using uint = unsigned int;
 
//Déclaration de la classe Guerrier
class Guerrier : public Personnage
{
public:
 
//Constructeur et destructeur
Guerrier() {};
~Guerrier() {};
 
//Autres fonctions
void coup_d_Epee(Personnage &autre) const
{
autre.recevoirDegats(10);
}
 
void crier() const { std::cout << "Arrrrgh" << std::endl; }
 
 
protected:
 
};
 
#endif 

 

   La fonction crier() est redéfinie dans la classe Guerrier. Le cri du guerrier est plus sauvage que le cri d'un personnage (''Arrrrgh''). laugh

   La fonction main() étant identique dans les deux projets, nous n'afficherons cependant ici que le résultat dans la console après les cris des objets ''unPersonnage'' et ''unGuerrier''.

 

 

 

Remarque : Le prototype de la fonction redéfinie dans la classe dérivée doit correspondre exactement au prototype de la fonction de la classe mère. Ceci veut dire que la liste des paramètres de la fonction à redéfinir ainsi que le mot-clé const s'il est présent, doivent se retrouver à l'identique dans la méthode redéfinie de la classe dérivée .

 


      1.3 – Masquer une méthode de classe de base

 

   Dans l'exemple précédent, la méthode crier() redéfinie dans la classe Guerrier masque la méthode crier() de la classe Personnage. Cela est très bien ainsi, nous voulions ''entendre'' le cri du guerrier. angel

   Il y a cependant une importante exception qui pourrait causer problème. Si nous surchargeons une ou plusieurs méthodes dans une classe de base et que l'une de ces méthodes surchargées est redéfinie dans une classe dérivée, nous ne pourrons plus avoir accès aux autres méthodes surchargées de la classe de base à partir d'un objet de la classe dérivée ! surprise

   Nous n'avons dès lors qu'une seule solution : Nous devons redéfinir toutes les méthodes surchargées de la classe mère à l'intérieur de la classe fille. frown

   Voyons ceci dans un exemple :

 

   Projet 154HeritageSimple_7

      Fichier HeritageSimple_7.cpp  

 

//projet 154HeritageSimple_7
//Fichier : HeritageSimple.cpp
//Masquage d'une méthode de classe de base
//Méthodes surchargées
#ifndef HERITAGE_SIMPLE_7
#define HERITAGE_SIMPLE_7
 
#include <iostream>
 
using namespace std;
 
class Personnage
{
public:
 
void Sprinter() const
{
std::cout << "Un personnage realise une course de 100 metres" << std::endl;
}
 
void Sprinter(int distance) const
{
std::cout << "Un personnage realise une course de " << distance << " metres";
std::cout << std::endl;
}
 
protected:
 
};
 
 
class Sportif : public Personnage
{
public:
 
void Sprinter() const
{
std::cout << "Un sportif realise une course de 800 metres" << std::endl;
}
 
};
 
#endif
 
 
int main()
{
Personnage unPersonnage;
Sportif unSportif;
 
std::cout << std::endl;
unPersonnage.Sprinter();
unPersonnage.Sprinter(400);
std::cout << std::endl;
 
unSportif.Sprinter();
unSportif.Sprinter(1000); //Erreur... la fonction ne prend pas 1 argument !
std::cout << std::endl;
 
cin.get();
return 0;
} 

 

   Dans la classe Personnage, nous définissons une méthode Sprinter() sans paramètre. Nous surchargeons cette fonction en lui passant une variable dénommée ''distance'' en paramètre.

   Dans la classe Sportif nous redéfinissons la méthode Sprinter() sans paramètre.

   On passe à la fonction main() où nous créons un objet unPersonnage et un objet unSportif.

   Nous appliquons les méthodes Sprinter() et Sprinter(int) à l'objet unPersonnage ainsi que la méthode Sprinter() à l'objet unSportif. La fonction Sprinter(int) ne peut cependant pas s'appliquer à l'objet unSportif car le compilateur nous indique que la fonction ne prend pas d'argument. Ce programme ne pourra donc pas être compilé, la méthode non redéfinie dans la classe mère est cachée à l'objet de la classe fille. Si nous n'avions pas redéfini la méthode Sprinter() sans paramètre dans la classe Sportif, l'objet unSportif aurait pu appeler la méthode de la classe de base.

   Pour que l'objet unSportif puisse utiliser la méthode Sprinter(int), il nous faut également redéfinir celle-ci dans la classe dérivée. wink

  

class Sportif : public Personnage
{
public:
 
void Sprinter() const
{
std::cout << "Un sportif realise une course de 800 metres" << std::endl;
}
 
void Sprinter(int distance) const
{
std::cout << "Un sportif realise une course de " << distance << " metres";
std::cout << std::endl;
}
 
};

 

   Le programme pouvant alors être compilé sans erreur.

 

int main()
{
Personnage unPersonnage;
Sportif unSportif;
 
std::cout << std::endl;
unPersonnage.Sprinter();
unPersonnage.Sprinter(400);
std::cout << std::endl;
 
unSportif.Sprinter();
unSportif.Sprinter(1000);
std::cout << std::endl;
 
cin.get();
return 0;

 

   Ce qui donne comme résultat dans la console :

 

 

     Allez, un petit exercice angel :

   Réécrivez l'exemple ci-dessus en y ajoutant les méthodes membres avancer(), reculer() et crier() du projet 148HeritageSimple_1 du chapitre 25 que vous placerez dans la classe Personnage. Vous redéfinirez ces méthodes dans la classe Sportif. Passez également une variable nb_pas en paramètre aux méthodes avancer() et reculer() et faites pousser un cri différent à un personnage et un sportifwink

 

 


      1.4 – Appeler une méthode d'une classe de base à partir d'un objet d'une classe dérivée

 

   Nous pouvons appeler une méthode d'une classe de base à partir d'un objet d'une classe dérivée à l'aide de l'opérateur de résolution de portée.

   Ce qui d'une manière générale s'écrit :

Objet_classe_dérivée.nom_classe_de_base::méthode_membre_classe_de_base

   Si nous reprenons notre projet précédent, nous allons voir que nous aurions pu appeler la méthode de la classe de base en écrivant :

unSportif.Personnage::Sprinter(1000)

   et permettre ainsi au programme d'être compilé.

   Une méthode d'une classe dérivée peut également appeler elle-même une méthode de classe de base, nous allons voir tout cela dans l'exemple suivant wink :

 


      Projet 155HeritageSimple_8 

 

//projet 155HeritageSimple_8
//Fichier : HeritageSimple.cpp
//Appel d'une méthode de classe de base
 
#ifndef HERITAGE_SIMPLE_8
#define HERITAGE_SIMPLE_8
 
#include <iostream>
 
using namespace std;
 
class Personnage
{
public:
 
void Sprinter() const
{
std::cout << "Un personnage realise une course de 100 metres" << std::endl;
}
 
void Sprinter(int distance) const
{
std::cout << "Un personnage realise une course de " << distance << " metres";
std::cout << std::endl;
}
 
protected:
 
};
 
 
class Sportif : public Personnage
{
public:
 
void Sprinter() const
{
std::cout << "Appel de la Methode Sprinter(int) de la classe Personnage" << endl;
std::cout << "par une methode de la classe Sportif" << endl;
Personnage::Sprinter(800);
}
 
};
 
#endif
 
 
int main()
{
Personnage unPersonnage;
Sportif unSportif;
 
std::cout << std::endl;
unPersonnage.Sprinter();
unPersonnage.Sprinter(400);
std::cout << std::endl;
 
unSportif.Sprinter();
cout << endl;
cout << "Et dans la fonction main() on appelle la methode Sprinter(int) de la" << endl;
cout << "classe Personnage par un objet de la classe derivee" << endl;
unSportif.Personnage::Sprinter(1000);
std::cout << std::endl;
 
cin.get();
return 0;
}

 

   Allez, on compare avec l'exemple précédent. On ne touche pas à la classe Personnage, celle-ci contient toujours une fonction membre Sprinter() et une fonction surchargée Sprinter(int).

   Par contre, dans la classe Sportif, nous n'avons pas redéfini la méthode Sprinter(int) de la classe de base, nous n'en avons pas besoin pour notre exemple.

   Dans la classe Sportif, la méthode Sprinter() sans paramètre a été modifiée en ceci que cette fonction peut elle-même appeler la méthode Sprinter(int) de la classe Personnage. Il s'agit d'une des fonctionnalités de C++ qui permet à une méthode d'une classe dérivée d'appeler des méthodes définies dans sa classe de base. wink

   Et dans la fonction main(), un objet unSportif appelle directement une méthode de la classe Personnage par l'intermédiaire de l'opérateur de résolution de portée qui permet d'atteindre cette méthode.

   Voyons les résultats dans la console :

 

 

 

 

   1.5 – Méthodes virtuelles

 

   Les méthodes virtuelles sont à la base du polymorphisme. Ce terme, issu du grec (poly = plusieurs) et (morphe = forme), permet la liaison d'objets de classes dérivées avec des pointeurs sur une classe de base.

   Nous consacrerons le chapitre 27 à détailler ce qu'est le polymorphisme mais auparavant, nous introduirons la notion de méthode virtuelle en montrant dans un premier temps les limites de l'héritage simple et comment y remédier par l'utilisation de ces méthodes virtuelles. angel

   Nous allons créer une classe Personnage et en faire dériver deux classes filles, les classes Guerrier, et Druide, par exemple. cheeky

   Nous allons ainsi demander à chacun d'entre-eux, dans un exemple, de faire une courte présentation de leurs qualités. angel

 


   Projet 156HeritageSimple_9

      Fichier Personnage.h 

 

//Projet 156HeritageSimple_9
//Héritage simple - Redéfinition de méthodes (2)
//fichier Personnage.h
#ifndef DEF_PERSONNAGE
#define DEF_PERSONNAGE
 
//Déclaration de la classe Personnage
class Personnage
{
public:
 
//Constructeur et destructeur
Personnage() {};
~Personnage() {};
 
void Se_Presenter() const
{
std::cout << "Je suis un personnage, le chef du village" << std::endl;
}
 
 
protected:
 
};
 
#endif 

 

     Fichier Guerrier.h

 

//Projet 156HeritageSimple_9
//Héritage simple - Redéfinition de méthodes (2)
//fichier Guerrier.h
#ifndef DEF_GUERRIER
#define DEF_GUERRIER
 
//Déclaration de la classe Guerrier
class Guerrier : public Personnage
{
public:
 
//Constructeur et destructeur
Guerrier() {};
~Guerrier() {};
 
void Se_Presenter() const
{
std::cout << "Je suis un guerrier, defenseur du village" << std::endl;
}
 
protected:
 
};
 
#endif 

 

     Fichier Druide.h

 

//Projet 156HeritageSimple_9
//Héritage simple - Redéfinition de méthodes (2)
//fichier Druide.h
#ifndef DEF_DRUIDE
#define DEF_DRUIDE
 
//Déclaration de la classe Druide
class Druide : public Personnage
{
public:
 
//Constructeur et destructeur
Druide() {};
~Druide() {};
 
void Se_Presenter() const
{
std::cout << "Je suis un druide, guerisseur du village" << std::endl;
}
 
 
protected:
 
};
 
#endif 

 

   Fichier HeritageSimple_9.cpp

 

//Projet 156HeritageSimple_9
//Héritage simple - Redéfinition de méthodes (2)
//fichier HeritageSimple_9.cpp
 
#include <iostream>
#include "Personnage.h"
#include "Guerrier.h"
#include "Druide.h"
 
using namespace std;
 
 
int main()
{
cout << endl;
 
//Création des objet Personnage, Guerrier et Druide
Personnage unPersonnage;
Guerrier unGuerrier;
Druide unDruide;
 
cout << "Presentation :" << endl << endl;
unPersonnage.Se_Presenter();
unGuerrier.Se_Presenter();
unDruide.Se_Presenter();
 
cin.get();
return 0;
} 

 

   Dans le fichier Personnage.h, nous définissons une méthode Se_Presenter() qui est redéfinie dans les classes dérivées. Chacun de nos objets utilise sa propre méthode pour faire les présentations, pas de problème ici, les classes Guerrier et Druide héritent de Personnage.

   Le résultat dans la console :

 

 

 

   Bien, modifions notre fichier HeritageSimple_9.cpp. Nous allons passer un objet de chaque classe à une fonction Presentation().  

 

//Projet 156HeritageSimple_9
//Héritage simple - Redéfinition de méthodes (2)
//fichier HeritageSimple_9.cpp
 
#include <iostream>
#include "Personnage.h"
#include "Guerrier.h"
#include "Druide.h"
 
using namespace std;
 
void Presentation(Personnage p) //On passe un personnage en argument
{
p.Se_Presenter();
}
 
void Presentation(Guerrier g) //On passe un guerrier en argument
{
g.Se_Presenter();
}
 
void Presentation(Druide d) //On passe un druide en argument
{
d.Se_Presenter();
}
 
 
int main()
{
//Création des objet Personnage, Guerrier et Druide
Personnage unPersonnage;
Guerrier unGuerrier;
Druide unDruide;
 
cout << endl;
cout << "Presentation" << endl << endl;
Presentation(unPersonnage);
Presentation(unGuerrier);
Presentation(unDruide);
 
cin.get();
return 0;
} 

 

   Ici nous implémentons trois méthodes Presentation() auxquelles on passe un objet de chaque classe. Pas de problème, le résultat devrait être le même. 

   Et en effet, le résultat dans la console est identique au résultat de la console ci-dessus. angel

   Mais attendez... surprise un guerrier et un druide sont tous deux des personnages, donc si nous n'utilisions qu'une seule fonction à laquelle on passe un objet personnage, nous devrions avoir aussi le même résultat ? frown

   Voyons cela.

 

 

//Projet 156HeritageSimple_9
//Héritage simple - Redéfinition de méthodes (2)
//fichier HeritageSimple_9.cpp
 
 
#include <iostream>
#include "Personnage.h"
#include "Guerrier.h"
#include "Druide.h"
 
using namespace std;
 
void Presentation(Personnage &p) //On passe un personnage en argument
{
p.Se_Presenter();
}
 
 
int main()
{
//Création des objet Personnage, Guerrier et Druide
Personnage unPersonnage;
Guerrier unGuerrier;
Druide unDruide;
 
cout << endl;
cout << "Presentation" << endl << endl;
Presentation(unPersonnage);
Presentation(unGuerrier);
Presentation(unDruide);
 
cin.get();
return 0;
} 

 

    Le résultat dans la console :

 


 

   Oh Oh... surprise Il semblerait qu'il y ait un problème, que se passe-t-il ? blush

   Nous voyons effectivement que si nous passons un objet personnage à la fonction Presentation(), c'est bien notre personnage qui se présente mais si nous passons un guerrier ou un druide en paramètre à la fonction en espérant que ces deux derniers avatars se présentent, nous voyons cependant que c'est également la fonction Se_Presenter() de la classe Personnage qui est appelée. cheeky

   Il se fait que le compilateur n'a accès qu'à cette fonction. Pour lui, c'est chaque fois un personnage qui est passé à la fonction Presentation() et pour qu'il puisse avoir accès aux méthodes redéfinies Se_Presenter() des classes Guerrier et Druide, nous devons déclarer, dans la classe de base, une méthode ''virtuelle'' et lui passer une référence en argument (rappelez-vous qu'une référence peut-être un pointeur ou une référence elle-même wink ).

   Pour déclarer la méthode Se_Presenter() en tant que méthode virtuelle, il suffit d'ajouter le mot-clé ''virtual'' devant le nom de la fonction Se_Presenter() de la classe mère Personnage. Il n'est pas nécessaire que les classes dérivées définissent les méthodes redéfinies en tant que méthodes virtuelles car elles le sont par héritage mais nous le ferons cependant toujours. Cela me semble plus clair lors de la lecture du code mais surtout nous n'oublierions pas de l'ajouter si une classe dérivée devait elle-même devenir une classe de base. wink

   Nous allons implémenter la modification de ce que nous avons vu jusqu'ici dans ce paragraphe 1.5 en proposant un second projet.

 


   Projet 157HeritageSimple_10

      Fichier Personnage.h

 

 

//Projet 157HeritageSimple_10
//Héritage simple - Méthodes virtuelles (1)
//fichier Personnage.h
#ifndef DEF_PERSONNAGE
#define DEF_PERSONNAGE
 
//Déclaration de la classe Personnage
class Personnage
{
public:
 
//Constructeur et destructeur
Personnage() {};
~Personnage() {};
 
virtual void Se_Presenter() const
{
std::cout << "Je suis un personnage, le chef du village" << std::endl;
}
 
 
protected:
 
};
 
#endif 

 

     Fichier Guerrier.h

 

//Projet 157HeritageSimple_10
//Héritage simple - Méthodes virtuelles (1)
//fichier Guerrier.h
#ifndef DEF_GUERRIER
#define DEF_GUERRIER
 
//Déclaration de la classe Guerrier
class Guerrier : public Personnage
{
public:
 
//Constructeur et destructeur
Guerrier() {};
~Guerrier() {};
 
virtual void Se_Presenter() const
{
std::cout << "Je suis un guerrier, defenseur du village" << std::endl;
}
 
 
protected:
 
};
 
#endif 

 

   Fichier Druide.h

 

//Projet 157HeritageSimple_10
//Héritage simple - Méthodes virtuelles (1)
//fichier Druide.h
#ifndef DEF_DRUIDE
#define DEF_DRUIDE
 
//Déclaration de la classe Druide
class Druide : public Personnage
{
public:
 
//Constructeur et destructeur
Druide() {};
~Druide() {};
 
virtual void Se_Presenter() const
{
std::cout << "Je suis un druide, guerisseur du village" << std::endl;
}
 
 
protected:
 
};
 
#endif 

 

     Fichier HeritageSimple_10.cpp

 

//Projet 157HeritageSimple_10
//Héritage simple - Méthodes virtuelles (1)
//fichier HeritageSimple_10.cpp
 
#include <iostream>
#include "Personnage.h"
#include "Guerrier.h"
#include "Druide.h"
 
using namespace std;
 
//On passe une réf sur un personnage const en argument
void Presentation(const Personnage &p)
{
p.Se_Presenter();
}
 
int main()
{
//Création des objet Personnage, Guerrier et Druide
Personnage unPersonnage;
Guerrier unGuerrier;
Druide unDruide;
 
cout << endl;
cout << "Presentation" << endl << endl;
Presentation(unPersonnage);
Presentation(unGuerrier);
Presentation(unDruide);
 
cin.get();
return 0;
} 

 

   Voila. Maintenant le compilateur sait à quelle méthode redéfinie il doit faire appel pour une présentation exacte de nos trois avatars. angel

   Toutes les remarques nécessaires à la compréhension de cet exemple ayant été faites auparavant, nous pouvons maintenant enfin montrer le résultat désiré dans la console cool

 

 

 

 

   2. Corrigés des exercices du chapitre 25

 

      Exercice 1 :

   Pour cet exercice on demandait d'écrire un programme qui affichera, à l'aide de méthodes membres d'accès publique, la race (ORC), le nom (Zorbar), le titre (Chef shaman) d'un objet unShaman. Vous ferez dériver la classe Shaman d'une classe Personnage et faites en sorte que le shaman frappe le personnage d'un coup d'épée. Pour terminer, affichez le nombre de points de vie du personnage (en supposant qu'il en perde 10) à l'aide d'une méthode membre d'accès publique. Votre personnage devra être de race ELFE.


   Fichier Personnage.h

 

//Projet Chap25Exercice_1
//Manipulation d'objets de classes de bases et de classes dérivées
//fichier Personnage.h
#ifndef DEF_PERSONNAGE
#define DEF_PERSONNAGE
 
#include <string>
 
 
using uint = unsigned int;
 
//Déclaration de la classe Personnage
class Personnage
{
public:
 
//Constructeur et destructeur
Personnage() : _race("ELFE"), _qte_Vie(100) {};
~Personnage() {};
 
uint get_Vie() const { return _qte_Vie; }
std::string get_Race() const { return _race; }
 
//Fonctions
void recevoirDegats(uint degats) { _qte_Vie -= degats; }
 
 
protected:
 
uint _qte_Vie;
std::string _race;
 
};
 
#endif 

 

   Le constructeur de la classe Personnage définit la race et le nombre de points de vie d'un personnage.

 

   Fichier Shaman.h

 

//Projet Chap25Exercice_1
//Manipulation d'objets de classes de bases et de classes dérivées
//fichier Guerrier.h
#ifndef DEF_SHAMAN
#define DEF_SHAMAN
 
using uint = unsigned int;
 
//Déclaration de la classe Guerrier
class Shaman : public Personnage
{
public:
 
//Constructeur et destructeur
Shaman() : _race("ORC"), _nom("Zorbar"), _titre("Chef shaman") {};
~Shaman() {}
 
//méthodes d'accès publique
std::string get_Name() const { return _nom; }
std::string get_Race() const { return _race; }
std::string get_Titre() const { return _titre; }
 
//Autre fonction
void coup_d_Epee(Personnage &autre) const
{
autre.recevoirDegats(10);
}
 
 
protected:
 
std::string _race;
std::string _nom;
std::string _titre;
 
};
 
#endif 

 

   La classe Shaman dérive de Personnage. Son constructeur définit la race, le nom et le titre d'un objet Shaman.

 

   Fichier Chap25Ex_1.cpp

 

//Projet Chap25Exercice_1
//Manipulation d'objets de classes de bases et de classes dérivées
//fichier HeritageSimple_2.cpp
 
#include <iostream>
#include <string>
#include "Personnage.h"
#include "Shaman.h"
 
using namespace std;
 
 
int main()
{
cout << endl;
//Création d'un objet Personnage
 
Personnage unPersonnage;
 
cout << "Creation d'un objet unPersonnage" << endl;
cout << "Ce personnage est de race " << unPersonnage.get_Race() << endl;
cout << "Il a " << unPersonnage.get_Vie() << " points de vie" << endl;
 
cout << endl;
 
//Création d'un objet Shaman
Shaman unShaman;
 
cout << "Creation d'un objet unShaman" << endl;
cout << "Sa race est : " << unShaman.get_Race() << endl;
cout << "Son nom est : " << unShaman.get_Name() << endl;
cout << "Son titre est : " << unShaman.get_Titre() << endl << endl;
 
cout << "Le shaman frappe le personnage d'un coup d'epee" << endl;
unShaman.coup_d_Epee(unPersonnage);
cout << "Le personnage a recu (- 10pdV) de degats" << endl;
cout << "Les pdV du personnage sont maintenant de " << unPersonnage.get_Vie();
 
cin.get();
return 0;
} 

 

    Dans la fonction main(), les méthodes membres d'accès publique get_Race() et get_Vie() affichent la race et le nombre de points de vie du personnage. Les méthodes définies dans le fichier Shaman.h retournent la race, le nom et le titre d'un shaman.

   Le shaman devait frapper le personnage d'un coup d'épée. On applique donc à l'objet unShaman la méthode coup_d_epee() à laquelle on passe un objet Shaman en paramètre.

   Pour terminer on affiche les nouveaux points de vie du personnage à l'aide de la méthode get_Vie().

   Rien de bien compliqué ici donc. cheeky

 


      Exercice 2 (Un petit challenge)

 

   Je vous demanderai de bien vouloir vous reporter à l'énoncé de cet exercice dans le chapitre 25. Je vous remercie de votre compréhension. angel

 

   Fichier Personnage.h

 

//Chap25Exercice_2
//Fichier : Personnage.h
//Déclaration de la classe Personnage
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
#ifndef DEF_PERSONNAGE
#define DEF_PERSONNAGE
 
#include <string>
 
using uint = unsigned int;
 
//Déclaration de la classe Personnage
class Personnage
{
 
public:
 
//Constructeur et destructeur
Personnage() : _qte_Vie(100) {};
 
~Personnage() {};
 
//Fonctions
void recevoirSoins(int soins)
{
_qte_Vie += soins;
 
if (_qte_Vie > 100)
_qte_Vie = 100;
}
 
uint get_Vie() const { return _qte_Vie; }
void recevoirDegats(uint degats) { _qte_Vie -= degats; }
 
void frapperAvecLesPoings(Personnage &autre) const
{
autre.recevoirDegats(2);
}
 
 
protected:
 
uint _qte_Vie;
 
};
 
#endif 

 

   Fichier Guerrier.h

 

//Chap25Exercice_2
//Fichier : Guerrier.h
//Déclaration de la classe Guerrier
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
#ifndef DEF_GUERRIER
#define DEF_GUERRIER
 
#include "Personnage.h"
 
using uint = unsigned int;
 
//Déclaration de la classe Guerrier – Hérite de Personnage
class Guerrier : public Personnage
{
public:
 
//Constructeur et destructeur
Guerrier() {};
~Guerrier() {}
 
//Autre fonction
void coup_d_Epee(Personnage &autre) const
{
autre.recevoirDegats(10);
}
 
protected:
 
};
#endif 

 

   La classe Guerrier hérite de Personnage et implémente la méthode coup_d_Epee().


   Fichier Archer.h

 

//Chap25Exercice_2
//Fichier : Archer.h
//Déclaration de la classe Archer
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
#ifndef DEF_ARCHER
#define DEF_ARCHER
 
#include "Personnage.h"
 
using uint = unsigned int;
 
//Déclaration de la classe Guerrier – Hérite de Personnage
class Archer : public Personnage
{
public:
 
//Constructeur et destructeur
Archer() {};
~Archer() {}
 
//Autre fonction
void tir_a_l_arc(Personnage &autre) const
{
autre.recevoirDegats(7);
}
 
 
protected:
 
};
#endif 

 

   La classe Archer hérite de Personnage et implémente la méthode tir_a_l_arc().

 

   Fichier Guerrier_du_Nord.h

 

 //Chap25Exercice_2
//Fichier : Guerrier_du_Nord.h
//Déclaration de la classe Guerrier_du_Nord
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
#ifndef DEF_GUERRIER_NORD
#define DEF_GUERRIER_NORD
 
#include <string>
#include "Guerrier.h"
//Nous déclarons la classe Guerrier_des_Plaines avant toute chose
//car la classe Guerrier_du_Nord y fait référence à l'intérieur
//de la fonction amie Echange_arme() et ce, afin que le compilateur sache qu'elle existe.
class Archer_des_Plaines;
 
class Guerrier_du_Nord : public Guerrier //Guerrier_du_Nord hérite de Guerrier
{
public:
 
//constructeurs
Guerrier_du_Nord();
Guerrier_du_Nord(std::string armePrincipale, std::string armeSecondaire);
 
//destructeur
~Guerrier_du_Nord();
 
//méthodes d'accès publiques
std::string ArmePrincipale_GetName() const;
std::string ArmeSecondaire_GetName() const;
void ArmePrincipale_SetName(std::string armePrincipale);
void ArmeSecondaire_SetName(std::string armeSecondaire);
 
//DEFINITION D'UNE PREMIERE FONCTION AMIE EN TANT QUE PONT ENTRE LES
//CLASSES GUERRIER_DU_NORD et GUERRIER_DES_PLAINES
friend void Echange_arme(Guerrier_du_Nord, Archer_des_Plaines);
 
 
private:
 
std::string _armePrincipale;
std::string _armeSecondaire;
};
 
#endif

 

   La classe Guerrier_du_Nord hérite de la classe Guerrier.

 

   Fichier Archer_des_Plaines.h

 

//Chap25Exercice_2
//Fichier : Archer_des_Plaines.h
 
//Déclaration de la classe Archer_des_Plaines
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
#ifndef DEF_ARCHER_PLAINES
#define DEF_ARCHER_PLAINES
 
#include <string>
#include "Archer.h"
//Nous déclarons la classe Guerrier_du_Nord avant toute chose
//car la classe Guerrier_des_Plaines y fait référence à l'intérieur
//de la fonction amie Echange_arme() et ce, afin que le compilateur sache qu'elle existe.
class Guerrier_du_Nord;
 
class Archer_des_Plaines : public Archer //Archer_des_Plaines hérite de Archer
{
public:
 
//Constructeurs
Archer_des_Plaines();
Archer_des_Plaines(std::string armePrincipale, std::string armeSecondaire);
 
//Destructeur
~Archer_des_Plaines();
 
//méthodes d'accès publiques
std::string ArmePrincipale_GetName() const;
std::string ArmeSecondaire_GetName() const;
void ArmePrincipale_SetName(std::string armePrincipale);
void ArmeSecondaire_SetName(std::string armeSecondaire);
 
//DEFINITION D'UNE FONCTION AMIE EN TANT QUE PONT ENTRE LES
//CLASSES GUERRIER_DU_NORD et GUERRIER_DES_PLAINES
friend void Echange_arme(Guerrier_du_Nord, Archer_des_Plaines);
 
 
private:
 
std::string _armePrincipale;
std::string _armeSecondaire;
 
};
 
#endif 

 

   La classe Archer_des_Plaines hérite de la classe Archer.

 

   Fichier Guerrier_du_Nord.cpp

 

//Chap25Exercice_2
//Fichier : Guerrier_du_Nord.cpp
//Définition de la classe Guerrier_du_Nord
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
 
#include "Guerrier_du_Nord.h"
 
using namespace std;
 
//constructeurs de Guerrier_du_Nord
Guerrier_du_Nord::Guerrier_du_Nord() {}
 
Guerrier_du_Nord::Guerrier_du_Nord(string armePrincipale, string armeSecondaire)
{
_armePrincipale = armePrincipale;
_armeSecondaire = armeSecondaire;
}
 
//destructeur de Guerrier_du_Nord
Guerrier_du_Nord::~Guerrier_du_Nord() {}
 
//Guerrier_du_Nord::ArmePrincipale_GetName(), méthode d'accès publique
//renvoie la valeur du membre _armePrincipale;
string Guerrier_du_Nord::ArmePrincipale_GetName() const
{
return _armePrincipale;
}
 
//Guerrier_du_Nord::ArmeSecondaire_GetName(), méthode d'accès publique
//renvoie la valeur du membre _armeSecondaire;
string Guerrier_du_Nord::ArmeSecondaire_GetName() const
{
return _armeSecondaire;
}
 
//définition de Guerrier_du_Nord::ArmePrincipale_SetName(), méthode d'accès publique
//définit le membre _armePrincipale
void Guerrier_du_Nord::ArmePrincipale_SetName(string armePrincipale)
{
//initialise la variable membre _armePrincipale
//avec la valeur passée par le paramètre armePrincipale
_armePrincipale = armePrincipale;
}
 
//définition de Guerrier_du_Nord::ArmeSecondaire_SetName(), méthode d'accès publique
//définit le membre _armeSecondaire
void Guerrier_du_Nord::ArmeSecondaire_SetName(string armeSecondaire)
{
//initialise la variable membre _armeSecondaire
//avec la valeur passée par le paramètre armeSecondaire
_armeSecondaire = armeSecondaire;
} 

 

   La classe Guerrier_du_Nord implémente son constructeur surchargé et ses méthodes membres.

 

   Fichier Archer_des_Plaines.cpp

 

//Chap25Exercice_2
//Fichier : Archer_des_Plaines.cpp
//Définition de la classe Archer_des_Plaines
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
 
#include "Archer_des_Plaines.h"
 
using namespace std;
 
//constructeurs de Guerrier_des_Plaines
Archer_des_Plaines::Archer_des_Plaines() {}
 
Archer_des_Plaines::Archer_des_Plaines(string armePrincipale, string armeSecondaire)
{
_armePrincipale = armePrincipale;
_armeSecondaire = armeSecondaire;
}
 
//destructeur de Guerrier_des_Plaines
Archer_des_Plaines::~Archer_des_Plaines() {}
 
//Guerrier_des_Plaines::ArmePrincipale_GetName(), méthode d'accès publique
//renvoie la valeur du membre _armePrincipale;
string Archer_des_Plaines::ArmePrincipale_GetName() const
{
return _armePrincipale;
}
 
//Guerrier_des_Plaines::ArmeSecondaire_GetName(), méthode d'accès publique
//renvoie la valeur du membre _armeSecondaire;
string Archer_des_Plaines::ArmeSecondaire_GetName() const
{
return _armeSecondaire;
}
 
//définition de Guerrier_des_Plaines::ArmePrincipale_SetName(), méthode d'accès publique
//définit le membre _armePrincipale
void Archer_des_Plaines::ArmePrincipale_SetName(string armePrincipale)
{
//initialise la variable membre _armePrincipale
//avec la valeur passée par le paramètre armePrincipale
_armePrincipale = armePrincipale;
}
 
//définition de Guerrier_des_Plaines::ArmeSecondaire_SetName(), méthode d'accès publique
//définit le membre _armeSecondaire
void Archer_des_Plaines::ArmeSecondaire_SetName(string armeSecondaire)
{
//initialise la variable membre _armePrincipale
//avec la valeur passée par le paramètre armePrincipale
_armeSecondaire = armeSecondaire;
} 

 

   La classe Archer_des_Plaines implémente son constructeur surchargé et ses méthodes membres.

 

   Fichier Pont.cpp

 

//Chap25Exercice_2
//Fichier : Pont.cpp
//Définition de la fonction Echange_Arme()
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
 
#include<iostream>
#include "Archer_des_Plaines.h"
#include "Guerrier_du_Nord.h"
 
using namespace std;
 
//DEFINITION DE LA FONCTION ECHANGE_ARME(Guerrier_du_Nord, Guerrier_des_Plaines)
void Echange_arme(Guerrier_du_Nord Thorgul, Archer_des_Plaines Elwyn)
{
string temp;
 
cout << "La fonction amie va intervertir les armes secondaires de chaque " << endl;
cout << "objet des classes Archer_des_Plaines et Guerrier_du_Nord." << endl << endl;
 
//On donne les armes à chaque guerrier
Thorgul.ArmePrincipale_SetName("Lourde hache d'eclair de Thor");
Elwyn.ArmePrincipale_SetName("Arc perforant de la douleur");
Thorgul.ArmeSecondaire_SetName("Poignard devoreur de chair");
Elwyn.ArmeSecondaire_SetName("Lame de feu buveuse d'ames");
 
//On affiche l'arme principale et secondaire de chaque guerrier
cout << "Armes de chaque guerrier :" << endl;
cout << "\nArme principale de Guerrier_du_Nord : " << Thorgul.ArmePrincipale_GetName() << endl;
cout << "Arme principale de Archer_des_Plaines : " << Elwyn.ArmePrincipale_GetName() << endl;
cout << "Arme secondaire de Guerrier_du_Nord : " << Thorgul.ArmeSecondaire_GetName() << endl;
cout << "Arme secondaire de Archer_des_Plaines : " << Elwyn.ArmeSecondaire_GetName() << endl;
 
//Les deux guerriers échangent leur arme secondaire
cout << "\nMaintenant chaque guerrier decide d'offrir son arme secondaire a l'autre." << endl << endl;
 
//On crée une variable temporaire pour l'échange
temp = Thorgul.ArmeSecondaire_GetName();
Thorgul.ArmeSecondaire_SetName(Elwyn.ArmeSecondaire_GetName());
Elwyn.ArmeSecondaire_SetName(temp);
 
//Lecture des armes de chaque querrier
cout << "Armes secondaires de chaque guerrier :" << endl;
cout << "Arme secondaire de Guerrier_du_Nord : " << Thorgul.ArmeSecondaire_GetName() << endl;
cout << "Arme secondaire de Archer_des_Plaines : " << Elwyn.ArmeSecondaire_GetName() << endl;
 
} 

 

   Le fichier Pont.cpp a quelque peu été ''élagué du superflu" et, comme demandé, mais vous voyez que contrairement au projet 106Class_13 du chapitre 17, nous utilisons une variable temporaire pour l'échange des armes secondaires. Aucun nom d'arme n'est cité, les méthodes GetName() et SetName() sont utilisées pour l'échange de la même façon qu'une fonction swap() le ferait.

 

   Fichier Chap25Ex_2MainFile.cpp

 

//Chap25Exercice_2
//Fichier : Chap25Ex_2mainFile.cpp
//Définition de la fonction main()
//Utilisation d'une fonction commune comme pont entre deux classes dérivées
 
#include <iostream>
#include <string>
#include "Archer_des_Plaines.h"
#include "Guerrier_du_Nord.h"
 
#include <conio.h>
 
 
using namespace std;
 
//On crée un objet Guerrier_du_Nord et un objet Guerrier_des_Plaines.
//On définit leurs armes principales et secondaires et on appelle la fonction Echange_arme()
//pour affichher leurs membres privés et en intervertir un.
 
int main()
{
Guerrier unGuerrier;
Archer unArcher;
 
cout << endl;
cout << "Un archer Elfe decoche une fleche a un guerrier ennemi (-7 pdV)" << endl;
unArcher.tir_a_l_arc(unGuerrier);
cout << "Les pdV du guerrier sont maintenant de " << unGuerrier.get_Vie() << endl;
cout << "Le guerrier frappe l'archer d'un coup d'epee (-10 pdV)" << endl;
unGuerrier.coup_d_Epee(unArcher);
cout << "Les pdV de l'archer sont desormais de " << unArcher.get_Vie() << endl << endl;
 
cout << "Plus tard, les fils du Guerrier et de l'Archer font la paix." << endl << endl;
 
string str1, str2;
 
Guerrier_du_Nord Thorgul(str1, str2);
Archer_des_Plaines Elwyn(str1, str2);
 
//Echange des armes secondaires
Echange_arme(Thorgul, Elwyn);
 
cin.get();
return 0;
} 

 

   La fonction main() débute par un échange de coups entre un guerrier et un archer. Plus tard, leurs fils décident de faire la paix et échangent leurs armes secondaires selon le code du projet 106Class_13 du chapitre 17. La lecture du chapitre 17 est donc indispensable à la bonne compréhension de cet exercice. 

 

   Voilà, c'est tout en ce qui concerne ce chapitre. cool

   Les corrigés des exercices de ce chapitre seront présentés à la fin du chapitre 27.

      @ bientôt pour le chapitre 27 –  Polymorphisme (1).                                                                     

            Gondulzak.  angel
 
 
 
 

Connexion

CoalaWeb Traffic

Today274
Yesterday178
This week774
This month4448
Total1743655

25/04/24