Chapitre 3
HERITAGE
 
 
Précédent Suivant
 

Héritage
Syntaxe
* class B : public A { ... };
* Signifie classe B hérite de classe A
* Plusieurs catégories d'héritage
* public, protected ou private
* On ne parlera ici que du plus courant: l'héritage public
* Héritage multiple possible
* class C : public A, public B { ... };
* Exemple
class Etudiant : public Personne {
private:
...
string etablissement;
...
};
Méthodes virtuelles
* Par défaut, une méthode n'est pas virtuelle en C++
* Méthode virtuelle ==> mot-clé "virtual"
class Personne {
...
virtual void afficher(void) const {
cout << "Personne " << nom << ", " << prenom << endl;
}
};
* Le mot-clé n'est pas nécessaire dans les sous-classes
class Etudiant : public Personne {
...
void afficher(void) const { ==> la méthode est bien virtuelle
cout << "Etudiant " << nom << ", " << prenom
<< ", " << etablissement << endl;
}
};
Polymorphisme (1/2)
* Pas de polymorphisme avec les variables objets
* Etudiant e;
* Personne p;
* p = e; ==> objet tronqué: seule la partie "Personne" reste
* Polymorphisme uniquement avec les pointeurs et les références
* Exemple avec pointeurs
* Etudiant * e = new Etudiant;
* Personne * p = e;
* p->afficher(); ==> appel méthode "afficher" de "Etudiant"
* Opérateur "->" ==> accès à un membre d'un objet pointé
* p->afficher() ? (*p).afficher();
Polymorphisme (2/2)
* Exemple avec références
* Etudiant e;
* Personne & p = e;
* p.afficher(); ==> appel méthode "afficher" de "Etudiant"
* Attention aux conteneurs
* Personne tab[];
==> ne contient que des objets "Personne"
* Personne * tab[];
==> peut contenir des objets des sous-classes de "Personne"
* Personne & tab[];
==> interdit (comment l'initialiser ?)
* Conversion
* Personne * p = new Personne();
* Etudiant * e = new Etudiant();
* p = e; ==> OK, conversion ascendante
* e = p; ==> interdit par défaut, conversion descendante
* e = (Etudiant *)p; ==> forçage pouvant échouer à l'exécution
Liste d'initialisation (1/3)
* Permet de contrôler la séquence de construction d'un objet
* S'exécute avant le début du constructeur
* Permet d'éviter des opérations inutiles
* Appel explicite au constructeur de chaque attribut
Personne(const string & n,const string & p)
: nom(n), prenom(p) {
// Code constructeur
}
* Attribut absent de la liste ==> construction par défaut
Liste d'initialisation (2/3)
* Exemple d'opérations inutiles
Personne(const string & n,const string & p)
/* Attributs construits par défaut */
{
nom = n; ==> construction précédente inutile
prenom = p; ? construction précédente inutile
}
* Pas d'héritage des constructeurs
* Personne(const string & n,const string & p)
* Personne p("Nawouak","Bruno") ==> OK
* Etudiant e("Nawouak","Bruno") ==> non
Liste d'initialisation (3/3)
* Héritage ==> appel en cascade des constructeurs
* Construction "Etudiant" ==> construction "Personne"
* Sélection du constructeur possible grâce à la liste d'initialisation
* Etapes de construction d'un objet
* Construction de chaque partie de classe mère
* Construction de chaque attribut
* Code de construction propre
* Exemple
Etudiant(const string & n,const string & p,
const string & e)
: Personne(n,p), etablissement(e) {
// Code constructeur
}
* Classe mère absente de la liste ==> construction par défaut
Destruction
* Héritage ==> exécution en cascade des destructeurs
* Destruction "Etudiant" ==> destruction "Personne"
* Etapes de destruction d'un objet
* Code de destruction propre
* Destruction de chaque attribut
* Destruction de chaque partie de classe mère
* Au moins une méthode virtuelle ==> destructeur virtuel
* virtual ~Personne(void);
* Car le polymorphisme doit s'appliquer à la destruction
* Personne * p = new Etudiant;
* delete p; ==> appel "~Etudiant", puis "~Personne"
* Sans destructeur virtuel, seulement appel "~Personne"
Compléments
* Méthode abstraite = méthode sans code
* virtual void afficher(void) const = 0;
* La classe devient automatiquement abstraite
* Pas de mot-clé en C++
* Aucune instance directe de la classe possible
* Accès aux membres de la classe mère à partir de la fille
* Contrairement à Java, pas de mot-clé spécifique
* Utilisation du nom de la classe mère
* Exemple: dans la classe "Etudiant"
* "this" permet d'accéder aux membres hérités
* this.nom; ==> attribut classe "Personne"
* Mais pour les méthodes, le polymorphisme opère
* this.afficher(); ==> méthode classe "Etudiant"
* Pour éviter le polymorphisme
* Personne::afficher(); ==> méthode classe "Personne"