0% ont trouvé ce document utile (0 vote)
35 vues30 pages

Main 7

Ce document présente le concept d'héritage en programmation orientée objet (POO) avec C++. Il explique comment créer des classes dérivées à partir de classes de base, en partageant des attributs et des méthodes, tout en abordant les niveaux d'accès et la gestion des constructeurs. L'héritage permet de réduire la redondance et d'organiser le code de manière plus efficace.

Transféré par

khalid haddou
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
35 vues30 pages

Main 7

Ce document présente le concept d'héritage en programmation orientée objet (POO) avec C++. Il explique comment créer des classes dérivées à partir de classes de base, en partageant des attributs et des méthodes, tout en abordant les niveaux d'accès et la gestion des constructeurs. L'héritage permet de réduire la redondance et d'organiser le code de manière plus efficace.

Transféré par

khalid haddou
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

L’héritage

Programmation Orientée Objet en C++


Module: S5 - IFA et MIASI

Pr. Abdessamad EL BOUSHAKI


[Link]@[Link]

FST Marrakech
Université Cadi Ayyad

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 1/30
L’héritage

L’héritage

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 2/30
L’héritage

Problématique

Gérer des produits en vente dans un magasin.


Chaque produit comporte une référence, un nom, un prix HT et un prix TTC.

Le taux de TVA est de 20, sauf pour les produits culturels : 5.5.

Les produits périssables ont une date limite de vente.

Le matériel multimédia a une durée de garantie exprimée en années.

Chaque produit peut afficher une « étiquette » contenant référence, prix, et


informations supplémentaires.
Sans héritage :
Définir les classes produitstandard, produitculturel,
produitperissable, produitmultimedia... et copier/coller du code !

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 3/30
L’héritage

Solution

Tous les produits ont des données communes (la référence...) et des
comportements communs (l’affichage de l’étiquette, le calcul du prix TTC)

Créer une classe produit qui regroupe (factorise) ce qui est commun à tous
les produits et une classe fille
I produitperissable qui contient ce qui est particulier à un produit périssable.
I Et on crée d’autres classes filles de produit pour les autres produits
particuliers.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 4/30
L’héritage

Définition

La notion d’héritage est l’un des fondements de POO.

Consiste à définir une classe, dite classe dérivée ou classe fille, à partir d’une
autre classe, dite classe de base ou classe mère, en récupérant
automatiquement dans la classe dérivée tous les membres de la classe de
base, et en lui en ajoutant éventuellement de nouveaux membres.

En pratique, pour déterminer si une classe B hérite d’une classe A, il suffit de


savoir s’il existe une relation "est un"entre B et A.

Souvent, on utilise l’héritage simple : une classe fille a une seul classe mère.
On parle d’héritage multiple quand une classe fille a plusieurs classes mères.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 5/30
L’héritage

Définition

Plus précisément, lorsqu’une sous-classe B est créée à partir d’une classe A, B


va hériter l’ensemble:
I des attributs de A
I des méthodes de A (sauf les constructeurs/destructeurs)

Les attributs et méthodes de A vont être disponibles pour B sans que l’on ait
besoin de les redéfinir explicitement dans B.

De plus :
I des attributs et/ou méthodes supplémentaires peuvent être définis par la
sous-classe B
I ces membres constituent l’enrichissement apporté par cette sous-classe.

L’héritage permet donc :


I d’expliciter des relations structurelles et sémantiques entre classes
I de réduire les redondances de description et de stockage des propriétés

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 6/30
L’héritage

La pratique en C++

Définition d’une sous-classe en C++ :


Syntaxe
class N omClasseParente
{

// corps de la classe m è re

};

class NomClasseEnfant : public N o m C l a s s e P a r e n t e


{
/* * Ici on d é finit des nouveaux attributs et
des nouvelles m é thodes
qui sp é cialisent la sous - classe * */
// ...
};

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 7/30
L’héritage

Exemple
Supposez que nous disposions de la classe Point suivante :

class Point
{
private :
int x ;
int y ;

public :
void initialise ( int abs , int ord ) ;
void deplace ( int dx , int dy ) ;
void afficher () ;
};
void Point :: initialise ( int abs , int ord )
{
x = abs ; y = ord ;
}
void Point :: deplace ( int dx , int dy )
{
x += dx ; y += dy ;
}
void Point :: afficher ()
{
cout << " Je suis en " << x << " " << y << endl ;
}

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 8/30
L’héritage

Exemple
Imaginons que nous ayons besoin d’une classe Pixel, destinée à manipuler
des points colorés d’un plan.
Une telle classe peut manifestement disposer des mêmes fonctionnalités que
la classe Point, auxquelles on pourrait adjoindre:
I un attribut nommé couleur, de type int, destiné à représenter la couleur
d’un pixel,
I une méthode nommée colore, chargée de définir la couleur.

Une classe Pixel, dérivée de Point


class Pixel : public Point // Un pixel color é est avant tout un point
{
private :
int couleur ;

public :
void colore ( int couleur ) ;
};
void Pixel :: colore ( int couleur )
{
this . couleur = couleur ;
}

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 9/30
L’héritage

Exemple

Disposant de cette classe, nous pouvons déclarer des variables de type Pixel
et créer des objets de ce type de manière usuelle, par exemple :

Pixel px1 ; // d é claration d ’ une instance pixel


Pixel * px2 = new Pixel ; // allocation dynamique pour un pixel

Tout objet d’une classe dérivée cumule les champs dérivés dans la classe de
base avec ceux définis dans sa propre classe.
Un objet de type Pixel peut alors faire appel :
I aux méthodes publiques de Pixel, ici colore ;
I mais aussi aux méthodes publiques de Point : initialise, deplace et
afficher.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 10/30
L’héritage

Accès aux membres d’une sous-classe

Si la classe B hérite des données et méthodes de la classe A, cela ne veut pas


forcément dire que la classe B ait accès à toutes les données et méthodes de
la classe A. En effet, héritage n’est pas synonyme d’accessibilité.

Lorsqu’une donnée de la classe supérieure est déclarée en mode private, la


classe dérivée ne peut ni consulter ni modifier directement cette donnée
héritée. L’accès ne peut se réaliser qu’au travers des méthodes public de la
classe supérieure.

Il est possible, grâce à la protection protected, d’autoriser l’accès en


consultation et modification des données de la classe supérieure. Les données
marquées protected de la classe A sont alors accessibles depuis la classe B,
mais pas depuis une autre classe.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 11/30
L’héritage

Cas de membres privés de la classe de base


Une méthode d’une classe dérivée n’a pas accès aux membres privés de sa
classe de base.
class Point
{
private :
int x , y ;
};

class Pixel : public Point


{
private :
int couleur ;
public :
void affichePix () // m é thode affichant les coordonn é es
// et la couleur
{
cout << " Je suis en " << x << " , " << y << endl ;
/* * NON : x et y sont priv é s * */
cout << " et ma couleur est : " << couleur << endl ;
}
};

Ici, la méthode affichePix de Pixel n’a pas accès aux champs privés x et
y de sa classe de base.
Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 12/30
L’héritage

Cas de membres publics ou protégés de la classe de base


Une méthode d’une classe dérivée a accès aux membres publics ou protégés
de sa classe de base.
class Point
{
protected : // public :
int x , y ;
};

class Pixel : public Point


{
private :
int couleur ;
public :
void affichePix () // m é thode affichant les coordonn é es
// et la couleur
{
cout << " Je suis en " << x << " , " << y << endl ;
/* * OUI : x et y sont accessibles * */
cout << " et ma couleur est : " << couleur << endl ;
}
};

Ici, la méthode affichePix de Pixel a accès aux champs publics ou


protégés x et y de sa classe de base.
Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 13/30
L’héritage

Cas de méthodes publics et attributs privées de la classe de


base
Exemple
class Point
{
private :
int x , y ;
public :
void initialise ( int abs , int ord ) { x = abs ; y = ord ;}
void affiche () { cout << " Je suis en " << x << " " << y << endl ;}
};
class Pixel : public Point
{
private :
int couleur ;
public :
void affichePix ()
{
affiche () ; // é quivalent à this - > affiche ()
cout << " et ma couleur est : " << couleur << endl ;
}
void initialisePix ( int x , int y , int couleur )
{
initialise (x , y ) ; this . couleur = couleur ;
}
};

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 14/30
L’héritage

Restriction des accès lors de l’héritage

Les niveaux d’accès peuvent être modifiés lors de l’héritage.


Syntaxe
class ClasseEnfant : [ acces ] classeParente
{
/* D é claration des membres
sp é cifiques à la sous - classe */
// ...
};

où acces est le mot-clé public, protected ou private.


Par défaut, l’accès est privé.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 15/30
L’héritage

Restriction des accès lors de l’héritage

Récapitulatif des changements de niveaux d’accès aux membres hérités, en


fonction du niveau initial et du type d’héritage:

Statut des membres de base


Public Protected Private
Mode de Public Public Protected Inaccessible
dérivation Protected Protected Protected Inaccessible
Private Private Private Inaccessible

Remarque :
I Lorsqu’une classe dérivée possède des fonctions amies, ces derniers disposent
exactement des mêmes autorisations d’accès que les fonctions membres de la
classe dérivée. En particulier, les fonctions amies d’une classe dérivée auront
bien accès aux membres déclarés protégés dans sa classe de base.
I En revanche, les déclarations d’amitié ne s’héritent pas. Ainsi, si f a été
déclaré amie d’une classe A et si B dérive de A, f n’est pas automatiquement
amie de B.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 16/30
L’héritage

Utilisation des droits d’accès - Récapitulatif

Membres publics : accessibles pour les utilisateurs de la classe.

Membres protégés : accessibles aux autres programmeurs pour


d’éventuelles extensions par héritage de la classe.

Membres privés : utilisable par les fonctions membres et les classes et


opérations amies de cette seule classe, à l’exception des sous-classes;

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 17/30
L’héritage

Le constructeur d’une classe héritée

Les constructeurs des classes mères ne peuvent être utilisés pour construire
des instances de la classe fille.
⇒ Il faut donc définir de nouveaux constructeurs.
Lors de l’instanciation d’une sous-classe, il faut initialiser :
I les attributs propres à la sous-classe.
I les attributs hérités des super-classes.
MAIS...
I il ne doit pas être à la charge du concepteur des sous-classes de réaliser
lui-même l’initialisation des attributs hérités.
I L’accès à ces attributs peut notamment être interdit.
L’initialisation des attributs hérités doit donc se faire au niveau des classes
où ils sont explicitement définis.
Solution : l’initialisation des attributs hérités doit se faire en invoquant les
constructeurs des super-classes.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 18/30
L’héritage

Le constructeur d’une classe héritée


L’invocation du constructeur de la super-classe se fait au début de la section
d’appel au constructeurs des attributs.
Syntaxe
SousClasse ( liste de parametres ) : SuperClasse ( Arguments ) ,
attribut1 ( valeur1 ) ,... , attributN ( valeurN )
{
// corps du constructeur
}

La construction d’un objet d’une classe dérivée comporte:


I la réservation de la place pour l’objet;
I l’appel d’un constructeur approprié (constructeur par défaut) de la classe de
base;
I appel des constructeurs pour les membres objets;
I l’exécution du corps de la fonction constructeur.
Remarque : Lorsque la super-classe admet un constructeur par défaut,
l’invocation explicite de ce constructeur dans la sous-classe n’est pas
obligatoire, Le compilateur se charge de réaliser l’invocation du constructeur.
Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 19/30
L’héritage

Le constructeur d’une classe héritée


Exemple: Pour construire un objet Pixel, nous devons définir ses
coordonnées et sa couleur. Le constructeur de la classe Pixel doit appeler le
constructeur de la classe Point.
class Point
{
private :
int x , y ;
public :
Point ( int x , int y ) : this . x ( x ) , this . y ( y ) {}
};

class Pixel : public Point


{
private :
int couleur ;

public :
Pixel ( int x , int y , int couleur ) : Point (x , y ) , /* * appel de
constructeur de la classe de base , auquel on fournit en
arguments les valeurs de x et de y * */
this . couleur ( couleur ) // in itiali sation des membres d ’ objets
{ }
};

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 20/30
L’héritage

Le constructeur d’une classe héritée


Si la classe parente n’admet pas de constructeur par défaut, l’invocation
explicite d’un de ses constructeurs est obligatoire dans les constructeurs de
la sous-classe.
Exemple
class Rectangle
{
protected :
double largeur ;
double hauteur ;
public :
Rectangle ( double l , double h ) : largeur ( l ) , hauteur ( h ) {}
// le reste de la classe ...
};
class Rectangle3D : public Rectangle
{
private :
double profondeur ;
public :
Rectangle3D ( double l , double h , double p )
: Rectangle (l , h ) , profondeur ( p ) {}
// le reste de la classe ...
};

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 21/30
L’héritage

Le constructeur d’une classe héritée


Si la classe de base admettre au moins un constructeur explicite.
Ici il n’est pas nécessaire d’invoquer explicitement le constructeur de la classe
parente puisque celle-ci admet un constructeur par défaut.

Exemple
class Rectangle
{
protected :
double largeur ;
double hauteur ;
public :
Rectangle () : largeur (0.0) , hauteur (0.0) {}
// le reste de la classe ...
};
class Rectangle3D : public Rectangle
{
private :
double profondeur ;
public :
Rectangle3D ( double p )
: profondeur ( p ) {}
// le reste de la classe ...
};

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 22/30
L’héritage

Le destructeur d’une classe héritée

Le destructeur des classes mères est toujours appelé implicitement après


l’exécution du destructeur de la classe fille.

On n’appelle jamais explicitement le destructeur des classes mères dans le


destructeur de la classe fille.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 23/30
L’héritage

Redéfinition de méthodes
La redéfinition de méthode consiste à fournir dans une sous-classe une
nouvelle implémentation d’une méthode déjà déclarée dans une classe
parent.
La redéfinition n’est pas obligatoire, mais elle permet d’adapter un
comportement et de le spécifier pour la sous-classe.
Pour la réaliser, il suffit de créer dans la sous-classe une méthode avec
l’exacte même signature que la méthode originale dans la classe parent.
Même nom, mêmes arguments, code différent.
On peut rappeler la version d’origine (de la classe parent) avec l’opérateur de
portée ::.

class A
{
public :
void Fonct () { ..... }
}
class B : public A
{
public :
void Fonct () { ..... }
}

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 24/30
L’héritage

Redéfinition de méthodes
Exemple de redéfinition de la méthode afficher dans la classe dérivée Pixel
class Point
{
private :
int x , y ;
public :
void afficher () { cout << " Je suis en " << x << " " << y << endl ; }
// le reste de la classe ...
};
class Pixel : public Point
{
private :
int couleur ;

void afficher ()
{
Point :: afficher () ;
cout << " et ma couleur est : " << couleur << endl ;
}
// le reste de la classe ...
};
main ()
{
Pixel px (5 ,3 , 2) ;
px . affiche () ; // ici , il s ’ agit de affiche de Pixel
}

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 25/30
L’héritage

Redéfinition et surdéfinition
Il va de soi que lorsqu’une fonction est redéfinie dans une classe dérivée, elle
masque une fonction de même signature de la classe de base.
En revanche, les choses sont moins naturelles en cas de surdéfinition ou,
même, de mixage entre ces deux possibilités. Considérez :

class A
{
public :
void f ( int n ) { ..... } // f est surd é finie
void f ( char c ) { ..... } // dans A
} ;
class B : public A
{
public :
void f ( float x ) { ..... } // on ajoute une trois è me d é finition dans B
} ;
main ()
{
int n ; char c ; A a ; B b ;
a . f ( n ) ; // appelle A :: f ( int ) ( r è gles habituelles )
a . f ( c ) ; // appelle A :: f ( char ) ( r è gles habituelles )
b . f ( n ) ; // appelle B :: f ( float ) ( alors que A :: f ( int ) conviendrait )
b . f ( c ) ; // appelle B :: f ( float ) ( alors que A :: f ( char ) conviendrait )
}

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 26/30
L’héritage

Redéfinition et surdéfinition

Si on effectuait dans B une redéfinition de l’une des fonctions f de A, comme


dans :
class A
{
public :
void f ( int n ) { ..... } // f est surd é finie
void f ( char c ) { ..... } // dans A
} ;
class B : public A
{
public :
void f ( int n ) { ..... } // on red é finit f ( int ) dans B
} ;
main ()
{
int n ; char c ; B b ;
b . f ( n ) ; // appelle B :: f ( int )
b . f ( c ) ; // appelle B :: f ( int )
}

Dans ce cas, on voit qu’une redéfinition d’une méthode dans une classe
dérivée cache en quelque sorte les autres.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 27/30
L’héritage

Compatibilité entre classe de base et classe dérivée

En POO, on considère d’une manière générale qu’un objet d’une classe


dérivée peut remplacer un objet d’une classe de base (l’objet de la classe
dérivée possède toutes les potentialités pour remplacer un objet de la classe
de base). L’inverse n’est pas vrai.

En C++, cette compatibilité ne s’applique que pour la dérivation publique et


se résume aux conversions implicites suivantes :
I un objet de type dérivé dans un objet de type de base,
I un pointeur sur un objet de type dérivé en un pointeur sur un objet de type de
base.

Après une telle conversion, seules les fonctionnalités de l’objet de type de


base ne sont applicables.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 28/30
L’héritage

Compatibilité entre classe de base et classe dérivée

Si B hérite de A, alors toutes les instances de B sont aussi des instances de A,


et il est donc possible de faire :

A a; B b; a = b;

// Propri é t é conserv é e lorsqu ’ on utilise des pointeurs :


A * pa ; B * pb =& b ; pa = pb ; /* * car pointer sur un B c ’ est avant tout
pointer sur un A * */
// Evidement , l ’ inverse n ’ est pas vrai :
A a ; B b ; b = a ; // ERREUR !
// Pareil pour les pointeurs :
A * pa =& a ; B * pb ; pb = pa ; /* * ERREUR : car pointer sur un A n ’ est pas
pointer sur un B * */

Conclusion :
I Traiter un type dérivé comme s’il était son type de base est appelé
transtypage ascendant ou surtypage (upcasting).
I A l’opposé, les transtypage descendant (downcast) posent un problème
particulier car leur vérification n’est possible qu’à l’exécution. Ils nécessitent
l’utilisation d’opérateur de cast : dynamic_cast.

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 29/30
L’héritage

Héritage multiple
Une classe peut hériter de plusieurs classes. Les classes de bases sont alors
énumérées dans la définition.
class D : public B1 , public B2 {...}

Exemple :

class Point
{
int x , y ;
public :
Point (...) {...}
};
class Coul {
int couleur ;
public :
Coul (...) {...}
};
// classe d é riv é e
class Pixel : public Point , public Coul
{
...
Pixel (...) : Point (...) , Coul (...) {...}
};

Pr. Abdessamad EL BOUSHAKI (FST Marrakech) Programmation Orientée Objet en C++ 30/30

Vous aimerez peut-être aussi