Was ist der Unterschied zwischen
public
,private
undprotected
Vererbung in C ++?
Alle Fragen, die ich zu SO gefunden habe, befassen sich mit bestimmten Fällen.
Was ist der Unterschied zwischen
public
,private
undprotected
Vererbung 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
, protected
und private
.
Lassen:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
Base
ist , ist sich auch bewusst, dass es Base
enthält publicMember
.Base
enthält protectedMember
.Base
ist 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 Base
und eine Klasse Child
, von der geerbt wird Base
.
public
, alles, was bekannt ist Base
und Child
auch bekannt ist, von dem Child
erbt Base
.protected
, nur Child
, und ihre Kinder, sind sich bewusst , dass sie von erben Base
.private
, ist niemand anderem als Child
der Vererbung bekannt.SomeBase
wie 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_cast
von 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
, r
in 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
, z
in der Klasse Sub ist geschützt und für Variable x
ist 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 Super
oder dieser Sub
Klasse ist, wird von der Super
Klasse abgeleitet. Die Sub
Klasse führt weder neue Variablen noch neue Funktionen ein. Bedeutet dies, dass jedes Objekt der Sub
Klasse alle Merkmale nach dem erbt?Super
Klasse tatsächlich eine Kopie der Super
Objekte einer Klasse ist?
Nein . Das tut es nicht.
Wenn wir den folgenden Code kompilieren, erhalten wir nur Kompilierungsfehler, die dies aussagen put
und get
Methoden 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 Sub
Klasse können "fast" die gleichen Dinge tun wie ihre älteren Geschwister, die aus der Super
Klasse 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 Sub
Klasse 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 Sub
Klasse 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 D
ist nicht a B
, aber jeder D
verwendet es B
in seiner Implementierung. Private Vererbung kann immer durch Verwendung von Containment beseitigt werden:
class B {};
class D {
private:
B b_;
};
Auch dies D
kann 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 protected
Vererbungsmodelle. Zumindest habe ich noch keine überzeugende Erklärung gesehen.
D
privat abgeleitet D
, kann es virtuelle Funktionen von überschreiben B
. (Wenn es sich beispielsweise B
um eine Beobachterschnittstelle handelt, D
kann diese implementiert und this
an Funktionen übergeben werden, für die auch eine Schnittstelle erforderlich ist, ohne dass jeder sie D
als Beobachter verwenden kann.) Außerdem können D
Mitglieder von selektiv B
in ihrer Schnittstelle verfügbar gemacht werden using B::member
. Beides ist syntaktisch unpraktisch zu implementieren, wenn B
es sich um ein Mitglied handelt.
protected
Vererbung Ich fand nützlich mit einer virtual
Basisklasse und protected
ctor: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.myPrivateMember
funktioniert die Referenzierung nicht. Allerdings this.myProtectedMember
wird. Der Wert wird noch gekapselt, so dass , wenn wir eine Instanziierung dieser Klasse haben genannt myObj
, dann myObj.myProtectedMember
wird 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.