Was ist der Unterschied zwischen öffentlicher, privater und geschützter Vererbung in C++?

Lesezeit: 12 Minuten

Was ist der Unterschied zwischen public, privateund protected Vererbung in C++?

Alle Fragen, die ich auf SO gefunden habe, beziehen sich auf bestimmte Fälle.

Benutzer-Avatar
Kirill V. Ljadwinski

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.

Über die Verwendung von geschützter und privater Vererbung können Sie hier lesen.

  • Was Anzurio geschrieben hat, wurde nur in Verbindung mit Ihrer Antwort direkt unten angeklickt. Плус 1.

    – Ich werde nicht existieren Ich werde nicht existieren

    4. März 2015 um 4:45 Uhr


  • Mein Verständnis davon, wie dies funktionierte, war SO WEIT AB! Vielen Dank für die Klarstellung.

    – tjwrona1992

    3. August 2017 um 12:43 Uhr

  • Ich habe einige Zeit gebraucht, um das zu verstehen. Aber jetzt ist es klar. Vielen Dank!

    – Chan-Kim

    26. April 2019 um 7:50 Uhr


  • Guter Hinweis, dass „privat“ die Standardeinstellung für Klassen ist.

    – Johann Leuenhagen

    6. Juli 2020 um 3:57 Uhr

  • Wunderbare Erklärung. Soweit ist hier alles klar.

    – Badhan Sen

    16. Juni 2021 um 17:45 Uhr

Benutzer-Avatar
Anzurio

Um diese Frage zu beantworten, möchte ich zunächst die Accessoren der Mitglieder in meinen eigenen Worten beschreiben. Wenn Sie dies bereits wissen, springen Sie zur Überschrift “weiter:”.

Mir sind drei Accessoren bekannt: public, protected und private.

Lassen:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Alles, was bewusst ist Base ist sich dessen auch bewusst Base enthält publicMember.
  • Das wissen nur die Kinder (und deren Kinder). Base enthält protectedMember.
  • Niemand aber Base ist sich bewusst privateMember.

Mit „ist sich dessen bewusst“ meine ich „die Existenz anerkennen und somit darauf zugreifen können“.

nächste:

Das Gleiche gilt für öffentliche, private und geschützte Erbschaften. Betrachten wir eine Klasse Base und eine Klasse Child das erbt von Base.

  • Wenn das Erbe ist publicalles, was bewusst ist Base und Child ist sich dessen auch bewusst Child erbt von Base.
  • Wenn das Erbe ist protectednur Childund seine untergeordneten Elemente, sind sich dessen bewusst, dass sie von erben Base.
  • Wenn das Erbe ist privateniemand anderes als Child ist sich der Erbschaft bewusst.

  • Ich möchte noch ein paar Worte hinzufügen, dass die Sichtbarkeit in C++ auf der Klasse statt auf dem Objekt basiert, was bedeutet, dass Objekte derselben Klasse uneingeschränkt auf die privaten Felder der anderen zugreifen können.

    – Zhe Chen

    27. April 2015 um 13:29 Uhr

  • Wenn es Ihnen schwer fällt, dies zu verstehen, lesen Sie die Antwort von Kirill V. Lyadvinsky, dann kommen Sie zurück und lesen Sie dies.

    – Die Vivandiere

    25. Juni 2015 um 22:35 Uhr

  • Dies ist nur ein weiterer Fall, der zeigt, wie zum größten Teil geerbt wird von SomeBase ist wie eine fest codierte Möglichkeit, einen anonymen Member des Typs einzufügen SomeBase. Dieses hat wie jedes andere Mitglied einen Zugriffsspezifizierer, der die gleiche Kontrolle über den externen Zugriff ausübt.

    – Unterstrich_d

    27. Februar 2016 um 18:28 Uhr


  • @ZheChen Wenn ich Objekte Tom und Jerry der Klasse Person mit privatem Feldalter habe, wie können Sie mit Tom auf Jerrys Alter zugreifen (und es ändern?)

    – Gen

    12. Juli 2016 um 20:25 Uhr

  • Können Sie veranschaulichen, was Sie mit „sich der ‚Erbschaft‘ bewusst“ meinen? Ich kann verstehen “Ich kann darauf zugreifen, ich kann darauf nicht zugreifen”, aber ich verstehe es nicht, wenn einer sagt “Ich weiß, dass A von B erbt”. Was mache ich hier, überprüfe ich die Vererbung?

    – Lineal

    10. September 2018 um 22:44 Uhr

Benutzer-Avatar
Johannes Schaub – litb

Durch das Einschränken der Sichtbarkeit der Vererbung kann der Code nicht erkennen, dass eine Klasse eine andere Klasse erbt: Implizite Konvertierungen von der abgeleiteten in die Basis funktionieren nicht, und static_cast Von der Basis zum Abgeleiteten funktioniert es auch nicht.

Nur Mitglieder/Freunde einer Klasse können private Vererbung sehen, und nur Mitglieder/Freunde und abgeleitete Klassen können geschützte Vererbung sehen.

öffentlich Nachlass

  1. 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ützt Nachlass

  1. Geschützt im Sinne von implementiert. Selten nützlich. Benutzt in boost::compressed_pair um von leeren Klassen abzuleiten und Speicher zu sparen, indem leere Basisklassen optimiert werden (Beispiel unten verwendet keine Vorlage, um auf dem 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!
      }
    };
    

Privat Nachlass

  1. Implementiert im Sinne von. Die Verwendung der Basisklasse dient nur zum Implementieren der abgeleiteten Klasse. Nützlich bei Merkmalen und wenn es auf die Größe ankommt (leere Merkmale, die nur Funktionen enthalten, nutzen die Optimierung der leeren Basisklasse). Oft Eindämmung ist aber die bessere lösung. Die Größe für Zeichenfolgen ist kritisch, daher wird dies hier häufig verwendet

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

öffentlich Mitglied

  1. Aggregat

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

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

geschützt Mitglied

  1. Bereitstellen eines erweiterten Zugriffs für abgeleitete Klassen

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

Privat Mitglied

  1. Behalten Sie Implementierungsdetails bei

    class window {
    private:
      int width;
    };
    

Beachten Sie, dass Umwandlungen im C-Stil absichtlich das Umwandeln einer abgeleiteten Klasse in eine geschützte oder private Basisklasse auf definierte und sichere Weise und auch das Umwandeln in die andere Richtung ermöglichen. Dies sollte unter allen Umständen vermieden werden, da es den Code von Implementierungsdetails abhängig machen kann – aber wenn nötig, können Sie von dieser Technik Gebrauch machen.

  • Ich denke, Scott Myers (so sehr ich seine Sachen auch mag) hat viel für die allgemeine Verwirrung zu sagen. Ich denke jetzt, dass seine Analogien von IS-A und IS-IMPLEMENTED-IN-TERMS-OF für das, was vor sich geht, ausreichend sind.

    – GefahrenMaus

    14. September 2012 um 10:20 Uhr

Benutzer-Avatar
BugShotGG

Diese drei Schlüsselwörter werden auch in einem ganz anderen Zusammenhang verwendet, um das zu spezifizieren Sichtbarkeitsvererbungsmodell.

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

Geben Sie hier die Bildbeschreibung ein

Die obige Tabelle wird wie folgt interpretiert (siehe erste Zeile):

wenn eine Komponente ist erklärt als öffentlich und seine Klasse ist vererbt als öffentlich das Ergebnis Zugriff ist öffentlich.

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 variabel x ist keiner.

Ein ausführlicheres 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;
}

Lassen Sie uns nun 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 Klasse named ist Super oder das Sub Klasse leitet sich von der ab Super Klasse. Das Sub Klasse führt weder neue Variablen noch neue Funktionen ein. Bedeutet es, dass jedes Objekt der Sub Klasse erbt alle Merkmale nach der Super Klasse ist tatsächlich eine Kopie von a Super Objekte der Klasse?

Nein. Das tut es nicht.

Wenn wir den folgenden Code kompilieren, erhalten wir nichts als Kompilierungsfehler, die dies besagen put und get Methoden sind unzugänglich. Wieso den?

Wenn wir den Sichtbarkeitsbezeichner weglassen, geht der Compiler davon aus, dass wir den sogenannten privates Erbe. Es bedeutet, dass alle öffentlich Komponenten der Oberklasse verwandeln sich in Privat zugreifen, sind private Oberklassenkomponenten überhaupt nicht zugänglich. Dies bedeutet folglich, dass Sie letzteres nicht innerhalb der Unterklasse verwenden dürfen.

Wir müssen dem Compiler mitteilen, dass wir die zuvor verwendete Zugriffsrichtlinie beibehalten möchten.

class Sub : public Super { };

Lassen Sie sich nicht täuschen: Dies bedeutet nicht, dass private Komponenten der Super-Klasse (wie die Speichervariable) auf magische Weise in öffentliche umgewandelt werden. Privat Komponenten bleiben Privat, öffentlich
wird bleiben öffentlich.

Objekte der Sub Klasse kann “fast” die gleichen Dinge tun wie ihre älteren Geschwister, die aus der erstellt wurden Super Klasse. “Fast” denn die Tatsache, eine Unterklasse zu sein, bedeutet auch, dass die -Klasse hat den Zugriff auf die privaten Komponenten der Superklasse verloren. Wir können keine Mitgliedsfunktion von schreiben Sub Klasse, die in der Lage wäre, die Speichervariable direkt zu manipulieren.

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

Ja.

Die dritte Zugriffsebene wird aufgerufen geschützt. Das Schlüsselwort geschützt bedeutet, dass die Komponente damit gekennzeichnet ist verhält sich wie eine öffentliche, wenn sie von einer der Unterklassen verwendet wird, und sieht für den Rest der Welt wie eine private aus. — 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 hinzugefügt Sub Klasse und es macht eine wichtige Sache: es greift auf die Speichervariable der Klasse Super zu.

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

object.storage = 0;

Der Compiler teilt Ihnen mit, dass es sich um eine error: 'int Super::storage' is protected.

Schließlich erzeugt das letzte Programm die folgende Ausgabe:

storage = 101

Benutzer-Avatar
Doug T.

Es hat damit zu tun, wie die öffentlichen Member der Basisklasse von der abgeleiteten Klasse verfügbar gemacht werden.

  • public -> die öffentlichen Mitglieder der Basisklasse sind öffentlich (normalerweise die Vorgabe)
  • protected -> Die öffentlichen Mitglieder der Basisklasse werden geschützt
  • private -> Die öffentlichen Mitglieder der Basisklasse sind privat

Wie litb betont, 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 AFAIK-eigenes C++, ist eine “IMPLEMENTED IN TERMS OF”-Beziehung. Das willst du benutzen die öffentliche Schnittstelle in der abgeleiteten Klasse, möchten aber nicht, dass der Benutzer der abgeleiteten Klasse Zugriff auf diese Schnittstelle hat. Viele argumentieren, dass Sie in diesem Fall die Basisklasse aggregieren sollten, d. h. anstatt die Basisklasse als private Basis zu haben, machen Sie ein Mitglied von abgeleitet, um die Funktionalität der Basisklasse wiederzuverwenden.

  • Sagen Sie besser “Öffentlich: Das Erbe wird von allen gesehen”. protected: die Vererbung wird nur von abgeleiteten Klassen und Freunden gesehen”, “private: die Vererbung wird nur von der Klasse selbst und Freunden gesehen”. Dies unterscheidet sich von Ihrer Formulierung, da nicht nur die Mitglieder unsichtbar sein können, sondern auch die IS-A-Beziehung kann unsichtbar sein.

    – Johannes Schaub – litb

    13. Mai 2009 um 20:59 Uhr

  • Das einzige Mal, dass ich private Vererbung verwendet habe, war, genau das zu tun, was Doug T beschreibt, dh “Sie möchten die öffentliche Schnittstelle in der abgeleiteten Klasse verwenden, aber Sie 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 verfügbar zu machen.

    – Reich

    22. April 2010 um 22:06 Uhr

Benutzer-Avatar
Pascha

Member in base class : Private   Protected   Public   

Art der Vererbung : Objekt geerbt als:

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

  • Sagen Sie besser “Öffentlich: Das Erbe wird von allen gesehen”. protected: die Vererbung wird nur von abgeleiteten Klassen und Freunden gesehen”, “private: die Vererbung wird nur von der Klasse selbst und Freunden gesehen”. Dies unterscheidet sich von Ihrer Formulierung, da nicht nur die Mitglieder unsichtbar sein können, sondern auch die IS-A-Beziehung kann unsichtbar sein.

    – Johannes Schaub – litb

    13. Mai 2009 um 20:59 Uhr

  • Das einzige Mal, dass ich private Vererbung verwendet habe, war, genau das zu tun, was Doug T beschreibt, dh “Sie möchten die öffentliche Schnittstelle in der abgeleiteten Klasse verwenden, aber Sie 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 verfügbar zu machen.

    – Reich

    22. April 2010 um 22:06 Uhr

1) Öffentliches Erbe:

a. Auf private Elemente 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.

Daher können andere Klassen öffentliche Member der Basisklasse über das abgeleitete Klassenobjekt verwenden.

2) Geschützte Vererbung:

a. Auf private Elemente 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) Privater Nachlass:

a. Auf private Elemente 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 kann auf keine Mitglieder der Basisklasse von anderen Klassen über das Objekt der abgeleiteten Klasse zugegriffen werden, da sie in der abgeleiteten Klasse privat sind. Daher kann selbst die Unterklasse der abgeleiteten Klasse nicht auf sie zugreifen.

1013670cookie-checkWas ist der Unterschied zwischen öffentlicher, privater und geschützter Vererbung in C++?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy