Frage Unterschied zwischen privater, öffentlicher und geschützter Vererbung


Was ist der Unterschied zwischen public, private, und protected Vererbung in C ++? Alle Fragen, die ich zu SO gestellt habe, befassen sich mit bestimmten Fällen.


813
2018-05-13 20:47


Ursprung


Antworten:


Um diese Frage zu beantworten, möchte ich die Accessoren des Mitglieds zuerst mit meinen eigenen Worten beschreiben. Wenn Sie das bereits wissen, fahren Sie mit der Überschrift "weiter:" fort.

Es gibt drei Accessoren, die mir bekannt sind: public, protected und private.

Lassen:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Alles, was bewusst ist Base ist mir auch bewusst, dass Base enthält publicMember.
  • Das wissen nur die Kinder (und ihre Kinder) Base enthält protectedMember.
  • Niemand außer Base ist sich bewusst privateMember.

Mit "ist bewusst" meine ich "erkenne die Existenz von und bin somit in der Lage, darauf zuzugreifen".

Nächster:

Gleiches gilt für die öffentliche, private und geschützte Erbschaft. Lassen Sie uns eine Klasse betrachten Base und eine Klasse Child das erbt von Base.

  • Wenn die Vererbung ist publicalles was bewusst ist Base und Child ist mir auch bewusst, dass Child erbt von Base.
  • Wenn die Vererbung ist protected, nur Childund seine Kinder wissen, dass sie von ihm erben Base.
  • Wenn die Vererbung ist private, niemand anders als Child ist sich der Vererbung bewusst.

902
2018-05-13 20:49



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 Zugriffs.

Über die Verwendung der geschützten und privaten Vererbung könnten Sie lesen Hier.


1221
2017-09-03 11:27



Wenn Sie die Sichtbarkeit der Vererbung einschränken, kann 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 bis zum abgeleiteten funktioniert 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.

Öffentlichkeit Erbe

  1. IS-Eine 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ützt Erbe

  1. Geschütztes implementiert in-terms-of. Selten nützlich. Benutzt in boost::compressed_pair aus leeren Klassen ableiten und Speicher mit der leeren Basisklassenoptimierung speichern (Beispiel unten verwendet keine Vorlage, um am Punkt 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!
      }
    };
    

Privatgelände Erbe

  1. Implementiert-in-Termen-von. Die Verwendung der Basisklasse dient nur zur Implementierung der abgeleiteten Klasse. Nützlich mit Traits und wenn es auf die Größe ankommt (leere Traits, die nur Funktionen enthalten, nutzen die leere Basisklassenoptimierung). Häufig Eindämmung ist jedoch die bessere Lösung. Die Größe für Strings ist kritisch, daher wird sie hier oft verwendet

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

Öffentlichkeit Mitglied

  1. Aggregat

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. Accessoren

    class window {
    public:
        int getWidth() const;
    };
    

geschützt Mitglied

  1. Bereitstellung eines erweiterten Zugriffs für abgeleitete Klassen

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

Privatgelände Mitglied

  1. Implementierungsdetails aufbewahren

    class window {
    private:
      int width;
    };
    

Beachten Sie, dass C-Style-Umwandlungen absichtlich eine definierte Klasse und eine sichere Klasse in eine geschützte oder private Basisklasse umwandeln und auch in die andere Richtung umwandeln können. Dies sollte um jeden Preis vermieden werden, da Code von Implementierungsdetails abhängig gemacht werden kann - aber Sie können diese Technik bei Bedarf auch anwenden.


98
2017-09-03 16:04



Es hat damit zu tun, wie die öffentlichen Mitglieder der Basisklasse von der abgeleiteten Klasse exponiert werden.

  • öffentlich -> öffentliche Mitglieder der Basisklasse sind öffentlich (normalerweise der Standard)    
  • protected -> Öffentliche Mitglieder der Basisklasse werden geschützt    
  • privat -> öffentliche Mitglieder der Basisklasse sind privat

Wie Litb zeigt, ist die öffentliche Vererbung eine traditionelle Vererbung, die Sie in den meisten Programmiersprachen sehen. Das heißt, es modelliert eine "IS-A" -Beziehung. Private Vererbung, etwas AFAIK, das C ++ eigen ist, ist eine "IMPLEMENTED IN Terms of" -Beziehung. Das willst du benutzen die öffentliche Schnittstelle in der abgeleiteten Klasse, möchte aber nicht, dass der Benutzer der abgeleiteten Klasse Zugriff auf diese Schnittstelle hat. Viele argumentieren, dass in diesem Fall sollten Sie die Basisklasse aggregieren, das heißt, anstatt die Basisklasse als private Basis zu haben, make in einem Member von abgeleitet, um die Funktionalität der Basisklasse wiederzuverwenden.


61
2018-05-13 20:49



Diese drei Schlüsselwörter werden auch in einem völlig anderen Kontext verwendet, um den Sichtbarkeitsvererbungsmodell.

Diese Tabelle sammelt alle möglichen Kombinationen der Komponentendeklaration und des Vererbungsmodells und stellt den resultierenden Zugriff auf die Komponenten dar, wenn die Unterklasse vollständig definiert ist.

enter image description here

Die obige Tabelle wird folgendermaßen interpretiert (werfen Sie einen Blick auf die erste Zeile):

wenn eine Komponente ist erklärt wie Öffentlichkeit und seine Klasse ist vererbt wie Öffentlichkeit das Ergebnis Zugriff ist Öffentlichkeit.

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 Variablen p, q, r im Unterricht Subsub ist keiner.

Ein anderes Beispiel:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

Der resultierende Zugriff für Variablen y, z im Unterricht Sub ist geschützt und für Variable x ist keiner.

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 können wir eine Unterklasse definieren:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

Die definierte Klasse namens Sub, die eine Unterklasse der benannten Klasse ist Super oder das Sub Klasse ist von der abgeleitet Super Klasse. Das Sub Die Klasse stellt weder neue Variablen noch neue Funktionen vor. Bedeutet es, dass irgendein Objekt der Sub Klasse erbt alle Merkmale nach dem Super Klasse ist in der Tat eine Kopie von a Super Klassenobjekte?

Nein. Es tut es nicht.

Wenn wir den folgenden Code kompilieren, erhalten wir nur Kompilierungsfehler, die das sagen put und get Methoden sind nicht zugänglich. Warum?

Wenn wir den Sichtbarkeitsspezifizierer weglassen, nimmt der Compiler an, dass wir das so genannte anwenden werden private Vererbung. Es bedeutet, dass alle Öffentlichkeit Superklassenkomponenten verwandeln sich in Privatgelände Zugriff, private Superclass-Komponenten sind überhaupt nicht zugänglich. Es bedeutet folglich, dass Sie das Letztere nicht innerhalb der Unterklasse verwenden dürfen.

Wir müssen den Compiler darüber informieren, dass die zuvor verwendete Zugriffsrichtlinie beibehalten werden soll.

class Sub : public Super { };

Lass dich nicht irreführen: Es bedeutet nicht, dass private Komponenten des Super   Die Klasse (wie die Speichervariable) wird in einer öffentlichen in eine öffentliche Klasse umgewandelt   etwas magische Art. Privatgelände Komponenten bleiben erhalten Privatgelände, Öffentlichkeitwird bleiben Öffentlichkeit.

Objekte des Sub Klasse kann "fast" die gleichen Dinge tun wie ihre älteren Geschwister aus der Super Klasse. "Fast" weil die Tatsache, eine Unterklasse zu sein, auch bedeutet, dass die Klasse hat den Zugriff auf die privaten Komponenten der Oberklasse verloren. Wir können keine Memberfunktion der schreiben Sub Klasse, die in der Lage wäre, die Speichervariable direkt zu manipulieren.

Dies ist eine sehr ernsthafte Einschränkung. Gibt es eine Problemumgehung?

Ja.

Die dritte Zugriffsebene wird aufgerufen geschützt. Das Schlüsselwort protected bedeutet, dass die Komponente damit markiert ist verhält sich wie ein öffentlicher, wenn er von einer der Unterklassen benutzt wird und für den Rest der Welt wie ein privater aussieht. - Dies gilt nur für die öffentlich geerbten 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 es tut eine wichtige Sache: Es greift auf die Speichervariable der Super-Klasse zu.

Es wäre nicht möglich, wenn die Variable als privat deklariert würde. Im Hauptfunktionsbereich bleibt die Variable trotzdem verborgen. Wenn Sie also etwas schreiben wie:

object.storage = 0;

Der Compiler wird Ihnen mitteilen, dass es ein error: 'int Super::storage' is protected.

Schließlich wird das letzte Programm die folgende Ausgabe erzeugen:

storage = 101

40
2018-06-07 16:56



Member in base class : Private   Protected   Public   

Vererbungstyp  :Objekt geerbt als:

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

34
2017-09-09 05:25



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 Klasse Abgeleitete öffentlich.

Daher können andere Klassen öffentliche Member 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. Öffentliche Mitglieder der Basisklasse werden ebenfalls geschützte Mitglieder der abgeleiteten Klasse.

Daher können andere Klassen keine öffentlichen Member der Basisklasse über das abgeleitete Klassenobjekt verwenden. aber sie sind für die Unterklasse von Derived verfügbar.

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 keine anderen Mitglieder der Basisklasse über abgeleitete Klassenobjekte auf andere Klassen zugreifen, da sie in der abgeleiteten Klasse privat sind. Also, sogar Unterklasse von Derived Klasse kann nicht auf sie zugreifen.


22
2018-05-26 04:42



Öffentliche Vererbung modelliert eine IS-A-Beziehung. Mit

class B {};
class D : public B {};

jeden D  ist ein  B.

Private Vererbung modelliert eine IS-IMPLEMENTED-USING-Beziehung (oder wie auch immer diese aufgerufen wird). Mit

class B {};
class D : private B {};

ein D ist nicht ein B, aber jeder D benutzt seine B in seiner Umsetzung. Private Vererbung kann immer durch die Verwendung von Containment entfernt werden:

class B {};
class D {
  private: 
    B b_;
};

Dies Dkann auch mit implementiert werden Bin diesem Fall unter Verwendung seiner b_. 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 praktisch wie die private Vererbung. Oft ist das eine lahme Entschuldigung dafür, faul zu sein.

Ich glaube nicht, dass irgendjemand was weiß protected Vererbungsmodelle. Zumindest habe ich noch keine überzeugende Erklärung gesehen.


19
2017-09-03 12:34



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 untergeordneten Klassen Sie polymorph verwenden.

Wenn Sie privat erben, können Sie nur übergeordnete Klassenmethoden ausführen.

Das symbolisiert im Grunde das Wissen, das der Rest der Klassen über Ihre Beziehung mit Ihrer Elternklasse hat


12
2017-09-03 11:27



Auf geschützte Datenelemente kann von allen Klassen zugegriffen werden, die von Ihrer Klasse erben. Private Datenmitglieder können dies jedoch nicht. Sagen wir, wir haben folgendes:

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

Von innerhalb Ihrer Erweiterung zu dieser Klasse, Referenzierung this.myPrivateMember wird nicht funktionieren. Jedoch, this.myProtectedMember werden. Der Wert ist noch gekapselt, also wenn wir eine Instanz dieser Klasse aufgerufen haben myObj, dann myObj.myProtectedMember wird nicht funktionieren, also ist es in der Funktion zu einem privaten Datenmitglied ähnlich.


9
2018-05-13 20:57