Was ist der Unterschied zwischen public
, private
und protected
Vererbung in C ++?
Was Anzurio geschrieben hat, wurde nur in Verbindung mit Ihrer Antwort sofort darunter angeklickt.
Was ist der Unterschied zwischen public
, private
und protected
Vererbung in C ++?
class A
{
public:
int x;
protected:
int y;
private:
int z;
};
class B : public A
{
// x ist öffentlich
// y ist geschützt
// z ist von B aus nicht zugänglich
};
class C : protected A
{
// x ist geschützt
// y ist geschützt
// z ist von C aus nicht zugänglich
};
class D : private A // 'private' ist Standard für Klassen
{
// x ist privat
// y ist privat
// z ist von D aus nicht zugänglich
};
WICHTIGER HINWEIS: Die Klassen B, C und D enthalten alle die Variablen x, y und z. Es geht nur um den Zugriff.
Zum Thema Verwendung von geschützter und privater Vererbung können Sie hier nachlesen.
Was Anzurio geschrieben hat, wurde nur in Verbindung mit Ihrer Antwort sofort darunter angeklickt.
Mein Verständnis davon, wie das funktioniert hat, war SO WEIT FALSCH! Vielen Dank für die Klarstellung.
Um diese Frage zu beantworten, möchte ich erst einmal die Accessoren des Mitglieds in meinen eigenen Worten beschreiben. Wenn Sie dies bereits wissen, springen Sie zum Abschnitt "weiter:".
Es gibt drei mir bekannte Accessoren: public
, protected
und private
.
Lassen Sie uns:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
Base
Bescheid weiß, weiß auch, dass Base
publicMember
enthält.Base
protectedMember
enthält.Base
weiß von privateMember
.Mit "Bescheid wissen", meine ich "das Vorhandensein anerkennen und somit darauf zugreifen können".
Dasselbe passiert bei der öffentlichen, privaten und geschützten Vererbung. Betrachten wir eine Klasse Base
und eine Klasse Child
, die von Base
erbt.
Base
und Child
Bescheid weiß, dass Child
von Base
erbt.Child
und seine Kinder, dass sie von Base
erben.Child
von der Vererbung.
Ich würde gerne ein paar Worte hinzufügen, dass die Sichtbarkeit in C++ basierend auf Klassen statt auf Objekten ist, was bedeutet, dass Objekte derselben Klasse uneingeschränkt auf private Felder anderer Objekte zugreifen können.
Wenn Sie Schwierigkeiten haben, dies zu verstehen, lesen Sie die Antwort von Kirill V. Lyadvinsky, kehren Sie dann zurück und lesen Sie dies.
Dies ist nur ein weiterer Fall, der zeigt, wie, größtenteils, das Erben von SomeBase
nur eine harte Art ist, ein anonymes Element vom Typ SomeBase
zusammenzusetzen. Dies hat, wie jedes andere Element, einen Zugriffsspezifizierer, der dieselbe Kontrolle über den externen Zugriff ausübt.
Diese drei Schlüsselwörter werden auch in einem völlig anderen Kontext verwendet, um das Sichtbarkeitsvererbungsmodell festzulegen.
In dieser Tabelle werden alle möglichen Kombinationen der Komponentendeklaration und des Vererbungsmodells zusammengefasst und der resultierende Zugriff auf die Komponenten präsentiert, wenn die Unterklasse vollständig definiert ist.
Die obige Tabelle wird folgendermaßen interpretiert (schauen Sie sich die erste Zeile an):
wenn eine Komponente als public deklariert ist und ihre Klasse als public geerbt wird, ist der resultierende Zugriff public.
Ein Beispiel:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
Der resultierende Zugriff für die Variablen p
, q
, r
in der Klasse Subsub ist none.
Ein weiteres Beispiel:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
Der resultierende Zugriff für die Variablen y
, z
in der Klasse Sub ist protected und für die Variable x
ist none.
Ein detaillierteres Beispiel:
class Super {
private:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
int main(void) {
Super object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
Jetzt definieren wir eine Unterklasse:
class Sub : Super { };
int main(void) {
Sub object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
Die definierte Klasse mit dem Namen Sub, die eine Unterklasse der Klasse Super
ist oder dass die Klasse Sub
von der Klasse Super
abgeleitet ist. Die Klasse Sub
führt weder neue Variablen noch neue Funktionen ein. Bedeutet das, dass jedes Objekt der Klasse Sub
alle Merkmale nach der Klasse Super
erbt und tatsächlich eine Kopie der Objekte einer Klasse Super
ist?
Nein. Das tut es nicht.
Wenn wir den folgenden Code kompilieren, erhalten wir nichts als Kompilierungsfehler, die besagen, dass die Methoden put
und get
nicht zugänglich sind. Warum?
Wenn wir den Sichtbarkeitsspezifizierer auslassen, nimmt der Compiler an, dass wir die sogenannte private Vererbung anwenden wollen. Das bedeutet, dass alle öffentlichen Oberklassenkomponenten in einen privaten Zugriff umgewandelt werden, private Oberklassenkomponenten überhaupt nicht zugänglich sein werden. Das bedeutet folglich, dass Sie Letztere nicht innerhalb der Unterklasse verwenden dürfen.
Wir müssen dem Compiler mitteilen, dass wir die zuvor verwendete Zugriffspolitik beibehalten möchten.
class Sub : public Super { };
Lassen Sie sich nicht täuschen: Das bedeutet nicht, dass private Komponenten der Super Klasse (wie die Speichervariable) sich auf magische Weise in öffentliche verwandeln. Private Komponenten bleiben private, public bleiben public.
Objekte der Klasse Sub
können "fast" die gleichen Dinge tun wie ihre älteren Geschwister, die aus der Klasse Super
erstellt wurden. "Fast" weil die Tatsache, eine Unterklasse zu sein, auch bedeutet, dass die Klasse den Zugriff auf die privaten Komponenten der Oberklasse verloren hat. Wir können keine Memberfunktion der Klasse Sub
schreiben, die die Speichervariable direkt manipulieren könnte.
Dies ist eine sehr ernste Einschränkung. Gibt es einen Workaround?
Ja.
Die dritte Zugriffsebene wird protected genannt. Das Schlüsselwort protected bedeutet, dass die damit markierte Komponente sich wie eine öffentliche verhält, wenn sie von einer der Unterklasse verwendet wird, und für den Rest der Welt wie eine private erscheint. -- Dies gilt nur für öffentlich vererbte Klassen (wie die Superklasse in unserem Beispiel) --
class Super {
protected:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
class Sub : public Super {
public:
void print(void) {cout << "storage = " << storage;}
};
int main(void) {
Sub object;
object.put(100);
object.put(object.get() + 1);
object.print();
return 0;
}
Wie Sie im Beispielcode sehen, fügen wir der Klasse Sub
eine neue Funktionalität hinzu, die eine wichtige Sache tut: sie greift auf die Speichervariable der Superklasse zu.
Es wäre nicht möglich, wenn die Variable als privat deklariert wäre. Im Bereich der Hauptfunktion bleibt die Variable sowieso verborgen, also wenn Sie etwas wie folgt schreiben:
object.storage = 0;
Der Compiler informiert Sie, dass es ein Fehler: "int Super::storage" ist geschützt
ist.
Schließlich wird das letzte Programm folgende Ausgabe erzeugen:
storage = 101
Der erste, der das Fehlen eines Modifizierers erwähnt (wie in Klasse: Superklasse), erhält Privat. Dies ist ein wichtiger Punkt, den die anderen übersehen, zusammen mit gründlichen Erklärungen. +1
Ein geschütztes Element bei öffentlicher Vererbung wird in der abgeleiteten Klasse privat, stimmt das? Die Tabelle sagt, es wird geschützt?
Es hat damit zu tun, wie die öffentlichen Elemente der Basisklasse von der abgeleiteten Klasse aus zugänglich sind.
Wie litb feststellt, ist die öffentliche Vererbung die traditionelle Vererbung, die man in den meisten Programmiersprachen findet. Sie modelliert eine "IST-EIN" Beziehung. Private Vererbung, etwas AFAIK Eigenartiges von C++, ist eine "IMPLEMENTIERT IN BEZUG AUF" Beziehung. Das bedeutet, dass Sie die öffentliche Schnittstelle in der abgeleiteten Klasse verwenden möchten, aber den Benutzer der abgeleiteten Klasse keinen Zugriff auf diese Schnittstelle haben möchten. Viele argumentieren, dass Sie in diesem Fall die Basisklasse aggregieren sollten, das heißt anstatt die Basisklasse als eine private Basis zu haben, machen Sie sie zu einem Element der abgeleiteten Klasse, um die Funktionalität der Basisklasse wiederzuverwenden.
Besser sagen Sie "public: das Erbe wird von allen gesehen werden". geschützt: das Erbe wird nur von abgeleiteten Klassen und Freunden gesehen werden", "privat: das Erbe wird nur von der Klasse selbst und Freunden gesehen werden". Dies unterscheidet sich von Ihrer Formulierung, da nicht nur die Mitglieder unsichtbar sein können, sondern auch die IST-EIN-Beziehung unsichtbar sein kann.
Die einzige Zeit, dass ich private Vererbung verwendet habe, war genau das, was Doug T beschreibt, d.h. "Sie möchten die öffentliche Schnittstelle in der abgeleiteten Klasse verwenden, aber möchten nicht, dass der Benutzer der abgeleiteten Klasse Zugriff auf diese Schnittstelle hat". Ich habe es im Grunde verwendet, um die alte Schnittstelle abzudichten und eine andere durch die abgeleitete Klasse freizulegen.
Dies ist irreführend. Private Member einer Basisklasse verhalten sich ganz anders als gewöhnliche private Klassenmember - sie sind für die abgeleitete Klasse überhaupt nicht zugänglich. Ich glaube, Ihre Spalte mit drei "Private" sollte eine Spalte mit "Nicht zugreifbar" sein. Siehe die Antwort von Kirill V. Lyadvinsky zu dieser Frage.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.