Menu
Coddy logo textTech

Héritage multiple

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 53 sur 104.

Le C++ permet à une classe d'hériter de plusieurs classes de base simultanément. C'est ce qu'on appelle l'héritage multiple et cela vous permet de combiner des fonctionnalités provenant de différentes hiérarchies de classes.

Pour hériter de plusieurs classes, séparez-les par des virgules :

class Printer {
public:
    void print() {
        std::cout << "Printing document" << std::endl;
    }
};

class Scanner {
public:
    void scan() {
        std::cout << "Scanning document" << std::endl;
    }
};

class MultiFunctionDevice : public Printer, public Scanner {
public:
    void copy() {
        scan();
        print();
    }
};

La classe MultiFunctionDevice a désormais accès aux méthodes de Printer et de Scanner :

MultiFunctionDevice mfd;
mfd.print();  // Depuis Printer
mfd.scan();   // Depuis Scanner
mfd.copy();   // Sa propre méthode

Les constructeurs sont appelés dans l'ordre où les classes de base sont listées dans la déclaration d'héritage (de gauche à droite), et les destructeurs dans l'ordre inverse. Vous pouvez passer des arguments à chaque constructeur de base dans la liste d'initialisation :

class MultiFunctionDevice : public Printer, public Scanner {
public:
    MultiFunctionDevice() : Printer(), Scanner() {}
};

Un problème potentiel survient lorsque les deux classes de base possèdent un membre portant le même nom. Cela crée une ambiguïté, et vous devez utiliser l'opérateur de résolution de portée pour spécifier celui que vous visez :

class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};

C obj;
obj.A::show();  // Appeler la version de A
obj.B::show();  // Appeler la version de B

L'héritage multiple est puissant, mais il peut mener à des situations complexes, particulièrement lorsque les classes de base partagent un ancêtre commun. Nous explorerons ce défi dans la prochaine leçon.

challenge icon

Défi

Facile

Construisons un système d'appareils domestiques intelligents qui combine les capacités de plusieurs classes de base en utilisant l'héritage multiple. Vous allez créer des appareils capables à la fois de se connecter au WiFi et d'être contrôlés par la voix, puis combiner ces fonctionnalités dans une enceinte intelligente unifiée.

Vous organiserez votre code sur trois fichiers :

  • WiFiDevice.h : Définissez une classe WiFiDevice qui représente tout appareil capable de se connecter à un réseau :
    • Un membre protégé std::string networkName
    • Un constructeur qui prend un nom de réseau et le stocke
    • Une méthode publique connect() qui affiche : Connecting to WiFi: <networkName>
    • Une méthode publique status() qui affiche : WiFi Status: Connected
  • VoiceControl.h : Définissez une classe VoiceControl qui représente tout appareil doté de capacités vocales :
    • Un membre protégé std::string assistantName
    • Un constructeur qui prend un nom d'assistant et le stocke
    • Une méthode publique listen() qui affiche : <assistantName> is listening...
    • Une méthode publique status() qui affiche : Voice Status: Active
  • main.cpp : Lisez trois entrées (chacune sur une ligne séparée) :
    1. Nom de l'appareil (chaîne de caractères)
    2. Nom du réseau WiFi (chaîne de caractères)
    3. Nom de l'assistant vocal (chaîne de caractères)

    Définissez une classe SmartSpeaker qui hérite publiquement de WiFiDevice et de VoiceControl :

    • Un membre privé std::string deviceName
    • Un constructeur qui prend les trois paramètres, transmet le nom du réseau à WiFiDevice et le nom de l'assistant à VoiceControl en utilisant la liste d'initialisation, et stocke le nom de l'appareil
    • Une méthode powerOn() qui affiche : <deviceName> powering on..., puis appelle connect() et listen()
    • Une méthode showAllStatus() qui affiche le nom de l'appareil, puis utilise l'opérateur de résolution de portée pour appeler les deux méthodes status() afin de résoudre l'ambiguïté

    Créez un objet SmartSpeaker avec les valeurs d'entrée. Appelez powerOn(), affichez une ligne vide, puis appelez showAllStatus().

Par exemple, avec les entrées Echo, HomeNetwork, et Alexa :

Echo powering on...
Connecting to WiFi: HomeNetwork
Alexa is listening...

Echo Status:
WiFi Status: Connected
Voice Status: Active

La méthode showAllStatus() doit afficher le nom de l'appareil suivi de " Status:" sur une ligne, puis appeler la méthode status() de chaque classe de base en utilisant WiFiDevice::status() et VoiceControl::status() pour éviter toute ambiguïté puisque les deux classes de base possèdent une méthode portant le même nom.

Aide-mémoire

Le C++ prend en charge l'héritage multiple, permettant à une classe d'hériter de plusieurs classes de base simultanément :

class DerivedClass : public BaseClass1, public BaseClass2 {
    // Corps de la classe
};

La classe dérivée a accès aux membres de toutes les classes de base :

class Printer {
public:
    void print() {
        std::cout << "Printing document" << std::endl;
    }
};

class Scanner {
public:
    void scan() {
        std::cout << "Scanning document" << std::endl;
    }
};

class MultiFunctionDevice : public Printer, public Scanner {
public:
    void copy() {
        scan();   // Depuis Scanner
        print();  // Depuis Printer
    }
};

Les constructeurs des classes de base sont appelés dans l'ordre où ils apparaissent dans la liste d'héritage (de gauche à droite). Utilisez la liste d'initialisation pour transmettre des arguments à chaque constructeur de base :

class MultiFunctionDevice : public Printer, public Scanner {
public:
    MultiFunctionDevice() : Printer(), Scanner() {}
};

Lorsque plusieurs classes de base possèdent des membres portant le même nom, utilisez l'opérateur de résolution de portée pour lever l'ambiguïté :

class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};

C obj;
obj.A::show();  // Appelle la version de A
obj.B::show();  // Appelle la version de B

Essayez vous-même

#include <iostream>
#include <string>
#include "WiFiDevice.h"
#include "VoiceControl.h"

using namespace std;

// TODO: Définir la classe SmartSpeaker qui hérite publiquement de WiFiDevice et VoiceControl
// - Membre privé : deviceName (string)
// - Constructeur : prend deviceName, networkName, assistantName
//   Utiliser la liste d'initialisation pour passer networkName à WiFiDevice et assistantName à VoiceControl
// - Méthode powerOn() : affiche "<deviceName> powering on...", puis appelle connect() et listen()
// - Méthode showAllStatus() : affiche "<deviceName> Status:", puis appelle les deux méthodes status()
//   en utilisant la résolution de portée (WiFiDevice::status() et VoiceControl::status())

class SmartSpeaker {
    // TODO: Implémenter la classe SmartSpeaker ici
};

int main() {
    string deviceName, networkName, assistantName;
    getline(cin, deviceName);
    getline(cin, networkName);
    getline(cin, assistantName);

    // TODO: Créer un objet SmartSpeaker avec les valeurs d'entrée
    // TODO: Appeler powerOn()
    // TODO: Afficher une ligne vide
    // TODO: Appeler showAllStatus()

    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet