L'héritage permet de donner à une classe toutes les caractéristiques d'une ou de plusieurs autres classes. Les classes dont elle hérite sont appelées classes mères, classes de base ou classes antécédentes. La classe elle-même est appelée classe fille, classe dérivée ou classe descendante.
Les propriétés héritées sont les champs et les méthodes des classes de base.
Pour faire un héritage en C++, il faut faire suivre le nom de la classe fille par la liste des classes mères dans la déclaration avec les restrictions d'accès aux données, chaque élément étant séparé des autres par une virgule. La syntaxe (donnée pour class, identique pour struct) est la suivante :
class Classe_mere1 { /* Contenu de la classe mère 1. */ }; [class Classe_mere2 { /* Contenu de la classe mère 2. */ };] [...] class Classe_fille : public|protected|private Classe_mere1 [, public|protected|private Classe_mere2 [...]] { /* Définition de la classe fille. */ };
Dans cette syntaxe, Classe_fille hérite de la Classe_mere1, et des Classe_mere2, etc. si elles sont présentes.
La signification des mots clés private, protected et public dans l'héritage est récapitulée dans le tableau suivant :
Tableau 8-1. Droits d'accès sur les membres hérités
mot clé utilisé pour l'héritage | ||||
---|---|---|---|---|
Accès aux données | public | protected | private | |
mot clé utilisé | public | public | protected | private |
pour les champs | protected | protected | protected | private |
et les méthodes | private | interdit | interdit | interdit |
Ainsi, les données publiques d'une classe mère deviennent soit publiques, soit protégées, soit privées selon que la classe fille hérite en public, protégé ou en privé. Les données privées de la classe mère sont toujours inaccessibles, et les données protégées deviennent soit protégées, soit privées.
Il est possible d'omettre les mots clés public, protected et private dans la syntaxe de l'héritage. Le compilateur utilise un type d'héritage par défaut dans ce cas. Les classes de type struct utilisent l'héritage public par défaut et les classes de type class utilisent le mot clé private par défaut.
Exemple 8-5. Héritage public, privé et protégé
class Emplacement { protected: int x, y; // Données ne pouvant être accédées // que par les classes filles. public: void Change(int, int); // Méthode toujours accessible. }; void Emplacement::Change(int i, int j) { x = i; y = j; return; } class Point : public Emplacement { protected: unsigned int couleur; // Donnée accessible // aux classes filles. public: void SetColor(unsigned int); }; void Point::SetColor(unsigned int NewColor) { couleur = NewColor; // Définit la couleur. return; }
Si une classe Cercle doit hériter de deux classes mères, par exemple Emplacement et Forme, sa déclaration aura la forme suivante :
class Cercle : public Emplacement, public Forme { /* Définition de la classe Cercle. Cette classe hérite des données publiques et protégées des classes Emplacement et Forme. */ };
Il est possible de redéfinir les fonctions et les données des classes de base
dans une classe dérivée. Par exemple, si une classe B dérive de la classe A,
et que toutes deux contiennent une donnée d
, les instances de la classe
B utiliseront la donnée d
de la classe B et
les instances de la classe A utiliseront la donnée d
de la classe A. Cependant, les objets de classe B contiendront également
un sous-objet, lui-même instance de la classe de base A. Par conséquent, ils contiendront
la donnée d
de la classe A, mais cette dernière sera cachée
par la donnée d
de la classe la plus dérivée, à savoir la classe B.
Ce mécanisme est général : quand une classe dérivée redéfinit un membre d'une classe de base, ce membre est caché et on ne peut plus accéder directement qu'au membre redéfini (celui de la classe dérivée). Cependant, il est possible d'accéder aux données cachées si l'on connaît leur classe, pour cela, il faut nommer le membre complètement à l'aide de l'opérateur de résolution de portée (::). Le nom complet d'un membre est constitué du nom de sa classe suivi de l'opérateur de résolution de portée, suivis du nom du membre :
classe::membre
Exemple 8-6. Opérateur de résolution de portée et membre de classes de base
struct Base { int i; }; struct Derivee : public Base { int i; int LitBase(void); }; int Derivee::LitBase(void) { return Base::i; // Renvoie la valeur i de la classe de base. } int main(void) { Derivee D; D.i=1; // Accède à l'entier i de la classe Derivee. D.Base::i=2; // Accède à l'entier i de la classe Base. return 0; }
Précédent | Sommaire | Suivant |
Encapsulation des données | Niveau supérieur | Classes virtuelles |