Różnica między dziedziczeniem prywatnym, publicznym i chronionym

Jaka jest różnica między public, private, i protected dziedziczenie w C++?

Wszystkie pytania, które znalazłem, dotyczą konkretnych przypadków.
Author: Arsen Khachaturyan, 2009-05-13

16 answers

Aby odpowiedzieć na to pytanie, chciałbym najpierw opisać akcesoria członków własnymi słowami. Jeśli już to wiesz, przejdź do nagłówka " następny:".

Są trzy Accesory, o których wiem: public, protected i private.

Niech:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Wszystko, co jest świadome Base jest również świadome, że Base zawiera publicMember.
  • tylko dzieci (i ich dzieci) są świadome, że Base zawiera protectedMember.
  • nikt oprócz {[4] } nie jest świadomy privateMember.

Przez "jest świadomy", mam na myśli "uznać istnienie, a tym samym być w stanie uzyskać dostęp".

Następny:

To samo dzieje się z dziedziczeniem publicznym, prywatnym i chronionym. Rozważmy klasę Base i klasę Child, która dziedziczy z Base.
  • jeśli dziedziczenie jest public, wszystko, co jest świadome Base i Child jest również świadome, że Child dziedziczy z Base.
  • jeśli spadek jest protected, tylko Child, a jego dzieci, są świadomi, że dziedziczą po Base.
  • jeśli spadek jest private, nikt inny niż Child nie jest świadomy spadku.
 1115
Author: Anzurio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-01 20:08:18
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
};

WAŻNA UWAGA: Wszystkie klasy B, C i D zawierają zmienne x, y i Z. Jest to tylko kwestia dostępu.

O wykorzystaniu Dziedzictwa chronionego i prywatnego można przeczytać tutaj .

 1515
Author: Kirill V. Lyadvinsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-20 06:54:39

Ograniczenie widoczności dziedziczenia sprawi, że kod nie będzie w stanie zobaczyć, że jakaś klasa dziedziczy inną klasę: niejawne konwersje z pochodnej do bazy nie będą działać, a static_cast z bazy do pochodnej też nie będą działać.

Tylko członkowie/przyjaciele klasy mogą widzieć dziedziczenie prywatne, a tylko członkowie / przyjaciele i klasy pochodne mogą widzieć dziedziczenie chronione.

Public dziedziczenie

  1. Jest-dziedziczenie. Przycisk to-okno, wszędzie tam, gdzie potrzebne jest okno, można również przejść przycisk.

    class button : public window { };
    

Chroniony Spadek

  1. Protected-in-terms-of. Rzadko przydatne. Używane w boost::compressed_pair do wyprowadzania z pustych klas i zapisywania pamięci za pomocą optymalizacji pustych klas bazowych (poniższy przykład nie używa szablonu, aby być w punkcie):

    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!
      }
    };
    

Prywatne dziedziczenie

  1. Zaimplementowane-w-kategoriach - Korzystanie z klasa bazowa służy tylko do implementacji klasy pochodnej. Przydatne z cechami i jeśli rozmiar ma znaczenie (puste cechy, które zawierają tylko funkcje, wykorzystają optymalizację pustej klasy bazowej). Często jednak lepszym rozwiązaniem jest zabezpieczenie. Rozmiar dla ciągów jest krytyczny, więc jest to często spotykane użycie tutaj

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

Public członek

  1. Agregat

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

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

Protected member

  1. Zapewnienie rozszerzonego dostępu dla klas pochodnych

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

Private member

  1. Zachowaj szczegóły implementacji

    class window {
    private:
      int width;
    };
    

Zauważ, że rzucanie w stylu C celowo pozwala na rzucanie klasy pochodnej do chronionej lub prywatnej klasy bazowej w zdefiniowanym i bezpiecznym sposób i rzucić w przeciwnym kierunku też. Należy tego unikać za wszelką cenę, ponieważ może to uzależnić Kod od szczegółów implementacji - ale jeśli to konieczne, można skorzystać z tej techniki.

 118
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-20 13:35:57

Te trzy słowa kluczowe są również używane w zupełnie innym kontekście do określenia modelu dziedziczenia widoczności .

Ta tabela gromadzi wszystkie możliwe kombinacje modelu deklaracji i dziedziczenia komponentów, prezentując uzyskany dostęp do komponentów, gdy podklasa jest całkowicie zdefiniowana.

Tutaj wpisz opis obrazka

Powyższa tabela jest interpretowana w następujący sposób (spójrz na pierwszy wiersz):

Jeśli a komponent jest zadeklarowany jako public , a jego klasa jest dziedziczona jako public wynikowy dostęp jest public .

Przykład:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

Uzyskany Dostęp dla zmiennych p, q, r w klasie Subsub jest none.

Inny przykład:

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

Uzyskany Dostęp dla zmiennych y, z w klasie Sub jest zabezpieczony i dla zmiennej x jest brak.

Bardziej szczegółowy przykład:

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

Teraz zdefiniujmy podklasę:

class Sub : Super { };

int main(void) {
    Sub object;

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

Zdefiniowana Klasa o nazwie Sub, która jest podklasą klasy o nazwie Super lub klasy Sub pochodzi z klasy Super. Klasa Sub nie wprowadza nowych zmiennych ani nowych funkcji. Czy to znaczy, że każdy obiekt klasy Sub dziedziczy wszystkie cechy po klasie Super będącej w rzeczywistości a Kopia Super obiektów klasy?

Nie . Nie ma.

Jeśli skompilujemy poniższy kod, otrzymamy tylko błędy kompilacji mówiące, że metody put i get są niedostępne. Dlaczego?

Gdy pominiemy specyfikator widoczności, kompilator zakłada, że zastosujemy tzw. dziedziczenie prywatne . Oznacza to, że wszystkie komponenty public superclass zamieniają się w private access, private superclass komponenty nie będą w ogóle dostępne. Oznacza to, że nie możesz używać tego ostatniego w podklasie.

Musimy poinformować kompilator, że chcemy zachować wcześniej stosowaną politykę dostępu.

class Sub : public Super { };

nie daj się zwieść: nie oznacza to, że prywatne elementy Super Klasa (podobnie jak zmienna storage) zamieni się w publiczne w nieco magiczny sposób. prywatne komponenty pozostaną prywatne , public pozostaną publiczne .

Obiekty klasy Sub mogą robić "prawie" te same rzeczy, co ich starsze rodzeństwo utworzone z klasy Super. "prawie" ponieważ fakt bycia podklasą oznacza również, że Klasa straciła dostęp do prywatnych komponentów klasy nadrzędnej. Nie możemy napisać funkcji składowej klasy Sub, która byłaby w stanie bezpośrednio manipulować zmienną storage.

To bardzo poważna sprawa. ograniczenie. Czy jest jakieś obejście?

Tak .

Trzeci poziom dostępu nazywa się protected. Słowo kluczowe protected oznacza, że komponent oznaczony zachowuje się jak publiczny, gdy jest używany przez którąkolwiek z podklas i wygląda jak prywatny dla reszty świata . -- to prawda tylko dla klas odziedziczonych publicznie (jak Super klasa w naszym przykładzie) --

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

Jak widać w przykładzie kodu mamy nową funkcjonalność do klasy Sub i robi jedną ważną rzecz: uzyskuje dostęp do zmiennej storage z Super klasy .

Nie byłoby możliwe, gdyby zmienna została zadeklarowana jako prywatna. W głównym zakresie funkcji zmienna i tak pozostaje ukryta, więc jeśli napiszesz coś w stylu:

object.storage = 0;

Kompilator poinformuje cię, że jest to error: 'int Super::storage' is protected.

Wreszcie, ostatni program wytworzy następujące wyjście:

storage = 101
 76
Author: BugShotGG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-13 20:13:26

Ma to związek z tym, jak publiczne elementy klasy bazowej są eksponowane z klasy pochodnej.

  • public - > Public członków klasy bazowej będą publiczne (Zwykle domyślne)
  • protected - > public Członkowie klasy bazowej będą chronieni
  • private - > public class 'S base' s members will be private

Jak wskazuje litb, dziedziczenie publiczne jest tradycyjnym dziedziczeniem, które można zobaczyć w większości języków programowania. That is it models an " IS-A" związek. Dziedziczenie prywatne, coś charakterystycznego dla C++, jest relacją" zaimplementowaną w kategoriach". Oznacza to, że chcesz używać publicznego interfejsu w klasie pochodnej, ale nie chcesz, aby użytkownik klasy pochodnej miał dostęp do tego interfejsu. Wielu twierdzi, że w tym przypadku należy zagregować klasę bazową, czyli zamiast mieć klasę bazową jako prywatną bazę, zrobić w członie pochodnej w celu ponownego użycia funkcji klasy bazowej.

 66
Author: Doug T.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-13 21:19:58
Member in base class : Private   Protected   Public   

Typ dziedziczenia : obiekt dziedziczony jako :

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public
 37
Author: kinshuk4,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-26 18:06:54

1) Dziedziczenie Publiczne :

A. prywatne elementy klasy bazowej nie są dostępne w klasie pochodnej.

B. chronione elementy klasy bazowej pozostają chronione w klasie pochodnej.

C. Public Członkowie klasy bazowej pozostają publiczni w klasie pochodnej.

Tak więc, inne klasy mogą używać publicznych członków klasy bazowej poprzez obiekt klasy pochodnej.

2) Dziedziczenie Chronione :

A. Private members of Base class are not accessible in Derived klasy.

B. chronione elementy klasy bazowej pozostają chronione w klasie pochodnej.

C. Public Członkowie klasy bazowej również stają się chronionymi członkami klasy pochodnej.

Tak więc inne klasy nie mogą używać publicznych członków klasy bazowej poprzez obiekt klasy pochodnej, ale są one dostępne dla podklasy pochodnej.

3) Dziedziczenie Prywatne :

A. prywatne elementy klasy bazowej nie są dostępne w klasie pochodnej.

B. osoby chronione i publiczne w bazie klasa staje się prywatnymi członkami klasy pochodnej.

Tak więc, żaden element klasy bazowej nie może być dostępny dla innych klas poprzez obiekt klasy pochodnej, ponieważ są one prywatne w klasie pochodnej. Tak więc nawet podklasa pochodnych klasa nie ma do nich dostępu.

 28
Author: yuvi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-30 08:44:21

Dziedziczenie publiczne modeluje relację IS-A. Z

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

Każdy D jest B.

Prywatny model dziedziczenia jest-zaimplementowany-za pomocą relacji (lub jak to się nazywa). Z

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

A D jest Nie a B, ale każdy D używa swojego B w swojej implementacji. Dziedziczenie prywatne zawsze może być wyeliminowane, używając zamiast tego zabezpieczenia:

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

To D Również można zaimplementować za pomocą B, w tym przypadku za pomocą its b_. Hermetyzacja jest mniej ścisłym sprzężeniem między typami niż dziedziczenie, więc generalnie powinno być preferowane. Czasami używanie zabezpieczenia zamiast prywatnego dziedziczenia nie jest tak wygodne jak prywatne dziedziczenie. Często to kiepska wymówka dla lenistwa.

Chyba nikt nie wie jakie modele dziedziczenia. Przynajmniej nie widziałem jeszcze żadnego przekonującego wyjaśnienia.
 20
Author: sbi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-04 09:26:48

Jeśli dziedziczysz publicznie z innej klasy, wszyscy wiedzą, że dziedziczysz i możesz być użyty polimorficznie przez każdego za pomocą wskaźnika klasy bazowej.

Jeśli dziedziczysz tylko twoje dzieci będą mogły korzystać z Ciebie polimorficznie.

Jeśli dziedziczysz prywatnie tylko Ty będziesz mógł wykonać metody klasy nadrzędnej.

Co w zasadzie symbolizuje wiedzę reszty klas o twoich relacjach z klasą rodzica

 11
Author: Arkaitz Jimenez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-03 11:27:55

Protected data members mogą być dostępne dla dowolnych klas, które dziedziczą po twojej klasie. Jednak członkowie danych prywatnych nie mogą. Powiedzmy, że mamy:

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

Z twojego rozszerzenia do tej klasy, odwoływanie się this.myPrivateMember nie zadziała. Jednak this.myProtectedMember będzie. Wartość jest nadal zamknięta, więc jeśli mamy instancję tej klasy o nazwie myObj, to myObj.myProtectedMember nie będzie działać, więc jest ona podobna w funkcji do prywatnego elementu danych.

 9
Author: Andrew Noyes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-13 20:57:10
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

Na podstawie tego przykładu dla Javy... Myślę, że mały stolik wart tysiąca słów:)

 8
Author: Enissay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:48

Podsumowanie:

  • Private: nikt nie może go zobaczyć z wyjątkiem klasy
  • Protected: Private + derived classes can see it
  • Public: the world can see it

Podczas dziedziczenia można (w niektórych językach) zmienić typ ochrony elementu danych w określonym kierunku, np. z protected NA public.

 7
Author: Roee Adler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-13 20:58:28

Private:

Prywatny członek klasy bazowej może być dostępny tylko dla członków tej klasy bazowej .

Public:

Członkowie publiczni klasy bazowej mogą być dostępni przez członków tej klasy bazowej, członków jej klasy pochodnej, jak również członków, które są poza klasą bazową i klasą pochodną.

Chroniony:

Protected members of a base class can be accessed by members of base class as well as members of its derived klasy.


W skrócie:

Private : base

Protected : base + derived

Public : base + derived + any other member

 6
Author: varun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-12 14:59:20

Znalazłem łatwą odpowiedź, więc pomyślałem, że opublikuję ją również dla mojego przyszłego odniesienia.

Its from the 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
Author: Prajosh Premdas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-24 10:05:09

Jest to zasadniczo Ochrona dostępu publicznych i chronionych członków klasy bazowej w klasie pochodnej. W przypadku publicznego dziedziczenia, Klasa pochodna może widzieć publicznych i chronionych członków bazy. Z dziedziczeniem prywatnym nie może. z klasą protected, pochodną i wszelkimi klasami z niej pochodzącymi mogą je zobaczyć.

 3
Author: Dan Olson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-13 20:51:43

Próbowałem wyjaśnić dziedziczenie za pomocą zdjęcia poniżej.

Głównym gist jest to, że prywatne Członkowie klasy rodzica nigdy nie są bezpośrednio dostępne z pochodnych / potomnych klasy, ale można użyć funkcji członka klasy rodzica, aby uzyskać dostęp do prywatnych członków klasy rodzica. Zmienne prywatne są zawsze obecne w klasie pochodnej, ale nie mogą być dostępne przez klasę pochodną. Jego jak jego ich, ale nie można zobaczyć na własne oczy, ale jeśli zapytać kogoś z klasy rodzica to może opisz to sobie. Mapowanie dziedziczenia cpp

 2
Author: shubhcodegate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-23 08:29:06