Mehrfachvererbung
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 53 von 104.
C++ ermöglicht es einer Klasse, gleichzeitig von mehreren Basisklassen zu erben. Dies wird als Mehrfachvererbung bezeichnet und ermöglicht es Ihnen, Funktionen aus verschiedenen Klassenhierarchien zu kombinieren.
Um von mehreren Klassen zu erben, trennen Sie diese durch Kommas:
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();
}
};Die Klasse MultiFunctionDevice hat nun Zugriff auf Methoden sowohl von Printer als auch von Scanner:
MultiFunctionDevice mfd;
mfd.print(); // Von Printer
mfd.scan(); // Von Scanner
mfd.copy(); // Eigene MethodeKonstruktoren werden in der Reihenfolge aufgerufen, in der die Basisklassen in der Vererbungsdeklaration aufgeführt sind (von links nach rechts), und Destruktoren in umgekehrter Reihenfolge. Sie können jedem Basiskonstruktor in der Initialisierungsliste Argumente übergeben:
class MultiFunctionDevice : public Printer, public Scanner {
public:
MultiFunctionDevice() : Printer(), Scanner() {}
};Ein potenzielles Problem tritt auf, wenn beide Basisklassen ein Element mit demselben Namen haben. Dies führt zu Mehrdeutigkeit, und Sie müssen den Bereichsauflösungsoperator verwenden, um anzugeben, welches Element Sie meinen:
class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};
C obj;
obj.A::show(); // Rufe die Version von A auf
obj.B::show(); // Rufe die Version von B aufMehrfachvererbung ist leistungsstark, kann aber zu komplexen Situationen führen, insbesondere wenn Basisklassen einen gemeinsamen Vorfahren haben. Wir werden diese Herausforderung in der nächsten Lektion untersuchen.
Aufgabe
EinfachLass uns ein Smart-Home-Gerätesystem erstellen, das mithilfe von Mehrfachvererbung Funktionen mehrerer Basisklassen kombiniert. Du wirst Geräte erstellen, die sich sowohl mit WiFi verbinden als auch per Sprache steuern lassen, und diese Funktionen anschließend zu einem einheitlichen intelligenten Lautsprecher kombinieren.
Du organisierst deinen Code auf drei Dateien verteilt:
WiFiDevice.h: Definiere eineWiFiDevice-Klasse, die jedes Gerät repräsentiert, das sich mit einem Netzwerk verbinden kann:- Ein geschütztes
std::string networkName-Element - Einen Konstruktor, der einen Netzwerknamen entgegennimmt und ihn speichert
- Eine öffentliche
connect()-Methode, die Folgendes ausgibt:Connecting to WiFi: <networkName> - Eine öffentliche
status()-Methode, die Folgendes ausgibt:WiFi Status: Connected
- Ein geschütztes
VoiceControl.h: Definiere eineVoiceControl-Klasse, die jedes Gerät mit Sprachfunktionen repräsentiert:- Ein geschütztes
std::string assistantName-Element - Einen Konstruktor, der einen Namen des Sprachassistenten entgegennimmt und ihn speichert
- Eine öffentliche
listen()-Methode, die Folgendes ausgibt:<assistantName> is listening... - Eine öffentliche
status()-Methode, die Folgendes ausgibt:Voice Status: Active
- Ein geschütztes
main.cpp: Lies drei Eingaben ein (jeweils in einer eigenen Zeile):- Gerätename (String)
- Name des WiFi-Netzwerks (String)
- Name des Sprachassistenten (String)
Definiere eine
SmartSpeaker-Klasse, die öffentlich vonWiFiDeviceundVoiceControlerbt:- Ein privates
std::string deviceName-Element - Einen Konstruktor, der alle drei Parameter entgegennimmt, den Netzwerknamen mithilfe der Initialisierungsliste an
WiFiDeviceund den Namen des Sprachassistenten anVoiceControlübergibt und den Gerätenamen speichert - Eine
powerOn()-Methode, die Folgendes ausgibt:<deviceName> powering on..., und anschließendconnect()undlisten()aufruft - Eine
showAllStatus()-Methode, die den Gerätenamen ausgibt und anschließend den Bereichsauflösungsoperator verwendet, um beidestatus()-Methoden aufzurufen und die Mehrdeutigkeit aufzulösen
Erstelle ein
SmartSpeaker-Objekt mit den Eingabewerten. RufepowerOn()auf, gib eine leere Zeile aus und rufe anschließendshowAllStatus()auf.
Beispielsweise mit den Eingaben Echo, HomeNetwork und Alexa:
Echo powering on...
Connecting to WiFi: HomeNetwork
Alexa is listening...
Echo Status:
WiFi Status: Connected
Voice Status: ActiveDie Methode showAllStatus() sollte den Gerätenamen gefolgt von " Status:" in einer Zeile ausgeben und anschließend die status()-Methode jeder Basisklasse mithilfe von WiFiDevice::status() und VoiceControl::status() aufrufen, um Mehrdeutigkeiten zu vermeiden, da beide Basisklassen eine Methode mit demselben Namen besitzen.
Probier es selbst
#include <iostream>
#include <string>
#include "WiFiDevice.h"
#include "VoiceControl.h"
using namespace std;
// TODO: Definiere die Klasse SmartSpeaker, die öffentlich von WiFiDevice und VoiceControl erbt
// - Privates Mitglied: deviceName (string)
// - Konstruktor: nimmt deviceName, networkName, assistantName entgegen
// Verwende die Initialisierungsliste, um networkName an WiFiDevice und assistantName an VoiceControl zu übergeben
// - powerOn() Methode: gibt "<deviceName> powering on..." aus, ruft dann connect() und listen() auf
// - showAllStatus() Methode: gibt "<deviceName> Status:" aus, ruft dann beide status() Methoden auf
// unter Verwendung der Bereichsauflösung (WiFiDevice::status() und VoiceControl::status())
class SmartSpeaker {
// TODO: Implementiere die Klasse SmartSpeaker hier
};
int main() {
string deviceName, networkName, assistantName;
getline(cin, deviceName);
getline(cin, networkName);
getline(cin, assistantName);
// TODO: Erstelle ein SmartSpeaker Objekt mit den Eingabewerten
// TODO: Rufe powerOn() auf
// TODO: Gib eine Leerzeile aus
// TODO: Rufe showAllStatus() auf
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamespaces & GültigkeitsbereichEinführung in OOP mit C++Klassen vs. ObjekteDer „this“-ZeigerMethoden (Member-Funktionen)Attribute (Datenmember)Grundlagen zu Ctors & DtorsRückblick – Einfacher Taschenrechner4Klassenattribute
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen und -KlassenZusammenfassung – Bankkontoverwaltung7Vererbung
Grundlagen der VererbungZugriffsebenen bei der VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick – Mitarbeiterhierarchie2Speicherverwaltung
Stack- vs. Heap-SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Intelligente Zeiger in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsbezeichner in C++Zugriffsbezeichner im DetailInformationsverbergungStruct vs. KlasseVerschachtelte und innere KlassenWiederholung – Studierendenverwaltungssystem8Polymorphie
Polymorphie zur Compilezeit vs. LaufzeitFunktionsüberladungVirtuelle Funktionen erneut betrachtetRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIRückblick – Shape-Calculator3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorMove-KonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktor im DetailDrei-/Fünf-/Null-RegelZusammenfassung – String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladung der Operatoren [] und ()TypkonvertierungsoperatorenWiederholung – Matrix-Klasse9Templates
FunktionstemplatesKlassen-TemplatesTemplate-SpezialisierungVariadische TemplatesGrundlagen zu SFINAE und Type TraitsRückblick – Generischer ContainerÜbe selbstständig: Online-C++-Compiler