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
EinfachLassen Sie uns ein Smart-Home-Gerätesystem bauen, das Funktionen aus mehreren Basisklassen mithilfe von Mehrfachvererbung kombiniert. Sie werden Geräte erstellen, die sich sowohl mit dem WLAN verbinden als auch per Sprache gesteuert werden können, und diese Funktionen dann in einem einheitlichen Smart Speaker kombinieren.
Sie werden Ihren Code über drei Dateien organisieren:
WiFiDevice.h: Definieren Sie eine KlasseWiFiDevice, die jedes Gerät repräsentiert, das in der Lage ist, sich mit einem Netzwerk zu verbinden:- Ein geschütztes (protected)
std::string networkNameMitglied - Ein Konstruktor, der einen Netzwerknamen entgegennimmt und 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 (protected)
VoiceControl.h: Definieren Sie eine KlasseVoiceControl, die jedes Gerät mit Sprachfunktionen repräsentiert:- Ein geschütztes (protected)
std::string assistantNameMitglied - Ein Konstruktor, der einen Namen für den Assistenten entgegennimmt und speichert
- Eine öffentliche
listen()Methode, die Folgendes ausgibt:<assistantName> is listening... - Eine öffentliche
status()Methode, die Folgendes ausgibt:Voice Status: Active
- Ein geschütztes (protected)
main.cpp: Lesen Sie drei Eingaben ein (jede in einer separaten Zeile):- Gerätename (String)
- WLAN-Netzwerkname (String)
- Name des Sprachassistenten (String)
Definieren Sie eine Klasse
SmartSpeaker, die öffentlich von sowohlWiFiDeviceals auchVoiceControlerbt:- Ein privates
std::string deviceNameMitglied - Ein Konstruktor, der alle drei Parameter entgegennimmt, den Netzwerknamen an
WiFiDeviceund den Namen des Assistenten anVoiceControlüber die Initialisierungsliste übergibt und den Gerätenamen speichert - Eine
powerOn()Methode, die Folgendes ausgibt:<deviceName> powering on..., und dannconnect()undlisten()aufruft - Eine
showAllStatus()Methode, die den Gerätenamen ausgibt und dann den Bereichsauflösungsoperator (scope resolution operator) verwendet, um beidestatus()Methoden aufzurufen, um die Mehrdeutigkeit aufzulösen
Erstellen Sie ein
SmartSpeakerObjekt mit den Eingabewerten. Rufen SiepowerOn()auf, geben Sie eine Leerzeile aus und rufen Sie dannshowAllStatus()auf.
Zum Beispiel 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 dann die status() Methode jeder Basisklasse mit WiFiDevice::status() und VoiceControl::status() aufrufen, um Mehrdeutigkeiten zu vermeiden, da beide Basisklassen eine Methode mit demselben Namen haben.
Spickzettel
C++ unterstützt Mehrfachvererbung, was es einer Klasse ermöglicht, gleichzeitig von mehreren Basisklassen zu erben:
class DerivedClass : public BaseClass1, public BaseClass2 {
// Class body
};Die abgeleitete Klasse hat Zugriff auf die Member aller Basisklassen:
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(); // From Scanner
print(); // From Printer
}
};Die Konstruktoren der Basisklassen werden in der Reihenfolge aufgerufen, in der sie in der Vererbungsliste erscheinen (von links nach rechts). Verwenden Sie die Initialisierungsliste, um Argumente an jeden Basiskonstruktor zu übergeben:
class MultiFunctionDevice : public Printer, public Scanner {
public:
MultiFunctionDevice() : Printer(), Scanner() {}
};Wenn mehrere Basisklassen Member mit demselben Namen haben, verwenden Sie den Bereichsauflösungs-Operator (scope resolution operator), um Mehrdeutigkeiten aufzulösen:
class A { public: void show() {} };
class B { public: void show() {} };
class C : public A, public B {};
C obj;
obj.A::show(); // Call A's version
obj.B::show(); // Call B's versionProbier 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 & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container