it-swarm.com.de

Unterschied zwischen privater, öffentlicher und geschützter Vererbung

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

932
user106599

Um diese Frage zu beantworten, möchte ich zuerst die Accessoren der Mitglieder in meinen eigenen Worten beschreiben. Wenn Sie dies bereits wissen, fahren Sie mit der Überschrift "next:" fort.

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

Lassen:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Alles, was über Base Bescheid weiß, weiß auch, dass BasepublicMember enthält.
  • Nur die Kinder (und ihre Kinder) wissen, dass BaseprotectedMember enthält.
  • Niemand außer Base weiß von privateMember.

Mit "ist sich dessen bewusst" meine ich "die Existenz anerkennen und somit in der Lage sein, darauf zuzugreifen".

nächster:

Gleiches gilt für die öffentliche, private und geschützte Vererbung. Betrachten wir eine Klasse Base und eine Klasse Child, die von Base erbt.

  • Wenn die Vererbung public ist, wissen alle, die Base und Child kennen, dass Child von Base erbt.
  • Wenn die Vererbung protected ist, wissen nur Child und seine untergeordneten Objekte, dass sie von Base erben.
  • Wenn die Vererbung private ist, weiß niemand außer Child von der Vererbung.
1002
Anzurio
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ütztem und privatem Erbe lesen Sie hier .

1372

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

public Vererbung

  1. IS-A Vererbung. Eine Schaltfläche ist ein Fenster, und wo immer ein Fenster benötigt wird, kann auch eine Schaltfläche übergeben werden.

    class button : public window { };
    

protected Vererbung

  1. Geschützt implementiert in Bezug auf. Selten nützlich. Wird in boost::compressed_pair verwendet, um aus leeren Klassen abzuleiten und Speicherplatz zu sparen, indem die Optimierung für leere Basisklassen verwendet wird.

    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 Vererbung

  1. 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, nutzen die leere Basisklassenoptimierung). Oft ist die Eindämmung 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();
      }
    };
    

öffentlich Mitglied

  1. Aggregat

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

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

protected Mitglied

  1. Erweiterten Zugriff für abgeleitete Klassen bereitstellen

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

privat Mitglied

  1. Implementierungsdetails aufbewahren

    class window {
    private:
      int width;
    };
    

Beachten Sie, dass C-Casts 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 auf jeden Fall vermieden werden, da Code von Implementierungsdetails abhängig gemacht werden kann. Bei Bedarf können Sie diese Technik jedoch verwenden.

107

Dies hängt damit zusammen, wie die öffentlichen Member der Basisklasse aus der abgeleiteten Klasse verfügbar gemacht werden.

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

Wie in Litb ausgeführt, handelt es sich bei der öffentlichen Vererbung um die traditionelle Vererbung, die in den meisten Programmiersprachen verwendet wird. Das heißt, es modelliert eine "IS-A" -Beziehung. Private Vererbung, etwas AFAIK Besonderes in C++, ist eine "IMPLEMENTED IN TERMS OF" -Beziehung. Das heißt, Sie möchten verwenden die öffentliche Schnittstelle in der abgeleiteten Klasse, möchten jedoch nicht, dass der Benutzer der abgeleiteten Klasse Zugriff auf diese Schnittstelle hat. Viele argumentieren, dass Sie in diesem Fall die Basisklasse aggregieren sollten, anstatt die Basisklasse als private Basis zu verwenden, und sie in ein abgeleitetes Member machen, um die Funktionalität der Basisklasse wiederzuverwenden.

62
Doug T.

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

Diese Tabelle enthält alle möglichen Kombinationen aus Komponentendeklaration und Vererbungsmodell, die den resultierenden Zugriff auf die Komponenten darstellen, wenn die Unterklasse vollständig definiert ist.

enter image description here

Die obige Tabelle wird folgendermaßen interpretiert (siehe erste Zeile):

wenn eine Komponente deklariert als öffentlich ist und ihre Klasse geerbt als öffentlich ist = das resultierende 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 in der Klasse Subsub ist keine.

Ein anderes 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 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;
}

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 der Klasse Sub ist, wird von der Klasse Super abgeleitet. Die Klasse Sub führt weder neue Variablen noch neue Funktionen ein. Bedeutet dies, dass ein Objekt der Klasse Sub alle Merkmale erbt, nachdem die Klasse Super tatsächlich eine Kopie der Objekte einer Klasse Super ist?

Nein. Das ist nicht der Fall.

Wenn wir den folgenden Code kompilieren, erhalten wir nur Kompilierungsfehler, die besagen, dass auf die Methoden put und get nicht zugegriffen werden kann. Warum?

Wenn wir den Sichtbarkeitsspezifizierer weglassen, geht der Compiler davon aus, dass wir das sogenannte private inheritance anwenden werden. Dies bedeutet, dass alle öffentlichen Komponenten der Oberklasse zu privaten Zugriff werden, auf private Komponenten der Oberklasse kann überhaupt nicht zugegriffen werden. Dies bedeutet folglich, dass Sie letzteres nicht innerhalb der Unterklasse verwenden dürfen.

Wir müssen den Compiler 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 Klasse Super (wie die Speichervariable) in gewisser Weise zu öffentlichen werden magische Art und Weise. privat Komponenten bleiben privat, öffentlich bleiben öffentlich.

Objekte der Klasse Sub können "fast" die gleichen Aktionen ausführen 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 Superklasse verloren hat. Wir können keine Mitgliedsfunktion der Klasse Sub schreiben, die die Speichervariable direkt manipulieren könnte.

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

Ja.

Die dritte Zugriffsebene heißt protected. Das Schlüsselwort protected bedeutet, dass die damit markierte Komponente 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 vererbten 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, haben wir eine neue Funktionalität für die Klasse Sub und sie macht eine wichtige Sache: sie greift auf die Speichervariable der Klasse Super z.

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

object.storage = 0;

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

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

storage = 101
58
BugShotGG
Member in base class : Private   Protected   Public   

Vererbungstyp: Objekt vererbt als:

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public
35
kinshuk4

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 Objekt Abgeleitete Klasse 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.

Andere Klassen können also keine öffentlichen Mitglieder der Basisklasse über das Objekt Abgeleitete Klasse verwenden. Sie sind jedoch für Unterklassen von Derived verfügbar.

) Private Inheritance:

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 Objekt Abgeleitete Klasse nicht auf Mitglieder der Basisklasse zugreifen, da sie in der abgeleiteten Klasse privat sind. Daher kann auch eine Unterklasse der abgeleiteten Klasse nicht auf sie zugreifen.

25
yuvi

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

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

jedes Dist aB.

Die private Vererbung modelliert eine IS-IMPLEMENTED-USING-Beziehung (oder wie auch immer genannt). Mit

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

a D ist nicht a B, aber jedes D verwendet sein B in seiner Implementierung. Private Vererbung kann immer durch die Verwendung von Containment beseitigt werden:

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

Auch dieses D kann mit B implementiert werden, in diesem Fall mit seinem b_. Einschließung ist eine weniger enge Kopplung zwischen Typen als Vererbung, daher sollte es im Allgemeinen bevorzugt werden. Manchmal ist die Verwendung von Containment anstelle der privaten Vererbung nicht so praktisch 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.

19
sbi

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 Sie nur von Ihren Kinderklassen polymorph verwendet werden.

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

Dies symbolisiert im Wesentlichen das Wissen der übrigen Klassen über Ihre Beziehung zu Ihrer Elternklasse

12
Arkaitz Jimenez

Auf geschützte Datenmember können alle Klassen zugreifen, die von Ihrer Klasse erben. Private Datenmitglieder können dies jedoch nicht. Angenommen, wir haben Folgendes:

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

In Ihrer Erweiterung zu dieser Klasse funktioniert das Verweisen auf this.myPrivateMember nicht. Jedoch wird this.myProtectedMember. Der Wert ist immer noch gekapselt. Wenn also eine Instanz dieser Klasse mit dem Namen myObj vorliegt, funktioniert myObj.myProtectedMember nicht, sodass die Funktion einem privaten Datenelement ähnlich ist.

9
Andrew Noyes
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 this Beispiel für Java ... Ich denke, eine kleine Tabelle sagt mehr als tausend Worte :)

8
Enissay

Zusammenfassung:

  • Privat: Niemand kann es sehen, außer innerhalb der Klasse
  • Geschützt: Private + abgeleitete Klassen können es sehen
  • Öffentlichkeit: Die Welt kann es sehen

Beim Erben können Sie (in einigen Sprachen) den Schutztyp eines Datenelements in eine bestimmte Richtung ändern, z. von geschützt zu öffentlich.

7
Roee Adler

Privatgelände:

Auf die privaten Mitglieder einer Basisklasse können nur Mitglieder dieser Basisklasse zugreifen.

Öffentlichkeit:

Auf die öffentlichen Member einer Basisklasse können Member dieser Basisklasse, Member ihrer abgeleiteten Klasse sowie die Member außerhalb der Basisklasse und der abgeleiteten Klasse zugreifen.

Geschützt:

Auf die geschützten Member einer Basisklasse können sowohl Member der Basisklasse als auch Member der abgeleiteten Klasse zugreifen.


Zusamenfassend:

privat: Basis

protected: Basis + abgeleitet

public: Basis + abgeleitet + jedes andere Mitglied

6
varun

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
}
4
Prajosh Premdas

Dies 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. Bei privater Vererbung ist dies nicht möglich. Mit protected können die abgeleitete Klasse und alle davon abgeleiteten Klassen sie sehen.

3
Dan Olson