Zugriffsstufen bei Vererbung
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 49 von 104.
Die Vererbungungsart, die Sie wählen, beeinflusst, wie auf Basisklassenmitglieder in der abgeleiteten Klasse zugegriffen wird. C++ bietet drei Optionen: public-, protected- und private-Vererbung.
Hier ist, wie jeder Typ den Elementzugriff verändert:
| Base Member | public inheritance | protected inheritance | private inheritance |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | inaccessible | inaccessible | inaccessible |
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class PublicDerived : public Base {
// pub ist public, prot ist protected, priv ist unzugänglich
};
class ProtectedDerived : protected Base {
// pub ist protected, prot ist protected, priv ist unzugänglich
};
class PrivateDerived : private Base {
// pub ist private, prot ist private, priv ist unzugänglich
};Öffentliche Vererbung modelliert „ist-ein“-Beziehungen und ist bei weitem am gebräuchlichsten. Ein Dog ist ein Animal, daher kann externer Code ihn als solchen behandeln.
Protected and private inheritance modellieren „implemented-in-terms-of“-Beziehungen. Sie verbergen die Schnittstelle der Basisklasse vor externem Code, was nützlich ist, wenn Sie die Implementierung wiederverwenden möchten, ohne die Vererbungsbeziehung offenzulegen. Bei privater Vererbung verlieren selbst weiter abgeleitete Klassen den Zugriff auf die ursprünglichen Basis-Member.
Aufgabe
EinfachLass uns untersuchen, wie verschiedene Arten der Vererbung (inheritance) die Zugänglichkeit (access) von Membern beeinflussen, indem wir eine einfache Gerätehierarchie aufbauen. Du wirst eine Base-Klasse Device und drei abgeleitete Klassen (derived) erstellen, die jeweils einen anderen Vererbungstyp verwenden, um hautnah zu erleben, wie public, protected und private Vererbung den Member-Zugriff verändern.
Du wirst deinen Code auf zwei Dateien aufteilen:
Device.h: Definiere eineBase-KlasseDevicemit drei Membern auf verschiedenen Zugriffsebenen:- Ein
publicstd::string model - Ein
protectedint serialNumber - Ein
privateint internalCode(standardmäßig auf 999 gesetzt) - Eine
publicmethodshowModel(), die folgendes ausgibt:Model: <model>
Erstelle dann drei
derivedKlassen, die jeweils mit verschiedenen Vererbungstypen vonDeviceerben:PublicDevicemittels publicinheritance— füge einemethoddisplaySerial()hinzu, die folgendes ausgibt:Serial: <serialNumber>ProtectedDevicemittels protectedinheritance— füge einemethoddisplaySerial()hinzu, die folgendes ausgibt:Serial: <serialNumber>PrivateDevicemittels privateinheritance— füge einemethoddisplaySerial()hinzu, die folgendes ausgibt:Serial: <serialNumber>
Jede abgeleitete
classsollte einenConstructorhaben, der einen Modellnamen und eine Seriennummer entgegennimmt, den Modellnamen an dieBase-Klasse übermittelt und die Seriennummer setzt.- Ein
main.cpp: Lies zwei Eingaben (input) ein (jeweils in einer eigenen Zeile):- Modellname (String)
- Seriennummer (
int)
Erstelle ein
objectjedes abgeleiteten Typs mit denselben Eingabewerten. Demonstriere dann die Zugriffsunterschiede:Für
PublicDevice:- Rufe
showModel()direkt amobjectauf (funktioniert, weilpublicinheritancees öffentlich belässt) - Greife direkt auf
modelzu und gib aus:Direct model access: <model> - Rufe
displaySerial()auf
Für
ProtectedDeviceundPrivateDevice:- Rufe nur
displaySerial()auf (die geerbtenshowModel()undmodelsind von außen nicht mehr öffentlich zugänglich)
Ausgabeformat:
--- PublicDevice --- Model: <model> Direct model access: <model> Serial: <serial> --- ProtectedDevice --- Serial: <serial> --- PrivateDevice --- Serial: <serial>
Zum Beispiel mit den Eingaben Laptop und 12345:
--- PublicDevice ---
Model: Laptop
Direct model access: Laptop
Serial: 12345
--- ProtectedDevice ---
Serial: 12345
--- PrivateDevice ---
Serial: 12345Beachte, wie nur PublicDevice externen Zugriff (external access) auf die geerbten public Member erlaubt. Die anderen Vererbungstypen verbergen die Schnittstelle der Base-Klasse vor externem Code, aber die abgeleiteten Klassen können intern über ihre eigenen Methoden weiterhin auf protected Member zugreifen.
Probier es selbst
#include <iostream>
#include <string>
#include "Device.h"
using namespace std;
int main() {
// Eingabe lesen
string modelName;
int serialNum;
getline(cin, modelName);
cin >> serialNum;
// TODO: Erstelle Objekte jedes abgeleiteten Typs mit den Eingabewerten
// PublicDevice pubDev(modelName, serialNum);
// ProtectedDevice protDev(modelName, serialNum);
// PrivateDevice privDev(modelName, serialNum);
// TODO: Demonstrate PublicDevice access
cout << "--- PublicDevice ---" << endl;
// - Rufe showModel() direkt auf dem Objekt auf
// - Access model directly and print: Direct model access: <model>
// - Rufe displaySerial() auf
// TODO: Demonstrate ProtectedDevice access
cout << "--- ProtectedDevice ---" << endl;
// - Rufe nur displaySerial() auf (showModel und model sind nicht öffentlich zugänglich)
// TODO: Demonstrate PrivateDevice access
cout << "--- PrivateDevice ---" << endl;
// - Rufe nur displaySerial() auf (showModel und model sind nicht öffentlich zugänglich)
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