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éthodeLes 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 BL'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.
Défi
FacileConstruisons un système d'appareils domestiques intelligents qui combine les fonctionnalités de plusieurs classes de base à l'aide de l'héritage multiple. Vous allez créer des appareils qui peuvent à la fois se connecter au WiFi et ê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éfinir une classeWiFiDevicequi représente tout appareil capable de se connecter à un réseau :- Un membre
std::string networkNameprotégé - Un constructeur qui reçoit 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
- Un membre
VoiceControl.h: définir une classeVoiceControlqui représente tout appareil doté de fonctionnalités vocales :- Un membre
std::string assistantNameprotégé - Un constructeur qui reçoit 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
- Un membre
main.cpp: lire trois entrées (chacune sur une ligne distincte) :- Nom de l'appareil (chaîne de caractères)
- Nom du réseau WiFi (chaîne de caractères)
- Nom de l'assistant vocal (chaîne de caractères)
Définir une classe
SmartSpeakerqui hérite publiquement à la fois deWiFiDeviceet deVoiceControl:- Un membre
std::string deviceNameprivé - Un constructeur qui reçoit les trois paramètres, transmet le nom du réseau à
WiFiDeviceet le nom de l'assistant àVoiceControlà l'aide de la liste d'initialisation, puis stocke le nom de l'appareil - Une méthode
powerOn()qui affiche :<deviceName> powering on..., puis appelleconnect()etlisten() - 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éthodesstatus()afin de résoudre l'ambiguïté
Créer un objet
SmartSpeakeravec les valeurs saisies. AppelerpowerOn(), afficher une ligne vide, puis appelershowAllStatus().
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: ActiveLa 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 à l'aide de 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.
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;
}
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
1Fondamentaux de la POO
Fichiers externesGénération et compilation en C++Fichiers d’en-tête et fichiers sourceEspaces de noms et portéeIntroduction à la POO en C++Classes et objetsLe pointeur « this »Méthodes (fonctions membres)Attributs (membres de données)Bases des constructeurs et destructeursRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d’instance et statiquesAccesseurs et mutateursFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d’accès de l’héritageOrdre d’appel des constructeurs et destructeursRedéfinition des méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif : hiérarchie des employés10Vue d’ensemble de la STL
Vue d’ensemble et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - fréquence des mots13Modèles de conception, partie 1
Introduction aux modèles de conceptionModèle SingletonFabrique et fabrique abstraiteModèle BuilderModèle ObserverModèle Strategy2Gestion de la mémoire
Mémoire de pile ou de tasPointeurs et référencesMémoire dynamique (new/delete)Pointeurs intelligents en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d’accès en C++Spécificateurs d’accès en profondeurMasquage de l’informationStruct vs classeClasses imbriquées et internesRécapitulatif - Système de gestion des dossiers étudiants8Polymorphisme
Polymorphisme à la compilation vs à l’exécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d’interfaces en C++Conversion dynamique et RTTIRécapitulatif - Calculateur de formes3Constructeurs et destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d’initialisation des constructeursConstructeurs déléguésApprofondissement des destructeursRègle des trois / cinq / zéroRécapitulatif - Classe String6Surcharge des opérateurs
Introduction à la surcharge des opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l’opérateur d’affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif – Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation des templatesTemplates variadiquesBases de SFINAE et des traits de typesRécapitulatif - Conteneur génériqueEntraînez-vous par vous-même : Compilateur C++ en ligne