Was ist der Unterschied zwischen
public,privateundprotectedVererbung in C ++?
Alle Fragen, die ich zu SO gefunden habe, befassen sich mit bestimmten Fällen.
Was ist der Unterschied zwischen
public,privateundprotectedVererbung in C ++?
Alle Fragen, die ich zu SO gefunden habe, befassen sich mit bestimmten Fällen.
Antworten:
Um diese Frage zu beantworten, möchte ich die Accessoren der Mitglieder zuerst in meinen eigenen Worten beschreiben. Wenn Sie dies bereits wissen, fahren Sie mit der Überschrift "Weiter:" fort.
Es gibt drei Zugriffsmethoden, die ich kenne: public, protectedund private.
Lassen:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
Baseist , ist sich auch bewusst, dass es Baseenthält publicMember.Baseenthält protectedMember.Baseist sich dessen bewusst privateMember.Mit "ist sich bewusst" meine ich "die Existenz von anerkennen und somit darauf zugreifen können".
Gleiches gilt für die öffentliche, private und geschützte Vererbung. Betrachten wir eine Klasse Baseund eine Klasse Child, von der geerbt wird Base.
public, alles, was bekannt ist Baseund Childauch bekannt ist, von dem Childerbt Base.protected, nur Child, und ihre Kinder, sind sich bewusst , dass sie von erben Base.private, ist niemand anderem als Childder Vererbung bekannt.SomeBasewie eine fest codierte Methode ist, um ein anonymes Mitglied des Typs zu komponieren SomeBase. Dieses hat wie jedes andere Mitglied einen Zugriffsspezifizierer, der dieselbe Kontrolle auf den externen Zugriff ausübt.
class A
{
public:
int x;
protected:
int y;
private:
int z;
};
class B : public A
{
// x is public
// y is protected
// z is not accessible from B
};
class C : protected A
{
// x is protected
// y is protected
// z is not accessible from C
};
class D : private A // 'private' is default for classes
{
// x is private
// y is private
// z is not accessible from D
};
WICHTIGER HINWEIS: Die Klassen B, C und D enthalten alle die Variablen x, y und z. Es ist nur eine Frage des Zugangs.
Informationen zur Verwendung von geschützter und privater Vererbung finden Sie hier .
Wenn Sie die Sichtbarkeit der Vererbung einschränken, kann der Code nicht erkennen, dass eine Klasse eine andere Klasse erbt: Implizite Konvertierungen von der abgeleiteten zur Basis funktionieren nicht und static_castvon der Basis zur abgeleiteten auch nicht.
Nur Mitglieder / Freunde einer Klasse können die private Vererbung sehen, und nur Mitglieder / Freunde und abgeleitete Klassen können die geschützte Vererbung sehen.
öffentliches Erbe
IS-A-Vererbung. Eine Schaltfläche ist ein Fenster, und überall dort, wo ein Fenster benötigt wird, kann auch eine Schaltfläche übergeben werden.
class button : public window { };geschützte Vererbung
Geschützt implementiert in Bezug auf. Selten nützlich. Wird verwendet boost::compressed_pair, um aus leeren Klassen abzuleiten und Speicher mithilfe der Optimierung für leere Basisklassen zu sparen (Beispiel unten verwendet keine Vorlage, um auf dem neuesten Stand zu bleiben):
struct empty_pair_impl : protected empty_class_1
{ non_empty_class_2 second; };
struct pair : private empty_pair_impl {
non_empty_class_2 &second() {
return this->second;
}
empty_class_1 &first() {
return *this; // notice we return *this!
}
};private Vererbung
Implementiert in Bezug auf. Die Verwendung der Basisklasse dient nur zur Implementierung der abgeleiteten Klasse. Nützlich bei Merkmalen und wenn es auf die Größe ankommt (leere Merkmale, die nur Funktionen enthalten, verwenden die Optimierung der leeren Basisklasse). Oft ist die Eindämmung jedoch die bessere Lösung. Die Größe für Zeichenfolgen ist kritisch, daher wird sie hier häufig verwendet
template<typename StorageModel>
struct string : private StorageModel {
public:
void realloc() {
// uses inherited function
StorageModel::realloc();
}
};öffentliches Mitglied
Aggregat
class pair {
public:
First first;
Second second;
};Accessoren
class window {
public:
int getWidth() const;
};geschütztes Mitglied
Bereitstellung eines erweiterten Zugriffs für abgeleitete Klassen
class stack {
protected:
vector<element> c;
};
class window {
protected:
void registerClass(window_descriptor w);
};privates Mitglied
Behalten Sie die Implementierungsdetails bei
class window {
private:
int width;
};Beachten Sie, dass Casts im C-Stil absichtlich das Umwandeln einer abgeleiteten Klasse in eine geschützte oder private Basisklasse auf definierte und sichere Weise und das Umwandeln in die andere Richtung ermöglichen. Dies sollte unter allen Umständen vermieden werden, da dadurch Code von Implementierungsdetails abhängig gemacht werden kann. Bei Bedarf können Sie diese Technik jedoch verwenden.
Diese drei Schlüsselwörter werden auch in einem völlig anderen Kontext verwendet, um das Sichtbarkeitsvererbungsmodell anzugeben .
In dieser Tabelle werden alle möglichen Kombinationen der Komponentendeklaration und des Vererbungsmodells zusammengefasst, die den resultierenden Zugriff auf die Komponenten darstellen, wenn die Unterklasse vollständig definiert ist.

Die obige Tabelle wird folgendermaßen interpretiert (siehe erste Zeile):
wenn eine Komponente deklariert als öffentliches und seine Klasse geerbt als öffentlich der resultierende Zugang ist öffentlich .
Ein Beispiel:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
Die sich ergebende Zugang für Variablen p, q, rin der Klasse SubSub ist keine .
Ein anderes Beispiel:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
Die sich ergebende Zugang für Variablen y, zin der Klasse Sub ist geschützt und für Variable xist keine .
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;
}
Definieren wir nun 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 mit dem Namen Superoder dieser SubKlasse ist, wird von der SuperKlasse abgeleitet. Die SubKlasse führt weder neue Variablen noch neue Funktionen ein. Bedeutet dies, dass jedes Objekt der SubKlasse alle Merkmale nach dem erbt?Super Klasse tatsächlich eine Kopie der SuperObjekte einer Klasse ist?
Nein . Das tut es nicht.
Wenn wir den folgenden Code kompilieren, erhalten wir nur Kompilierungsfehler, die dies aussagen put und getMethoden nicht zugänglich sind. Warum?
Wenn wir den Sichtbarkeitsspezifizierer weglassen, geht der Compiler davon aus, dass wir die sogenannte private Vererbung anwenden werden . Dies bedeutet, dass alle öffentlichen Komponenten der Oberklasse zu werden privaten Zugriff umgewandelt werden und auf private Komponenten der Oberklasse überhaupt nicht zugegriffen werden kann. Dies bedeutet folglich, dass Sie letzteres nicht innerhalb der Unterklasse verwenden dürfen.
Wir müssen den Compiler darüber informieren, dass wir die zuvor verwendete Zugriffsrichtlinie beibehalten möchten.
class Sub : public Super { };
Lassen Sie sich nicht irreführen : Dies bedeutet nicht, dass private Komponenten der Super-Klasse (wie die Speichervariable) auf magische Weise in öffentliche Komponenten umgewandelt werden. Private Komponenten bleiben privat , öffentlich bleibt öffentlich .
Objekte der SubKlasse können "fast" die gleichen Dinge tun wie ihre älteren Geschwister, die aus der SuperKlasse 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 Mitgliedsfunktion der SubKlasse schreiben , die die Speichervariable direkt manipulieren könnte.
Dies ist eine sehr schwerwiegende Einschränkung. Gibt es eine Problemumgehung?
Ja .
Die dritte Zugriffsebene wird als geschützt bezeichnet . Das Schlüsselwort protected bedeutet, dass sich die damit gekennzeichnete Komponente wie eine öffentliche verhält, wenn sie von einer der Unterklassen verwendet wird, und für den Rest der Welt wie eine private Komponente aussieht . - Dies gilt nur für die öffentlich vererbten Klassen (wie die Super-Klasse 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, haben wir eine neue Funktionalität für die SubKlasse und sie macht eine wichtige Sache: Sie greift von der Super-Klasse auf die Speichervariable zu .
Es wäre nicht möglich, wenn die Variable als privat deklariert würde. Im Hauptfunktionsbereich bleibt die Variable ohnehin verborgen, wenn Sie also Folgendes schreiben:
object.storage = 0;
Der Compiler informiert Sie darüber, dass es sich um eine handelt error: 'int Super::storage' is protected.
Schließlich erzeugt das letzte Programm die folgende Ausgabe:
storage = 101
Dies hängt damit zusammen, wie die öffentlichen Mitglieder der Basisklasse aus der abgeleiteten Klasse verfügbar gemacht werden.
Wie litb hervorhebt, ist die öffentliche Vererbung eine traditionelle Vererbung, die Sie in den meisten Programmiersprachen sehen werden. Das heißt, es modelliert eine "IS-A" -Beziehung. Private Vererbung, etwas, das AFAIK in C ++ eigen ist, ist eine Beziehung, die in Bezug auf die Bedingungen implementiert ist. Das heißt , Sie wollen verwenden die öffentliche Schnittstelle in der abgeleiteten Klasse, aber nicht wollen , den Benutzer von der abgeleiteten Klasse den Zugriff auf diese Schnittstelle haben. Viele argumentieren, dass Sie in diesem Fall die Basisklasse aggregieren sollten, dh anstatt die Basisklasse als private Basis zu haben, in einem Mitglied von abgeleitet machen, um die Funktionalität der Basisklasse wiederzuverwenden.
Member in base class : Private Protected Public
Vererbungstyp : Objekt geerbt als :
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
1) Öffentliche Vererbung :
ein. Auf private Mitglieder der Basisklasse kann in der abgeleiteten Klasse nicht zugegriffen werden.
b. Geschützte Mitglieder der Basisklasse bleiben in der abgeleiteten Klasse geschützt.
c. Öffentliche Mitglieder der Basisklasse bleiben in der abgeleiteten Klasse öffentlich.
Andere Klassen können also öffentliche Mitglieder der Basisklasse über das abgeleitete Klassenobjekt verwenden.
2) Geschützte Vererbung :
ein. Auf private Mitglieder der Basisklasse kann in der abgeleiteten Klasse nicht zugegriffen werden.
b. Geschützte Mitglieder der Basisklasse bleiben in der abgeleiteten Klasse geschützt.
c. Auch öffentliche Mitglieder der Basisklasse werden geschützte Mitglieder der abgeleiteten Klasse.
Daher können andere Klassen keine öffentlichen Mitglieder der Basisklasse über das abgeleitete Klassenobjekt verwenden. Sie stehen jedoch der Unterklasse Abgeleitet zur Verfügung.
3) Private Vererbung :
ein. Auf private Mitglieder der Basisklasse kann in der abgeleiteten Klasse nicht zugegriffen werden.
b. Geschützte und öffentliche Mitglieder der Basisklasse werden private Mitglieder der abgeleiteten Klasse.
Daher können andere Klassen über das Derived-Klassenobjekt nicht auf Mitglieder der Base-Klasse zugreifen, da sie in der Derived-Klasse privat sind. Daher kann auch die Unterklasse der abgeleiteten Klasse nicht auf sie zugreifen.
Öffentliche Vererbung modelliert eine IS-A-Beziehung. Mit
class B {};
class D : public B {};
jeder D ist ein B .
Private Vererbung modelliert eine IS-IMPLEMENTED-USING-Beziehung (oder wie auch immer das heißt). Mit
class B {};
class D : private B {};
a Dist nicht a B, aber jeder Dverwendet es Bin seiner Implementierung. Private Vererbung kann immer durch Verwendung von Containment beseitigt werden:
class B {};
class D {
private:
B b_;
};
Auch dies Dkann mit B, in diesem Fall mit seiner implementiert werdenb_ . Containment ist eine weniger enge Kopplung zwischen Typen als Vererbung, daher sollte es im Allgemeinen bevorzugt werden. Manchmal ist die Verwendung von Containment anstelle von privater Vererbung nicht so bequem wie die private Vererbung. Oft ist das eine lahme Entschuldigung dafür, faul zu sein.
Ich glaube nicht, dass jemand weiß, welche protectedVererbungsmodelle. Zumindest habe ich noch keine überzeugende Erklärung gesehen.
Dprivat abgeleitet D, kann es virtuelle Funktionen von überschreiben B. (Wenn es sich beispielsweise Bum eine Beobachterschnittstelle handelt, Dkann diese implementiert und thisan Funktionen übergeben werden, für die auch eine Schnittstelle erforderlich ist, ohne dass jeder sie Dals Beobachter verwenden kann.) Außerdem können DMitglieder von selektiv Bin ihrer Schnittstelle verfügbar gemacht werden using B::member. Beides ist syntaktisch unpraktisch zu implementieren, wenn Bes sich um ein Mitglied handelt.
protectedVererbung Ich fand nützlich mit einer virtualBasisklasse und protectedctor:struct CommonStuff { CommonStuff(Stuff*) {/* assert !=0 */ } }; struct HandlerMixin1 : protected virtual CommonStuff { protected: HandlerMixin1() : CommonStuff(nullptr) {} /*...*/ }; struct Handler : HandlerMixin1, ... { Handler(Stuff& stuff) : CommonStuff(&stuff) {} };
Wenn Sie öffentlich von einer anderen Klasse erben, weiß jeder, dass Sie erben, und Sie können von jedem über einen Basisklassenzeiger polymorph verwendet werden.
Wenn Sie geschützt erben, können nur Ihre Kinderklassen Sie polymorph verwenden.
Wenn Sie privat erben, können nur Sie selbst übergeordnete Klassenmethoden ausführen.
Dies symbolisiert im Wesentlichen das Wissen, das die übrigen Klassen über Ihre Beziehung zu Ihrer Elternklasse haben
Auf geschützte Datenelemente können alle Klassen zugreifen, die von Ihrer Klasse erben. Private Datenmitglieder können dies jedoch nicht. Nehmen wir an, wir haben Folgendes:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
Innerhalb Ihrer Erweiterung zu dieser Klasse this.myPrivateMemberfunktioniert die Referenzierung nicht. Allerdings this.myProtectedMemberwird. Der Wert wird noch gekapselt, so dass , wenn wir eine Instanziierung dieser Klasse haben genannt myObj, dann myObj.myProtectedMemberwird nicht funktionieren, so dass er in der Funktion zu einem privaten Datenelement ähnlich ist.
Accessors | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public | y | y | y
—————————————+————————————+———————————————+———————
protected | y | y | n
—————————————+————————————+———————————————+———————
private | | |
or | y | n | n
no accessor | | |
y: accessible
n: not accessible
Basierend auf diesem Beispiel für Java ... Ich denke, eine kleine Tabelle sagt mehr als tausend Worte :)
Zusammenfassung:
Beim Erben können Sie (in einigen Sprachen) den Schutztyp eines Datenelements in eine bestimmte Richtung ändern, z. B. von geschützt in öffentlich.
Auf die privaten Mitglieder einer Basisklasse können nur Mitglieder dieser Basisklasse zugreifen.
Auf die öffentlichen Mitglieder einer Basisklasse können Mitglieder dieser Basisklasse, Mitglieder ihrer abgeleiteten Klasse sowie Mitglieder außerhalb der Basisklasse und der abgeleiteten Klasse zugreifen.
Auf die geschützten Mitglieder einer Basisklasse können sowohl Mitglieder der Basisklasse als auch Mitglieder ihrer abgeleiteten Klasse zugreifen.
privat : Basis
geschützt : Basis + abgeleitet
public : base + abgeleitet + jedes andere Mitglied
Ich fand eine einfache Antwort und dachte deshalb daran, sie auch für meine zukünftige Referenz zu veröffentlichen.
Es ist von den Links http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/
class Base
{
public:
int m_nPublic; // can be accessed by anybody
private:
int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
int m_nProtected; // can be accessed by Base member functions, or derived classes.
};
class Derived: public Base
{
public:
Derived()
{
// Derived's access to Base members is not influenced by the type of inheritance used,
// so the following is always true:
m_nPublic = 1; // allowed: can access public base members from derived class
m_nPrivate = 2; // not allowed: can not access private base members from derived class
m_nProtected = 3; // allowed: can access protected base members from derived class
}
};
int main()
{
Base cBase;
cBase.m_nPublic = 1; // allowed: can access public members from outside class
cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}
Es ist im Wesentlichen der Zugriffsschutz der Öffentlichkeit und der geschützten Mitglieder der Basisklasse in der abgeleiteten Klasse. Bei der öffentlichen Vererbung kann die abgeleitete Klasse öffentliche und geschützte Mitglieder der Basis sehen. Mit privater Vererbung kann es nicht. Mit protected können die abgeleitete Klasse und alle daraus abgeleiteten Klassen sie sehen.