Aller au contenu

Programmation C-C++/C++ : La couche objet/Héritage

Un livre de Wikilivres.
Cours de C/C++
^
C++ : La couche objet
Généralités
Extension de la notion de type du C
Déclaration de classes en C++
Encapsulation des données
Héritage
Classes virtuelles
Fonctions et classes amies
Constructeurs et destructeurs
Pointeur this
Données et fonctions membres statiques
Surcharge des opérateurs
Des entrées - sorties simplifiées
Méthodes virtuelles
Dérivation
Méthodes virtuelles pures - Classes abstraites
Pointeurs sur les membres d'une classe

Livre original de C. Casteyde

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

[modifier | modifier le wikicode]
Accès aux membres hérités Mot clé utilisé pour l'héritage
public protected private

Mot clé utilisé

pour déclarer les membres

(les champs et les méthodes)

de la classe parente

public public protected private
protected protected protected private
private private private private

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 l'héritage private par défaut.

Exemple 8-5. Héritage public, privé et protégé

[modifier | modifier le wikicode]
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 forme : public Emplacement
{
protected:
    unsigned int couleur;  // Donnée accessible
                           // aux classes filles.

public:
    void SetColor(unsigned int);
};

void forme::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

[modifier | modifier le wikicode]
struct Base
{
    int i;
};

struct Derivee : /*public*/ Base // struct's utilisent l'héritage public par défaut
{
    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;
}