Zugriffsstufen bei Vererbung
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 49 von 104.
Die von Ihnen gewählte Vererbungsart beeinflusst, wie auf Member der Basisklasse in der abgeleiteten Klasse zugegriffen wird. C++ bietet drei Optionen: public, protected und private Vererbung.
Hier erfahren Sie, wie jeder Typ den Zugriff auf Member transformiert:
| Basis-Member | public-Vererbung | protected-Vererbung | private-Vererbung |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | nicht zugreifbar | nicht zugreifbar | nicht zugreifbar |
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class PublicDerived : public Base {
// pub ist public, prot ist protected, priv ist nicht zugänglich
};
class ProtectedDerived : protected Base {
// pub ist protected, prot ist protected, priv ist nicht zugänglich
};
class PrivateDerived : private Base {
// pub ist private, prot ist private, priv ist nicht zugänglich
};Öffentliche Vererbung modelliert „is-a“-Beziehungen und ist bei weitem die häufigste. Ein Dog ist ein Animal, sodass externer Code es als solches behandeln kann.
Geschützte und private Vererbung modellieren „implementiert-mittels“-Beziehungen (implemented-in-terms-of). 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 Basiselemente.
Aufgabe
EinfachLassen Sie uns untersuchen, wie sich verschiedene Vererbungstypen auf die Zugänglichkeit von Mitgliedern auswirken, indem wir eine einfache Gerätehierarchie aufbauen. Sie werden eine Basisklasse Device und drei abgeleitete Klassen erstellen, die jeweils einen anderen Vererbungstyp verwenden, um aus erster Hand zu sehen, wie öffentliche (public), geschützte (protected) und private Vererbung den Zugriff auf Mitglieder transformieren.
Sie werden Ihren Code in zwei Dateien organisieren:
Device.h: Definieren Sie eine BasisklasseDevicemit drei Mitgliedern auf verschiedenen Zugriffsebenen:- Ein öffentliches
std::string model - Ein geschütztes
int serialNumber - Ein privates
int internalCode(standardmäßig auf 999 gesetzt) - Eine öffentliche Methode
showModel(), die Folgendes ausgibt:Model: <model>
Erstellen Sie dann drei abgeleitete Klassen, die jeweils mit unterschiedlichen Vererbungstypen von
Deviceerben:PublicDeviceunter Verwendung von öffentlicher Vererbung (public inheritance) — fügen Sie eine MethodedisplaySerial()hinzu, die Folgendes ausgibt:Serial: <serialNumber>ProtectedDeviceunter Verwendung von geschützter Vererbung (protected inheritance) — fügen Sie eine MethodedisplaySerial()hinzu, die Folgendes ausgibt:Serial: <serialNumber>PrivateDeviceunter Verwendung von privater Vererbung (private inheritance) — fügen Sie eine MethodedisplaySerial()hinzu, die Folgendes ausgibt:Serial: <serialNumber>
Jede abgeleitete Klasse sollte einen Konstruktor haben, der einen Modellnamen und eine Seriennummer entgegennimmt, das Modell an die Basisklasse übergibt und die Seriennummer setzt.
- Ein öffentliches
main.cpp: Lesen Sie zwei Eingaben ein (jede in einer separaten Zeile):- Modellname (String)
- Seriennummer (Integer)
Erstellen Sie ein Objekt von jedem abgeleiteten Typ mit denselben Eingabewerten. Demonstrieren Sie dann die Zugriffsunterschiede:
Für
PublicDevice:- Rufen Sie
showModel()direkt am Objekt auf (funktioniert, da die öffentliche Vererbung es öffentlich hält) - Greifen Sie direkt auf
modelzu und geben Sie Folgendes aus:Direct model access: <model> - Rufen Sie
displaySerial()auf
Für
ProtectedDeviceundPrivateDevice:- Rufen Sie 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: 12345Beachten Sie, dass nur PublicDevice den externen Zugriff auf die geerbten öffentlichen Mitglieder erlaubt. Die anderen Vererbungstypen verbergen die Schnittstelle der Basisklasse vor externem Code, aber die abgeleiteten Klassen können intern über ihre eigenen Methoden weiterhin auf geschützte Mitglieder zugreifen.
Spickzettel
C++ bietet drei Vererbungsarten an, die steuern, wie auf Member der Basisklasse in abgeleiteten Klassen zugegriffen wird:
| Basis-Member | public-Vererbung | protected-Vererbung | private-Vererbung |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | nicht zugreifbar | nicht zugreifbar | nicht zugreifbar |
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class PublicDerived : public Base {
// pub ist public, prot ist protected, priv ist nicht zugreifbar
};
class ProtectedDerived : protected Base {
// pub ist protected, prot ist protected, priv ist nicht zugreifbar
};
class PrivateDerived : private Base {
// pub ist private, prot ist private, priv ist nicht zugreifbar
};Public-Vererbung bildet „is-a“-Beziehungen (ist-ein) ab und ist am gebräuchlichsten. Externer Code kann über die abgeleitete Klasse auf öffentliche Member der Basisklasse zugreifen.
Protected- und Private-Vererbung bilden „implemented-in-terms-of“-Beziehungen (implementiert-mithilfe-von) ab. Sie verbergen die Schnittstelle der Basisklasse vor externem Code. Bei der Private-Vererbung verlieren sogar weiter abgeleitete Klassen den Zugriff auf die ursprünglichen Basis-Member.
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: Objekte jedes abgeleiteten Typs mit den Eingabewerten erstellen
// PublicDevice pubDev(modelName, serialNum);
// ProtectedDevice protDev(modelName, serialNum);
// PrivateDevice privDev(modelName, serialNum);
// TODO: Zugriff auf PublicDevice demonstrieren
cout << "--- PublicDevice ---" << endl;
// - showModel() direkt am Objekt aufrufen
// - Direkt auf model zugreifen und ausgeben: Direct model access: <model>
// - displaySerial() aufrufen
// TODO: Zugriff auf ProtectedDevice demonstrieren
cout << "--- ProtectedDevice ---" << endl;
// - Nur displaySerial() aufrufen (showModel und model sind nicht öffentlich zugänglich)
// TODO: Zugriff auf PrivateDevice demonstrieren
cout << "--- PrivateDevice ---" << endl;
// - Nur displaySerial() aufrufen (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