Chapitre VChapitre V
Héritage ou dérivation d’une classe
2
HéritageHéritagePermet de créer une classe à partir d’une autre i.e. la nouvelle classebénéficie des données et fonctions membres de la classe dont elle dérive.
Dans cette nouvelle classe, vous pourrez ensuite définir de nouveaux membres afinde modifier et spécialiser la classe de base.
Technique permettant de réutiliser et de spécialiser les classes existantes :- évite de réécrire du code lorsqu’un comportement est hérité d’une autre classe;- augmente la fiabilité du code et réduit les coûts de maintenance.
Partage du code :- plusieurs programmeurs ou projets peuvent utiliser les mêmes classes;- plusieurs classes développées dans un projet peuvent hériter d’une même classe;- ainsi, plusieurs types d’objets partagent le code qu’ils héritent; ce code est écrit une seule fois.
Avantages de l’héritage :
3
HéritageHéritageAvantages de l’héritage :
Consistance des interfaces :- lorsque plusieurs classes héritent de la même super-classe, celles-ci auront les les mêmes comportements;- l’héritage permet d’unifier différents types d’objets sur la base de leurs ressemblances.Prototypage rapide :- lorsqu’on construit un système à partir de composantes réutilisables, on investit le temps de développement dans les nouvelles zones moins connues du logiciel;- permet de générer plus rapidement des prototypes de notre système.Masquage d’information :- réduction du couplage des données;- on se concentre sur la compréhension de la nature des abstractions disponibles et de leur interface;- la compréhension des mécanismes d’implantation n’est pas nécessaire à la bonne utilisation de ces composantes.
4
HéritageHéritageCoûts de l’héritage :
Rapidité d’exécution- on ne peut espérer obtenir autant de performance avec des outils génériques qu’avec une implantation spécifique.- toutefois, la perte de performance est mineure et est compensée par une augmentation de la rapidité de développement.Dimension du code exécutable- l’utilisation de librairies réutilisables produit souvent des exécutables plus gros que les systèmes conçus spécifiquement pour un projet.- toutefois, contenir les coûts, produire de la qualité et du code exempt d’erreur est plus important.Appel de méthode- il y a un coût à payer pour un appel de méthode p/r à un appel de procédure.- toutefois, il y a un gain à utiliser la technologie OO.Complexité du programme- la sur-utilisation de l’héritage augmente la complexité.
5
RéutilisationRéutilisation
Utiliser du code existant plutôt que de réécrire chaque application à partir de rien.
Accélère le temps de développement.
Réduit le coût de l’écriture et de la maintenance du code d’une application.
Réutilisation par « recyclage »Réutilisation par « recyclage »Prendre un bout de code dans un programme qui nous intéresse et l’utiliser dans unautre programme en l’adaptant.Problèmes rencontrés :
Trouver le code qui nous intéresse peut être difficile.Pas d’assurance que le code provenant d’un autre programme est correct.
Il peut être difficile de détacher un bout de code d’un programme à cause desnombreuses dépendances qui y sont implantées.
Le bout de code extrait peut demander d’importantes modifications pourfonctionner dans le nouveau programme.
Souvent plus facile de tout réécrire…
6
Propriétés essentielles du code réutilisablePropriétés essentielles du code réutilisable
Facile à trouver et à comprendre.
Assurance raisonnable que le code est correct.
Ne demande pas d’effectuer une séparation du code qui le contient.
Ne demande pas de changement pour être utilisé dans un nouveau programme.
Mythes de la réutilisationMythes de la réutilisationLa réutilisation résoudra la crise du logiciel.
Tout le code qu’on écrit devrait être réutilisable.
Il est toujours préférable de réutiliser que de coder à partir de rien.
La programmation orientée objet rend facile l’écriture de code réutilisable.
7
Illustration du concept d’héritageIllustration du concept d’héritage
Je connais bon nombre de comportements de Gilles, le fournisseur de bois, non pasparce que je sais qu’il est fournisseur de bois, mais parce qu’il est un commerçant.
De ce fait, je m’attends à ce qu’il me demande de l’argent pour ses services et qu’ilme donne un reçu en échange.
Ces comportements sont aussi vrais pour l’épicier, le fleuriste ou le coiffeur.
Étant donné que fournisseur de bois est plus spécialisé que Commerçant, ce qui estvrai pour le commerçant est vrai pour le fournisseur de bois et donc pour Gilles.
En structurant nos connaissances du problème à résoudre de manière hiérarchique,cela permet une meilleure compréhension du problème.
8
Illustration du concept d’héritageIllustration du concept d’héritage
Citoyen
Commerçant
Fournisseur de bois
9
Illustration du concept d’héritageIllustration du concept d’héritage
Prêt
Prêtauto
Prêthypothécaire
Prêtrénovations
Forme
Cercle Triangle Rectangle
Compte
Compted’épargne
Comptechèque
10
Hiérarchie d’héritage pour les membres Hiérarchie d’héritage pour les membres d’une communauté universitaired’une communauté universitaire
Membre Communauté
Employé Étudiant Ancien
Employéen faculté
Personnelhors faculté
Administrateur Enseignant
AdministrateurEnseignant
Étudiantemployé
Héritage multiple
Héritage multiple
11
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Codescommuns
Forme classique d’héritageHériter pour spécialiser
Matrice carrée
Matrice
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Réalisation d’une spécificationabstraiteS’assurer que les héritiers auront unemême interfaceLe parent est désigné comme classeabstraite parce qu’il définit descomportements communs sans les
implanter, les héritiers leferont.
Polygone
Figure géométrique
Cercle
Opérations imposées auxfigures géométriques :- Afficher - Aire- Normale - etc.
Codescommuns
13
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Héritage utilitaireOn veut récupérer diverses fonctionnalitésdu parent tout en modifiant certainsparamètres ou nom de méthode.
Approche à éviter :utiliser l’agrégationà la place.
Pile
Liste simple
Une pile n’est pas une liste à laquelleon ajoute des méthodes spécifiquesà la pile.La liste peut être utilisée commeattribut de la classe Pile.
Codescommuns
14
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Inverse de la spécialisationUne sous-classe va créer un concept plusgénéral que son parent en modifiant ouélargissant sa gamme de comportements.Fréquent lorsqu’on bâtit sur des classesexistantes dont on ne peut pas modifierle contenu.Approche à éviter :
préférable d’utiliser laspécialisation.
Codescommuns
15
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Polygone
Figure géométrique
Cercle
Librairie on ne possèdepas le code source
Polygone+ Cercle+
Généralisation
Renferme desfonctionnalitéssupplémentaires
Codescommuns
Chapitre V - Héritage ou dérivation d'une classe
16
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Héritage pour restreindre le comportementd’une sous-classe p/r au parent.Fréquent lorsqu’on bâtit sur des classesexistantes dont on ne peut pas modifierle contenu.Approche à éviter.
Pile
Dèque
Les opérations possibles sur une pilesont limitées p/r à celles d’un dèque.Il faut redéfinir les méthodes troppermissives.
Codescommuns
Chapitre V - Héritage ou dérivation d'une classe
17
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Des classes possèdent un code communmais n’ont pas de lien hiérarchique.On choisit arbitrairement une des classes commeparent laquelle renfermera le code commun.Fréquent lorsqu’on bâtit sur des classesexistantes dont on ne peut pas modifierle contenu.Approche à éviter :
Préférable de factoriser lecode commun dans une classeabstraite.Codes
communs
Chapitre V - Héritage ou dérivation d'une classe
18
Types d’héritage (Yves Roy)Types d’héritage (Yves Roy)
Spécialisation
Spécification
Construction
Généralisation
Extension
Limitation
Codescommuns
Souris
Tablette graphique
Il existe un code communaux 2 classes.
Il n’y a aucune raisonpourquoi la tablette graphiquehériterait de la souris.
Périphérique d’entrée
Tablette graphique Souris
Classe abstraite
Les héritiers implantent leur code spécifique.
Chapitre V - Héritage ou dérivation d'une classe
19
Héritage en C++Héritage en C++La classe dont dérive une classe se nomme la classe de base, la superclasse, la classeparent, la classe ancêtre, la classe mère ou la classe père.
La classe dérivée se nomme la classe fille ou la sous-classe.
Chaque fois que vous créez un objet d ’une classe dérivée, C++ créera un objet de laclasse de base.
Par ex., si B dérive de A, un objet de B est un objet de A avec des éléments supplém.
Les données membres des classes de base sont créées pour chaque objet dérivéindépendamment des directives de protection.
Exemple :
Si B dérive de A, et qu’une donnée membre de A est définie en privée (private),elle est allouée quand même.Elle sera utilisable par la partie A de l ’objet B et non par les méthodes spécifiquesde B.
Chapitre V - Héritage ou dérivation d'une classe
20
HéritageHéritage
Ce processus de création automatique d’un objet de la classe de base, chaque foisque l’on déclare un objet de la classe dérivée, se propage tout au long de la hiérarchie.
Bien distinguer entre l’utilisation de classes indépendantes et l’héritage.
Mise en oeuvre
class Nom_de_la_classe_derivee : <acces> Nom_de_la_classe_de_base{
…..};
<acces> désigne l ’une des 3 valeurs suivantes: public, private et protected.
à venir
Chapitre V - Héritage ou dérivation d'une classe
21
HéritageHéritage
Exemple : une classe B qui dérive de la classe A.
class B : public A{
……};
Note : La classe A doit obligatoirement être déclarée avant la classe B.
Chapitre V - Héritage ou dérivation d'une classe
22
HéritageHéritage
Exemple
Liste_simple
Polygone_2D
Polygone_2D_convexe
« hérite de »
Exercices résolus (chap. IV)
Chapitre V - Héritage ou dérivation d'une classe
23
Polygone_2D.hPolygone_2D.h
#include "Liste_simple.h"struct sommet_2D{
int x, y;};class Polygone_2D{/* Spécification fonctionnelle de la classe " Polygone_2D "Composantes :Chaque composante est un sommet du polygone 2D.Structure : Il existe une relation linéaire (structure) entre les sommets
du polygone. Cette relation décrit le mode de parcours ducontour polygonal dans le sens horaire. */
Chapitre V - Héritage ou dérivation d'une classe
24
Polygone_2D.h Polygone_2D.h (suite)(suite)
protected:
int Nb_de_sommets; /* Nombre de sommets du polygone */Liste_simple Ensemble_des_sommets;
float Aire_Triangle_2D(int x, int y, int u, int v, int a, int b);/* Retourne l'aire du triangle dont les coordonnées des sommets
sont resp. (x, y), (u, v) et (a, b).
Pré - NilPost - Retourne l'aire du triangle 2D. */
Chapitre V - Héritage ou dérivation d'une classe
25
Polygone_2D.h Polygone_2D.h (suite)(suite)
public:Polygone_2D();/* Permet de créer un polygone 2D à 0 sommet.
Pré - L > 0.Post - Un polygone à 0 sommet est créé. */
void Ajouter_sommet(int x, int y);/* Permet d'ajouter un sommet de coordonnées x, y au polygone.
L'ordre d'insertion des sommets du polygone doit respecterun mode de parcours dans le sens horaire.Pré - Le polygone 2D a déjà été créé.Post - Un sommet de coordonnées x,y a été ajouté au polygone.*/
Chapitre V - Héritage ou dérivation d'une classe
26
Polygone_2D.h Polygone_2D.h (suite)(suite)
int Nombre_de_sommets();/* Retourne le nombre de sommets du polygone 2D.
Pré - Le polygone 2D a déjà été créé.Post - Retourne le nombre de sommets. */
void Detruire_Polygone_2D();/* Permet de détruire les sommets du polygone 2D.
Pré - Le polygone 2D a déjà été créé et renferme au moins unsommet.
Post - Les sommets du polygone 2D ont été détruits. Le polygonerenferme 0 sommet. */
Chapitre V - Héritage ou dérivation d'une classe
27
Polygone_2D.h Polygone_2D.h (fin)(fin)
float Aire_Polygone_2D();
/* Retourne l'aire du polygone 2D.
Pré - Le polygone 2D a déjà été créé et le nombre de sommetsest supérieur ou égal à 3.
Post - L'aire du polygone 2D est retourné. */};
Chapitre V - Héritage ou dérivation d'une classe
28
Polygone_2D.cppPolygone_2D.cpp
#include <iostream.h>#include "Polygone_2D.h"Polygone_2D::Polygone_2D(){
Nb_de_sommets = 0;}void Polygone_2D::Ajouter_sommet(int x, int y){
sommet_2D * P = new sommet_2D;(*P).x = x; (*P).y = y;Ensemble_des_sommets.Inserer_fin_liste(P);Nb_de_sommets = Nb_de_sommets + 1;
}
Chapitre V - Héritage ou dérivation d'une classe
29
Polygone_2D.cpp Polygone_2D.cpp (suite)(suite)
int Polygone_2D::Nombre_de_sommets(){
return Nb_de_sommets;}
void Polygone_2D::Detruire_Polygone_2D(){
Ensemble_des_sommets.Detruire_liste();Nb_de_sommets = 0;
}
Chapitre V - Héritage ou dérivation d'une classe
30
Polygone_2D.cpp Polygone_2D.cpp (suite)(suite)
float Polygone_2D::Aire_Triangle_2D(int x, int y, int u, int v, int a, int b){
float aire;aire = ((float) ((v - y)*(a - x) - (u - x)*(b-y))) / 2.0f;return aire;
}
Chapitre V - Héritage ou dérivation d'une classe
31
Polygone_2D.cpp Polygone_2D.cpp (suite)(suite)
float Polygone_2D::Aire_Polygone_2D(){
int x, y, u, v, a, b;bool Fin;struct sommet_2D * P;float somme = 0.0;
Ensemble_des_sommets.Positionner_debut_liste();P = (sommet_2D *) Ensemble_des_sommets.Acces_element_courant();
x = (*P).x;y = (*P).y;
Chapitre V - Héritage ou dérivation d'une classe
32
Polygone_2D.cpp Polygone_2D.cpp (suite)(suite)
Fin = Ensemble_des_sommets.Positionner_sommet_suivant();P = (sommet_2D *) Ensemble_des_sommets.Acces_element_courant();u = (*P).x;v = (*P).y;
Fin = Ensemble_des_sommets.Positionner_sommet_suivant();P = (sommet_2D *) Ensemble_des_sommets.Acces_element_courant();a = (*P).x;b = (*P).y;
somme = somme + Aire_Triangle_2D(x, y, u, v, a, b);
Chapitre V - Héritage ou dérivation d'une classe
33
Polygone_2D.cpp Polygone_2D.cpp (fin)(fin)
while (Ensemble_des_sommets.Positionner_sommet_suivant() == false){P = (sommet_2D *) Ensemble_des_sommets.Acces_element_courant();
u = a;v = b;a = (*P).x;b = (*P).y;somme = somme + Aire_Triangle_2D(x, y, u, v, a, b);
}return somme;}
Chapitre V - Héritage ou dérivation d'une classe
34
Application Polygone_2D.cppApplication Polygone_2D.cpp#include <iostream.h>#include "Polygone_2D.h"void main(){
Polygone_2D Q;Q.Ajouter_sommet(1, 1); Q.Ajouter_sommet(1, 3);Q.Ajouter_sommet(2, 3); Q.Ajouter_sommet(2, 2);Q.Ajouter_sommet(3, 2); Q.Ajouter_sommet(3, 3);Q.Ajouter_sommet(4, 3); Q.Ajouter_sommet(4, 1);cout << "Nombre de sommets : " << Q.Nombre_de_sommets();cout << "Aire du polygone 2D : " << Q.Aire_Polygone_2D();Q.Detruire_Polygone_2D();cout << "Nombre de sommets : " << Q.Nombre_de_sommets();
}
Chapitre V - Héritage ou dérivation d'une classe
35
HéritageHéritage
Exemple (suite)
Liste_simple
Polygone_2D
Polygone_2D_convexe
« hérite de »
Exercices résolus (chap. IV)
Chapitre V - Héritage ou dérivation d'une classe
36
Polygone_2D_convexe.hPolygone_2D_convexe.h
#include "Polygone_2D.h"class Polygone_2D_convexe : public Polygone_2D{/*
Spécification fonctionnelle de la classe " Polygone_2D_convexe "dérivée de la classe "Polygone_2D".
Composantes :Chaque composante est un sommet d'un polygone convexe
Structure : Il existe une relation linéaire (structure) entre les sommetsdu polygone. Cette relation décrit le mode de parcours ducontour polygonal dans le sens horaire. */
Chapitre V - Héritage ou dérivation d'une classe
37
Polygone_2D_convexe.hPolygone_2D_convexe.h
public:void Point_visible_Polygone_2D_convexe(float * x, float * y);
/* Permet de calculer un point intérieur au polygone lequel estvisible de tous ses sommets.
Pré - Le polygone 2D convexe a déjà été créé et le nombre desommets est supérieur ou égal à 3.
Post - Les coordonnées réelles x, y d'un point visible dupolygone 2D convexe sont retournées en paramètres. */
};
Chapitre V - Héritage ou dérivation d'une classe
38
Polygone_2D_convexe.cppPolygone_2D_convexe.cpp
#include <iostream.h>#include "Polygone_2D_convexe.h"void Polygone_2D_convexe::Point_visible_Polygone_2D_convexe
(float * x, float * y){
float Vx, Vy;struct sommet_2D * P;Ensemble_des_sommets.Positionner_debut_liste();
P = (sommet_2D *) Ensemble_des_sommets.Acces_element_courant();Vx = (*P).x / (float) Nb_de_sommets;Vy = (*P).y / (float) Nb_de_sommets;
Chapitre V - Héritage ou dérivation d'une classe
39
Polygone_2D_convexe.cppPolygone_2D_convexe.cpp
while (Ensemble_des_sommets.Positionner_sommet_suivant() == false){P = (sommet_2D *) Ensemble_des_sommets.Acces_element_courant();
Vx = Vx + (*P).x / (float) Nb_de_sommets;Vy = Vy + (*P).y / (float) Nb_de_sommets;
}
*x = Vx; *y = Vy;
}
Chapitre V - Héritage ou dérivation d'une classe
40
Application Application Polygone_2D_convexe.cppPolygone_2D_convexe.cpp
#include <iostream.h>#include "Polygone_2D_convexe.h"void main(){
float a, b;Polygone_2D_convexe Q;
Q.Ajouter_sommet(1, 1);Q.Ajouter_sommet(1, 3);Q.Ajouter_sommet(4, 3);Q.Ajouter_sommet(4, 1);
Chapitre V - Héritage ou dérivation d'une classe
41
Application Application Polygone_2D_convexe.cppPolygone_2D_convexe.cpp
cout << "Nombre de sommets : " << Q.Nombre_de_sommets();cout << "Aire du polygone 2D : " << Q.Aire_Polygone_2D();
Q.Point_visible_Polygone_2D_convexe(&a, &b);cout << "Point visible : " << a << " , " << b;
Q.Detruire_Polygone_2D();cout << "Nombre de sommets : " << Q.Nombre_de_sommets();
}
Chapitre V - Héritage ou dérivation d'une classe
42
Héritage et protection des Héritage et protection des membresmembres
Rappel: 3 étiquettes de protection : public, private et protected.
Une classe dérivée peut accéder aux données membres publiques et protégées de laclasse de base.
Les données privées ne sont manipulables que par les fonctions membrespublic et protected de la classe qui les a définies.
Principe : Mieux vaut laisser privées toutes les données car,
- n’importe quelle fonction membre de classe dérivée peut corrompre les données protégées de la classe de base.- les classes possédant des données membres protégées sont difficiles à modifier car quelqu’un peut avoir écrit une classe dérivée dont le code repose sur ces données membres protégées.
Chapitre V - Héritage ou dérivation d'une classe
43
Héritage et protection des Héritage et protection des membresmembres
Exemple:
class A{
public:int i;
protected:int j;
private:int z;
public:A();void Affiche();
};
class B : public A{
public :void Utilise();
};
A::A(){
i=1;j=2;z=3;
}
Chapitre V - Héritage ou dérivation d'une classe
44
Héritage et protection des Héritage et protection des membresmembres
Exemple: (suite)
void A::Affiche(){
cout << "i : " << i << " \n ";cout << "j : " << j << " \n ";cout << "z : " << z << " \n ";
}void B:: Utilise(){
i=4;j=5;// z=6; // impossible, car z est privée.Affiche();
}
void main(){
B b;b.Utilise();// b.i = 7;// possible, car i est
// public.// b.Affiche(); // possible.
}
i : 4j : 5z : 3
public
Chapitre V - Héritage ou dérivation d'une classe
45
Héritage et protection des Héritage et protection des membresmembres
Note: La donnée membre i et la fonction Affiche() sont accessibles par toute fonctionqui déclare un objet de ce type ou d ’un type dérivé.
Quelles que soient les étiquettes de protection, une fonction membre d’une classepeut accéder à toutes les données membres de cette classe.
Un constructeur, comme toute fonction membre, doit être intégré à une étiquettede protection.
Dans la plupart des cas, les constructeurs sont déclarés dans la section public, ce quipermet à quiconque de créer les objets de cette classe en utilisant ces constructeurs.
Chapitre V - Héritage ou dérivation d'une classe
46
Spécification de l’héritageSpécification de l’héritage
En dérivant une classe, nous devons indiquer l ’étiquette de protection:class B : public A // Autres choix : private et protected{
…..};
Permet de spécifier la façon dont se propagera l’héritage en termes d ’accès dansune hiérarchie de classes.Dans la pratique, vous utiliserez presque exclusivement l’étiquette public.
2 règles d ’utilisation:Si vous omettez d ’employer un de ces mots clés, l’étiquette private est la valeurpar défaut.
Le choix de l’étiquette ne change rien pour la classe dérivée (B dans l’exemple)La spécification d’héritage n ’interviendra que pour les classes dérivées de B.
47
Spécification de l’héritageSpécification de l’héritage
Nous pouvons donc préciser pour une classe, la politique d’accès de ses propresclasses dérivées.Si B dérive de A avec le mot clé:
public: La protection des membres de la classe A reste inchangée au niveau de B.On peut imaginer chaque objet de la classe dérivée comme un objet de laclasse de base.
protected: Les membres public et protected de A sont considérés comme protected dans la classe B.Dans ce cas, les classes dérivées de B ont toujours accès aux membres de A.
private: Les membres public et protected de A sont considérés comme private dans la classe B. Les fonctions deviennent des utilitaires.Les classes dérivées de B n’ont plus accès aux membres de A.Forme alternative de la composition (voir ultérieurement).
48
Sommaire de l’accessibilité des membres Sommaire de l’accessibilité des membres de la classe de base dans une classe dérivéede la classe de base dans une classe dérivée
Mode d’accèsaux membres dela classe de base
Héritage public Héritage protected Héritage private
publicpublic dans la classedérivée.Accessible directementà partir de toute fonctionmembre, friend ou nonmembre.
protected dans la classedérivée.Accessible directementà partir de toute fonc-tion membre ou friend.
private dans la classedérivée.Accessible directe-ment à partir de toutefonction membre oufriend.
protected
protected dans la classedérivée.Accessible directementà partir de toute fonctionmembre ou friend.
protected dans la classedérivée.Accessible directementà partir de toute fonc-tion membre ou friend.
private dans la classedérivée.Accessible directe-ment à partir de toutefonction membre oufriend.
49
Sommaire de l’accessibilité des membres Sommaire de l’accessibilité des membres de la classe de base dans une classe dérivéede la classe de base dans une classe dérivée
Mode d’accèsaux membres dela classe de base
Héritage public Héritage protected Héritage private
privatemasqué dans la classedérivée.Accessible directementà partir de toute fonctionmembre ou friend par lebiais des fonctionsmembres public ouprotected de la classede base.
masqué dans la classedérivée.Accessible directementà partir de toute fonc-tion membre ou friendpar le biais desfonctions membrespublic ou protectedde la classe de base.
masqué dans la classedérivée.Accessible directe-ment à partir de toutefonction membre oufriend par le biais desfonctions membrespublic ou protectedde la classe de base.
Chapitre V - Héritage ou dérivation d'une classe
50
Spécification de l’héritageSpécification de l’héritage
L’étiquette de protection private utilisée par la classe de base ne peut pas êtremodifiée par les classes dérivées.
Par l’héritage, vous ne pouvez qu’augmenter le niveau de sécurité, jamais lediminuer.
Dans la pratique, les 2 spécifications d’héritage protected et private sont rarementutilisées puisqu’elles ont tendance à couper la relation d’héritage.
Chapitre V - Héritage ou dérivation d'une classe
51
Spécification de l ’héritageSpécification de l ’héritageExemple:
class A{
public:int i;
protected:int j;
private:int z;
};class B : private A{
// B a accès à A::i et A::j};
class C : public B{
// C n’a pas accès aux données de A.};class D : protected A{
// D a accès à A::i et A::j};class E : public D{
// E a accès à A::i et A::j};void main(){
E e; // e.i n’est pas accessible.}
Chapitre V - Héritage ou dérivation d'une classe
52
Héritage, constructeurs et Héritage, constructeurs et destructeursdestructeurs
L’héritage entraîne la création d ’objets en cascade.Ex.: Si B dérive de A, la création d’un objet de type B entraîne automatiquement
la création d’un objet de type A.
La création d ’un objet se traduit par l ’appel au constructeur de cette classe.
Qu’est-ce qui se passera au niveau des constructeurs des classes impliquées dansune relation d’héritage?
Le constructeur d’une classe dérivée va obligatoirement appeler le constructeur desa classe de base.
La destruction des objets liés par une relation d’héritage passe également par unenchaînement d’appels aux destructeurs des classes impliquées.
Chapitre V - Héritage ou dérivation d'une classe
53
Héritage, constructeurs et Héritage, constructeurs et destructeursdestructeurs
Exemple: les classes Polygone_2D et Polygone_2D_convexe
Polygone_2D_convexe est une classe sans constructeur ou, plus précisément, avec unconstructeur par défaut utilisé lors de la création des objets dérivés.
Le constructeur de la classe Polygone_2D était donc appelé automatiquement.
Chaque fois que vous créez un objet, s’il s’agit d’une classe dérivée, le constructeurva en premier lieu appeler le constructeur de la classe de base.
Les objets de base sont créés avant les objets dérivés.
Pour les destructeurs, c’est l’ordre inverse qui est employé: le destructeur d’uneclasse dérivée est appelé avant celui de sa classe de base.
Chapitre V - Héritage ou dérivation d'une classe
54
Héritage, constructeurs et Héritage, constructeurs et destructeursdestructeurs
Supposons que nous créions un objet d’une classe dérivée où la classe de base et laclasse dérivée contiennent toutes deux des objets d’autres classes.
Lorsqu’un objet de cette classe dérivée est créé, le constructeur des objets membresde la classe de base s’exécute en premier, suivi du constructeur des objets membresde la classe dérivée, puis du constructeur de la classe dérivée.
Les destructeurs sont appelés dans l’ordre inverse de celui des constructeurs.
Chapitre V - Héritage ou dérivation d'une classe
55
HéritageHéritage
Exemple
Liste_simple
Polygone_2D
Polygone_2D_convexe
« hérite de »
Exercices résolus (chap. IV)
Triangle_2D
« hérite de »
Chapitre V - Héritage ou dérivation d'une classe
56
HéritageHéritage « Polygone_2D.h »« Polygone_2D.h »#include "Liste_simple.h"
enum type_de_polygone {quelconque, convexe, triangle, quadrilatere};struct sommet_2D{
int x, y;};class Polygone_2D{ ...
protected:int Nb_de_sommets; /* Nombre de sommets du polyg.*/type_de_polygone statut;Liste_simple Ensemble_des_sommets;…
Chapitre V - Héritage ou dérivation d'une classe
57
HéritageHéritage « Polygone_2D.h »« Polygone_2D.h »public:
Polygone_2D();/* Permet de créer un polygone 2D quelconque à 0 sommet.
Pré - Nil.Post - Un polygone quelconque à 0 sommet est créé.*/
type_de_polygone Acces_statut();/* Retourne le type de polygone créé.
Pré - Le polygone 2D a déjà été créé.Post - Le type de polygone est retourné. */
...
Chapitre V - Héritage ou dérivation d'une classe
58
HéritageHéritage« Polygone_2D.cpp »« Polygone_2D.cpp »
#include <iostream.h>#include "Polygone_2D.h"Polygone_2D::Polygone_2D(){
Nb_de_sommets = 0;statut = quelconque;
}
type_de_polygone Polygone_2D::Acces_statut(){
return statut;}
Chapitre V - Héritage ou dérivation d'une classe
59
HéritageHéritage« Polygone_2D_convexe.h »« Polygone_2D_convexe.h »
#include "Polygone_2D.h"class Polygone_2D_convexe : public Polygone_2D{
...public:
Polygone_2D_convexe();
/* Permet de créer un polygone 2D convexe à 0 sommet.
Pré - Nil.Post - Un polygone convexe à 0 sommet est créé. */
...
Chapitre V - Héritage ou dérivation d'une classe
60
HéritageHéritage« Polygone_2D_convexe.cpp »« Polygone_2D_convexe.cpp »
#include "Polygone_2D_convexe.h"
Polygone_2D_convexe::Polygone_2D_convexe(){
Nb_de_sommets = 0; // pas nécessairestatut = convexe;
}
Chapitre V - Héritage ou dérivation d'une classe
61
HéritageHéritage « Triangle_2D.h »« Triangle_2D.h »
#include "Polygone_2D_convexe.h"class Triangle_2D : public Polygone_2D_convexe{/* Spécification fonctionnelle de la classe " Triangle_2D "
dérivée de la classe "Polygone_2D_convexe".
Composantes :Chaque composante est un sommet d'un triangle 2D.
Structure : Il existe une relation linéaire (structure) entre les sommetsdu polygone. Cette relation décrit le mode de parcours ducontour polygonal dans le sens horaire. */
Chapitre V - Héritage ou dérivation d'une classe
62
HéritageHéritage « Triangle_2D.h »« Triangle_2D.h »
public:
Triangle_2D();
/* Permet de créer un triangle 2D à 0 sommet.
Pré - Nil.Post - Un triangle à 0 sommet est créé. */
};
Chapitre V - Héritage ou dérivation d'une classe
63
HéritageHéritage « Triangle_2D.cpp »« Triangle_2D.cpp »
#include "Triangle_2D.h"
Triangle_2D::Triangle_2D(){
Nb_de_sommets = 0; // inutile.statut = triangle;
}
Chapitre V - Héritage ou dérivation d'une classe
64
HéritageHéritage«Application Triangle_2D.cpp »«Application Triangle_2D.cpp »
#include <iostream.h>#include "Triangle_2D.h"void main(){
float a, b;Triangle_2D Q;Q.Ajouter_sommet(1, 1);Q.Ajouter_sommet(1, 3);Q.Ajouter_sommet(4, 3);if (Q.Acces_statut() == triangle)
cout << " Ceci est un triangle.";
Chapitre V - Héritage ou dérivation d'une classe
65
HéritageHéritage«Application Triangle_2D.cpp »«Application Triangle_2D.cpp »
cout << "Nombre de sommets : " << Q.Nombre_de_sommets();cout << "Aire du triangle 2D : " << Q.Aire_Polygone_2D();
Q.Point_visible_Polygone_2D_convexe(&a, &b);cout << "Point visible : " << a << " , " << b;
Q.Detruire_Polygone_2D();cout << "Nombre de sommets : " << Q.Nombre_de_sommets();
}
FIN
Chapitre V - Héritage ou dérivation d'une classe
66
Dériver une classe qui possède Dériver une classe qui possède un constructeur avec argumentsun constructeur avec arguments
Contrainte : Le constructeur de la classe dérivée appelle automatiquement celui de laclasse de base uniquement si les 2 classes impliquées possèdent unconstructeur sans argument.
Autrement, nous devons appeler le constructeur de la classe de base.
Comment : Il faut définir un constructeur dans la classe dérivée pour appeler leconstructeur de la classe de base et lui passer les arguments adéquats.
En plus des données nécessaires au constructeur de la classe de base,nous pouvons ajouter, le cas échéant, des arguments supplémentaires àvotre constructeur pour les besoins internes de votre classe.
Chapitre V - Héritage ou dérivation d'une classe
67
ExempleExemple
class Aire_de_stationnement{protected:
int Nb_places; /* Capacité maximale */int Nb_places_disponibles;
public:Aire_de_stationnement(int Capacite);/* Permet de créer une aire de stationnement dont la capacité
est fixée en paramètre.Pré - Nil.Post - Une aire de stationnement vide est créée. */
Chapitre V - Héritage ou dérivation d'une classe
68
Exemple Exemple (suite)(suite)
void Arrivee_voiture();/* Simule l'arrivée d'une nouvelle voiture dans le stationnement.
Pré - L'aire de stationnement est créée et des places sontdisponibles.
Post - Une place de moins est disponible. */
void Depart_voiture();
/* Simule le départ d'une voiture du stationnement.Pré - L'aire de stationnement est créée et n'est pas vide.Post - Une place de plus est disponible. */
Chapitre V - Héritage ou dérivation d'une classe
69
Exemple Exemple (suite)(suite)
bool Capacite_maximum_atteinte();/* Vérifie s'il existe des places disponibles.
Pré - L'aire de stationnement est créée.Post - Retourne true si aucune place n'est disponible.
False autrement. */};class Stationnement_pour_handicapes : public Aire_de_stationnement{
public:Stationnement_pour_handicapes();
};
Chapitre V - Héritage ou dérivation d'une classe
70
Exemple Exemple (suite)(suite)
#include "Stationnement.h"
Aire_de_stationnement::Aire_de_stationnement(int Capacite){
Nb_places = Capacite;Nb_places_disponibles = Capacite;
}void Aire_de_stationnement::Arrivee_voiture(){
Nb_places_disponibles = Nb_places_disponibles - 1;}
Chapitre V - Héritage ou dérivation d'une classe
71
Exemple Exemple (suite)(suite)
void Aire_de_stationnement::Depart_voiture(){
Nb_places_disponibles = Nb_places_disponibles + 1;}
bool Aire_de_stationnement::Capacite_maximum_atteinte(){
if (Nb_places_disponibles == 0) return true;else return false;
}
Chapitre V - Héritage ou dérivation d'une classe
72
Exemple Exemple (suite)(suite)
Stationnement_pour_handicapes::Stationnement_pour_handicapes(): Aire_de_stationnement(3)
{}
Le constructeur dela classe dérivéepeut évoluer.
Syntaxe d’appelau constructeur
de base
La syntaxe d’appel au constructeur de base montre bien la réalité de l’ordred’appel aux constructeurs.
Chapitre V - Héritage ou dérivation d'une classe
73
Exemple Exemple (suite)(suite)
#include <iostream.h>#include "Stationnement.h"void main(){
Stationnement_pour_handicapes S;S.Arrivee_voiture(); S.Arrivee_voiture(); S.Arrivee_voiture();if (S.Capacite_maximum_atteinte() == true)
cout << " Capacite maximale atteinte ";S.Depart_voiture();if (S.Capacite_maximum_atteinte() == false)
cout << " Capacite maximale non atteinte ";}
Chapitre V - Héritage ou dérivation d'une classe
74
Ordre d’appel des constructeurs Ordre d’appel des constructeurs et destructeurset destructeurs
#include <iostream.h>
typedef enum {insecte = 0, vent, animal, eau, humain} mode_de_pollinisation;
typedef enum{guepe, coccinelle, mouche, libellule, cigale, abeille, fourmi, sauterelle, patineur}
type_insecte;
class Pollinisation{
protected : mode_de_pollinisation Mode;public : Pollinisation(mode_de_pollinisation M);
~Pollinisation();};
Chapitre V - Héritage ou dérivation d'une classe
75
Ordre d’appel des constructeurs Ordre d’appel des constructeurs et destructeurset destructeurs
Pollinisation::Pollinisation(mode_de_pollinisation M){
Mode = M;cout << "Constructeur de Pollinisation: "
<< Mode << endl;}
Pollinisation::~Pollinisation(){
cout << "Destructeur de Pollinisation: "<< Mode << endl;
}
Chapitre V - Héritage ou dérivation d'une classe
76
Ordre d’appel des constructeurs Ordre d’appel des constructeurs et destructeurset destructeurs
class Pollinisation_par_insecte : public Pollinisation{
private : type_insecte Nom_d_insecte;public : Pollinisation_par_insecte(type_insecte Nom);
~Pollinisation_par_insecte();};
Pollinisation_par_insecte::Pollinisation_par_insecte(type_insecte Nom) :Pollinisation(insecte)
{Nom_d_insecte = Nom;cout << "Constructeur de Pollinisation par insecte: "
<< Mode << " " << Nom_d_insecte << endl;}
77
Ordre d’appel des constructeurs Ordre d’appel des constructeurs et destructeurset destructeurs
Pollinisation_par_insecte::~Pollinisation_par_insecte(){
cout << "Destructeur de Pollinisation par insecte : "<< Mode << " " << Nom_d_insecte << endl;
}void main(){
Pollinisation P(vent);
{Pollinisation Q(eau);
}
Pollinisation_par_insecte R(guepe);Pollinisation_par_insecte S(abeille);
}
78
Ordre d’appel des constructeurs Ordre d’appel des constructeurs et destructeurset destructeurs
SORTIE
Constructeur de Pollinisation: 1Constructeur de Pollinisation: 3Destructeur de Pollinisation: 3Constructeur de Pollinisation: 0Constructeur de Pollinisation par insecte: 0 0Constructeur de Pollinisation: 0Constructeur de Pollinisation par insecte: 0 5Destructeur de Pollinisation par insecte: 0 5Destructeur de Pollinisation: 0Destructeur de Pollinisation par insecte: 0 0Destructeur de Pollinisation: 0Destructeur de Pollinisation: 1
Chapitre V - Héritage ou dérivation d'une classe
79
Héritage multipleHéritage multipleC++ permet de définir une classe qui dérive de 2 ou plusieurs classes.
Cette technique offre la possibilité de factoriser des attributs et des comportementsprovenant de classes qui ont peu ou pas de points communs.
Exemple : La classe C dérive à la fois des classes A et B.class C : public A, public B{};
La création d’un objet de type C entraîne la création d’un objet de type A etun objet de type B.Le constructeur de la classe C doit appeler les 2 constructeurs des classes debase (A et B).
L’héritage multiple est peu utilisée (voir plus loin d’autres techniques).
Chapitre V - Héritage ou dérivation d'une classe
80
ExempleExemple
Liste_simple
Polygone_2D
Polygone_2D_convexe
« hérite de »
Triangle_2D
« hérite de »
Caracteristiques_physiques
Objet_2D
« hérite de »
Chapitre V - Héritage ou dérivation d'une classe
81
Classe Classe « Caracteristiques_physiques »« Caracteristiques_physiques »
class Caracteristiques_physiques{
protected:int couleur_remplissage;int couleur_contour;
public:void Init_couleur_remplissage(int C);
/* Permet d'initialiser la couleur de remplissage C.Pré - Nil.Post - La couleur de remplissage est C. */
Chapitre V - Héritage ou dérivation d'une classe
82
Classe Classe « Caracteristiques_physiques »« Caracteristiques_physiques »
void Init_couleur_contour(int C);/* Permet d'initialiser la couleur de contour C.
Pré - Nil.Post - La couleur de contour est C. */
int Donner_couleur_remplissage();/* Retourne la couleur de remplissage.
Pré - La couleur de remplissage est initialisée.Post - La couleur de remplissage est retournée. */
int Donner_couleur_contour();/* Retourne la couleur de contour.
Pré - La couleur de contour est initialisée.Post - La couleur de contour est retournée. */
};
Chapitre V - Héritage ou dérivation d'une classe
83
Classe Classe « Caracteristiques_physiques »« Caracteristiques_physiques »
#include "Caracteristiques_physiques.h"void Caracteristiques_physiques::Init_couleur_remplissage(int C){
couleur_remplissage = C;}
void Caracteristiques_physiques::Init_couleur_contour(int C){
couleur_contour = C;}
Chapitre V - Héritage ou dérivation d'une classe
84
Classe Classe « Caracteristiques_physiques »« Caracteristiques_physiques »
int Caracteristiques_physiques::Donner_couleur_remplissage(){
return couleur_remplissage;}
int Caracteristiques_physiques::Donner_couleur_contour(){
return couleur_contour;}
Chapitre V - Héritage ou dérivation d'une classe
85
Classe « Objet_2D »Classe « Objet_2D »
#include "Polygone_2D.h"#include "Caracteristiques_physiques.h"class Objet_2D:public Polygone_2D, public Caracteristiques_physiques{
protected:int repere_x;int repere_y;
public:Objet_2D(int x, int y);/* Permet de créer un objet 2D avec un repère x, y.
Pré - Nil.Post - Un objet 2D est créé. */
Chapitre V - Héritage ou dérivation d'une classe
86
Classe « Objet_2D »Classe « Objet_2D »
void Modifier_repere(int x, int y);/* Permet de modifier le repère de l'objet 2D.
Pré - L'objet 2D a été créé.Post - Le repère de l'objet est maintenant x, y.*/
void Donner_repere(int * x, int * y);/* Retourne en paramètre le repère de l'objet.
Pré - L'objet 2D a été créé.Post - Le repère de l'objet est retourné. */
};
Chapitre V - Héritage ou dérivation d'une classe
87
Classe « Objet_2D »Classe « Objet_2D »#include "Objet_2D.h"Objet_2D::Objet_2D(int x, int y)
: Polygone_2D(), Caracteristiques_physiques(){
repere_x = x; repere_y = y;}void Objet_2D::Modifier_repere(int x, int y){
repere_x = x; repere_y = y;}void Objet_2D::Donner_repere(int * x, int * y){
*x = repere_x; *y = repere_y;}
Chapitre V - Héritage ou dérivation d'une classe
88
Classe « Application Classe « Application Objet_2D »Objet_2D »
#include <iostream.h>#include "Objet_2D.h"void main(){
int x, y;Objet_2D Q(1,2);Q.Ajouter_sommet(1, 1); Q.Ajouter_sommet(1, 3);Q.Ajouter_sommet(2, 3); Q.Ajouter_sommet(2, 2);Q.Ajouter_sommet(3, 2); Q.Ajouter_sommet(3, 3);Q.Ajouter_sommet(4, 3); Q.Ajouter_sommet(4, 1);Q.Init_couleur_remplissage(2); Q.Init_couleur_contour(3);
Chapitre V - Héritage ou dérivation d'une classe
89
Classe « Application Objet_2D »Classe « Application Objet_2D »
cout << "Nombre de sommets : " << Q.Nombre_de_sommets();cout << "Aire du polygone 2D : " << Q.Aire_Polygone_2D();cout << "Couleur de remplissage : " <<Q.Donner_couleur_remplissage();cout << "Couleur de contour : " << Q.Donner_couleur_contour();Q.Donner_repere(&x, &y);cout << "Repere : " << x << " " << y;
Q.Detruire_Polygone_2D();cout << "Nombre de sommets : " << Q.Nombre_de_sommets();
}
Chapitre V - Héritage ou dérivation d'une classe
90
Héritage multipleHéritage multiple
Une autre approche à privilégier pour définir la classe Objet_2D passe par leconcept de classe interne.
Chapitre V - Héritage ou dérivation d'une classe
91
Multiples inclusions d’un fichier en-têteMultiples inclusions d’un fichier en-tête
Pour empêcher de multiples inclusions d’un fichier en-tête, la déclaration d’une classedoit être comprise dans le code de précompilation suivant :
#ifndef Client_h#define Client_h
…..#endif
Cela empêche l’inclusion du code situé entre #ifndef et #endif si le nom Client_h estdéjà défini.
Le nom de la constante symboliqueest défini par convention.
Chapitre V - Héritage ou dérivation d'une classe
92
Classes virtuellesClasses virtuelles
Utilisées dans le cas de l’héritage multiple afin de permettre à plusieurs classesde partager le même objet de base.
A
B C
D
class A{};class B : public A{};class C : public A{};class D : public B, public C{};
Chapitre V - Héritage ou dérivation d'une classe
93
Classes virtuellesClasses virtuelles
Création d ’un objet de type D:
B, A C, A D car B dérive de A, C dérive de A.
2 objets de type A sont créés.
Cela peut provoquer des erreurs si l’on tente d’accéderaux membres de A.
Pour compenser un mauvais diagramme de classe, on peut faire en sorte que laclasse A soit une classe virtuelle.
Ainsi, il n’existera alors qu’un seul objet de type A pour chaque objet de type D.
Chapitre V - Héritage ou dérivation d'une classe
94
Classes virtuellesClasses virtuelles
class A{};class B : virtual public A{};class C : virtual public A{};class D : public B, public C{};
Peu d’intérêt dans la mesure où elles neservent généralement qu’à compenser ladéficience d’une hiérarchie de classes.
éviter ce style d’architecture
Chapitre V - Héritage ou dérivation d'une classe
95
ConclusionConclusion
Les utilisateurs n’ont pas besoin de voir le code source des classes à partir desquellesils héritent.
La création d’une classe dérivée n’affecte en rien le code source de sa classe de base;l’intégrité d’une classe de base est préservée par l’héritage.
Des modifications apportées à une classe de base n’impliquent pas de changement auniveau des classes dérivées aussi longtemps que les interfaces public et protected dela classe de base demeurent inchangées.
Toutefois, les classes dérivées peuvent nécessiter une nouvelle compilation.
FIN