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" |