Vous êtes sur la page 1sur 28

Chapitre 4

Héritage et polymorphisme
Héritage
1. L'héritage
Nous allons maintenant découvrir une des notions les plus importantes de la
POO : l'héritage.

 l'héritage est une technique qui permet de créer une classe à partir
d'une autre classe. Elle lui sert de modèle, de base de départ. Cela
permet d'éviter d'avoir à réécrire un même code source plusieurs fois.

 L'héritage, également appelé dérivation, permet de définir une


nouvelle classe en se basant sur une classe déjà existante nommée
aussi la « classe de base »,
La classe de base à partir de laquelle on hérite est aussi appelée
aussi « classe mère » dans la littérature,
 Réutilisation totale ou partielle des classes déjà développées,
 Gain de temps et d’énergie pour le développement et la maintenance
des codes sources (les méthodes identiques ne sont codées qu’une
seule fois dans la classe mère).
Héritage
1. L'héritage
En suivant cette règle très simple : Il y a héritage quand on peut dire :
« A est un B ».
 On peut dire «Un guerrier est un personnage » ou encore «Un magicien est
un personnage ».
 On peut donc définir un héritage : « la classe Guerrier hérite de Personnage »,
« la classe Magicien hérite de Personnage ».

Voici quelques exemples supplémentaires et corrects d'héritage :


• une voiture est un véhicule (Voiture hérite de Véhicule) ;
• un bus est un véhicule (Bus hérite de Véhicule) ;
• un chirurgien est un docteur (Chirurgien hérite de Docteur) ;
• etc.
En revanche, vous ne pouvez pas dire « Un docteur est un chirurgien», ou encore
« Un bus est un chirurgien». Donc, dans ces cas-là, on ne peut pas faire
d'héritage ou, plus exactement, cela n'aurait aucun sens.
Héritage
1. L'héritage
Héritage
1. L'héritage
Héritage
1. L'héritage
Héritage
1. L'héritage
Héritage
1. L'héritage
****** Notre exemple : la classe Personnage ******
Nous allons un peu simplifier notre classe Personnage. Voici ce sur quoi je vous
propose de partir :
class Personnage
{
public: Notre Personnage a un nom et
Personnage() : m_vie(100), m_nom("Jack") { une quantité de vie.
}; On n'a mis qu'un seul
Void recevoirDegats(int degats) { constructeur, celui par défaut.
m_vie -= degats;
}  Il permet d'initialiser le
Personnage avec un nom et lui
void coupDePoing(Personnage &cible) const donne 100 points de vie.
{
 Le Personnage peut recevoir
cible.recevoirDegats(10);
des dégâts, via la méthode
};
recevoirDegats et en distribuer,
private:
via la méthode coupDePoing().
int m_vie;
std::string m_nom;
};
Héritage
1. L'héritage
La classe Guerrier hérite de la classe Personnage
Intéressons-nous maintenant à l'héritage : l'idée est de créer une nouvelle classe
qui soit une sous-classe de Personnage.
On dit que cette classe hérite de Personnage.
Pour cet exemple, je vais créer une classe Guerrier qui hérite de Personnage. La
définition de la classe :

 Grâce à ce qu'on vient de faire, la classe Guerrier contiendra de base tous les
attributs et toutes les méthodes de la classe Personnage.

 Dans un tel cas,


 la classe Personnage est appelée la classe « Mère »
 et la classe Guerrier la classe « Fille ».
Héritage
1. L'héritage
La classe Guerrier hérite de la classe Personnage
Mais quel intérêt de créer une nouvelle classe si c'est pour qu'elle contienne les
mêmes attributs et les mêmes méthodes ?

Justement ! Le truc, c'est qu'on peut rajouter des attributs et des méthodes
spéciales dans la classe Guerrier. Par exemple, on pourrait rajouter une méthode
qui ne concerne que les guerriers, du genre
frapperCommeUnSourdAvecUnMarteau (bon ok, c'est un nom de méthode un peu
long, je l'avoue, mais l'idée est là).
Héritage
1. L'héritage
La classe Guerrier hérite de la classe Personnage
Schématiquement, on représente la situation comme à la figure suivante.
Héritage
1. L'héritage
La classe Magicien hérite aussi de Personnage

 On créait une classe Magicien qui hérite elle aussi de Personnage .


 Après tout, un Magicien est un Personnage , donc il peut récupérer les mêmes
propriétés de base : de la vie, un nom, donner un coup de poing, etc.
 La différence, c'est que le Magicien peut aussi envoyer des sorts magiques,
par exemple bouleDeFeu et bouleDeGlace.
 Pour utiliser sa magie, il a une réserve de magie qu'on appelle « Mana » (cela
fait un attribut à rajouter).
 Quand Mana tombe à zéro, il ne peut plus lancer de sort.
Héritage
1. L'héritage
La classe Magicien hérite aussi de Personnage
Héritage
1. L'héritage
La classe Magicien hérite aussi de Personnage

 Notez que, sur le schéma, je n'ai représenté que les méthodes des classes mais
les attributs (vie, nom… ) sont eux aussi hérités!
 Et le plus beau, c'est qu'on peut faire une classe qui hérite d'une classe qui
hérite d'une autre classe !
 Imaginons qu'il y ait deux types de magiciens : les magiciens blancs, qui sont
des gentils qui envoient des sorts de guérison, et les magiciens noirs qui sont
des méchants qui utilisent leurs sorts pour tuer des gens. Figure suivante :
Héritage
1. L'héritage
La classe Magicien hérite aussi de Personnage
Héritage
1. L'héritage
Héritage et constructeurs
 Vous avez peut-être remarqué que je n'ai pas encore parlé des constructeurs
dans les classes filles (Guerrier, Magicien… ).
 C'est justement le moment de s'y intéresser.
 On sait que Personnage a un constructeur (par défaut) défini comme ceci:

Personnage( ) : m_vie ( 100 ), m_nom ( "Jack")


{

};

Comme vous le savez, lorsqu'on crée un objet de type Personnage, le constructeur est
appelé avant toute chose.
Héritage
1. L'héritage
Héritage et constructeurs

Mais maintenant, que se passe-t-il lorsqu'on crée par exemple un Magicien


qui hérite de Personnage ?
 En fait, les choses se déroule dans l'ordre suivant :
1. Vous demandez à créer un objet de type Magicien ;
2. Le compilateur appelle d'abord le constructeur de la classe mère
(Personnage) ;
3. Puis, le compilateur appelle le constructeur de la classe fille (Magicien).

En clair, c'est d'abord le constructeur du « parent » qui est appelé, puis celui
du fils, et éventuellement celui du petit-fils (s'il y a un héritage d'héritage,
comme c'est le cas avec MagicienBlanc).
Héritage
1. L'héritage

Appeler le constructeur de la classe mère

Pour appeler le constructeur de Personnage en premier, il faut y faire


appel depuis le constructeur de Magicien.

Magicien ( ) : Personnage( ) : m_mana ( 100 )


{

};

Le premier élément de la liste d'initialisation indique de faire appel en


premier lieu au constructeur de la classe parente Personnage. Puis on
réalise les initialisations propres au Magicien (comme l'initialisation du
mana à 100).
Héritage
1. L'héritage

Transmission de paramètres

Le gros avantage de cette technique est que l'on peut « transmettre »


les paramètres du constructeur de Magicien au constructeur de
Personnage. Par exemple:

Magicien (string nom ) : Personnage(nom) : m_mana ( 100 )


{

};
Héritage
1. L'héritage
Schéma résumé
Héritage
1. L'héritage
Il me serait vraiment impossible de vous parler d'héritage sans vous parler de la
portée protected.
Actuellement, les portées (ou droits d'accès) que vous connaissez déjà sont :
 public : les éléments qui suivent sont accessibles depuis l'extérieur de la classe ;
 private : les éléments qui suivent ne sont pas accessibles depuis l'extérieur de la
classe.
Je vous ai en particulier donné la règle fondamentale du C++, l'encapsulation, qui
veut que l'on empêche systématiquement au monde extérieur d'accéder aux attributs
de nos classes.
La portée protected est un autre type de droit d'accès que je classerais entre public
(le plus permissif) et private (le plus restrictif). Il n'a de sens que pour les classes qui
se font hériter (les classes mères) mais on peut l'utiliser sur toutes les classes, même
quand il n'y a pas d'héritage.
Voici sa signification : les éléments qui suivent protected ne sont pas accessibles
depuis l'extérieur de la classe, sauf si c'est une classe fille.
Cela veut dire, par exemple, que si l'on met des éléments en protected dans la classe
Personnage, on y aura accès dans les classes filles Guerrier et Magicien. Avec la
portée private, on n'aurait pas pu y accéder !
Héritage
1. L'héritage

On peut alors directement manipuler la vie et le nom dans tous les éléments enfants
de Personnage, comme Guerrier et Magicien !
Héritage
1. L'héritage
En résumé:

 L'héritage permet de spécialiser une classe.


 Lorsqu'une classe hérite d'une autre classe, elle récupère toutes ses
propriétés et ses méthodes.
 Faire un héritage a du sens si on peut dire que l'objet A « est un » objet B. Par
exemple, une Voiture « est un » Vehicule.
 La classe de base est appelée classe mère et la classe qui en hérite est
appelée classe fille.
 Les constructeurs sont appelés dans un ordre bien précis : classe mère, puis
classe fille.
 En plus de public et private, il existe une portée protected. Elle est
équivalente à private mais elle est un peuplus ouverte : les classes filles peuvent
elles aussi accéder aux éléments.
 Si une méthode a le même nom dans la classe fille et la classe mère, c'est la
méthode la plus spécialisée, celle de la classe fille, qui est appelée.
Héritage
Exemple:
#include <iostream>
#include <string>
using namespace std;
class movement {
/////////////////////////////
private :
int _state; float _kelo;
float _meter; int _position; int _side;
/////////////////////////////
public :
movement(){
_state = 0; _kelo = 0;
_meter = 0; _position = 0; _side = 1;
}
//------------------//
void power_on(){
_state = 1;
cout << "START\a\n";
};
//------------------//
void move_on( float meter, char side){
if (_state == 0 ){
cout << "You must start the car!\n";
}
Héritage
Exemple:
else{
cout << "\nMOVE: ";
if(side=='f'){
_meter += meter;
_side = 1;
if(_meter>= 100) {
_meter -= 100;
_kelo++;
}
cout << "\t-> Moving " << meter<< " meter forward\n";
}else if(side=='b'){
_meter -= meter;
_side = -1;
if(_meter<= 0){
_meter=99;
_kelo--;
}
cout << "\t-> Moving " << meter << " meter backward\n";
}
}
}
//------------------//
Héritage
Exemple:
void position_(){
if (_side==1){
cout << "\t You moved to " << _kelo << ","<< _meter << " km\n";
}else{
cout << "\t You back to " << _kelo << ","<< _meter << " km\n";
}
}
~movement(){
cout << "\nSTOP\n";
}
/////////////////////////////
};
//#############################################//
class shape : public movement {
/////////////////////////////
private :
string _model; string _color;
int _doors; int _engine_force;
/////////////////////////////
public :
shape(){
_model = "BMW"; _color = "white";
_doors = 4; _engine_force= 200;
}
Héritage
Exemple:
//------------------//
void recolor( string color ){
_color = color;
}
//------------------//
void upgread_engine( int force){
_engine_force += force;
}
//------------------//
void descripe_(){
cout << "Model:\t"<< _model << endl
<< "Color:\t"<< _color << endl
<< "Doors:\t"<< _doors << endl
<< "Engine:\t"<< _engine_force << " horse\n\n";
}
};
Héritage
Exemple:
///////////////////////////////////////////////////
int main(){
shape car;
car.power_on(); //start
car.move_on(20,'f');
car.position_();
car.move_on(83,'f');
car.position_();
car.move_on(100,'f');
car.position_();
car.move_on(4,'b');
car.position_();
cout << "\n\n";
car.descripe_();
car.recolor("red");
car.upgread_engine(100);
car.descripe_();
}

Vous aimerez peut-être aussi