[C++] Разница между частным, общественным и защищенным наследованием


Answers

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

ВАЖНОЕ ПРИМЕЧАНИЕ. Классы B, C и D содержат переменные x, y и z. Это просто вопрос доступа.

Об использовании защищенного и частного наследования вы можете прочитать here .

Question

В чем разница между public , private и protected наследованием на C ++? Все вопросы, которые я нашел на SO, касаются конкретных случаев.




Доступ к защищенным данным может осуществляться любыми классами, которые наследуются от вашего класса. Частные члены данных, однако, не могут. Допустим, у нас есть следующее:

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

Из вашего расширения в этот класс ссылка на this.myPrivateMember не будет работать. Однако this.myProtectedMember будет. Значение все еще инкапсулировано, поэтому, если у нас есть экземпляр этого класса myObj , то myObj.myProtectedMember не будет работать, поэтому он аналогичен функции для частного элемента данных.




Резюме:

  • Частный: его никто не видит, кроме как внутри класса
  • Защищено: классы private + производные могут видеть это
  • Общественность: мир может видеть это

При наследовании вы можете (на некоторых языках) изменять тип защиты члена данных в определенном направлении, например, от защищенного до публичного.




Это, по сути, защита доступа публичных и защищенных членов базового класса в производном классе. При наличии общего наследования производный класс может видеть общедоступные и защищенные члены базы. При частном наследовании он не может. С защищенным производным классом и любыми полученными из него классами можно их увидеть.




Member in base class : Private   Protected   Public   

Тип наследования : Объект, унаследованный как :

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



Это связано с тем, как публичные члены базового класса отображаются из производного класса.

  • public -> публичные члены базового класса будут общедоступными (обычно это значение по умолчанию)
  • protected -> публичные члены базового класса будут защищены
  • private -> публичные члены базового класса будут закрытыми

Как подчеркивает litb, публичное наследование является традиционным наследованием, которое вы увидите на большинстве языков программирования. Это моделирует отношения «IS-A». Частное наследование, что-то, что AFAIK, свойственное C ++, является отношением «ВЫПОЛНЕННЫЕ В УСЛОВИЯХ». То есть вы хотите использовать открытый интерфейс в производном классе, но не хотите, чтобы пользователь производного класса имел доступ к этому интерфейсу. Многие утверждают, что в этом случае вы должны агрегировать базовый класс, то есть вместо базового класса как частной базы, сделать в члене производного, чтобы повторно использовать функциональность базового класса.




Публичное наследование моделирует отношения IS-A. С

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

каждый D является B

Частное наследование моделирует отношения IS-IMPLEMENTED-USING (или что-то другое). С

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

D не является B , но каждый D использует свой B в своей реализации. Частное наследование всегда можно устранить, используя вместо него:

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

Этот D тоже может быть реализован с использованием B , в этом случае с использованием его b_ . Сдерживание является менее жесткой связью между типами, чем наследование, поэтому в целом это должно быть предпочтительным. Иногда использование сдерживания вместо частного наследования не так удобно, как частное наследование. Часто это хромое оправдание ленивости.

Я не думаю, что кто-то знает, какие protected модели наследования. По крайней мере, я пока не вижу убедительного объяснения.




Смотрите эти коды, чтобы понять особенности c ++ о наследовании ... Я положил результат в конце ... Надеюсь, это поможет.

#include <iostream>
using namespace std;

class A {
private:
    void pri();
    A(int a);
protected:
    virtual void pro() {}
public:
    void pub1() { cout<<"A.pub1()\n"; }
    virtual void pub2() { cout<<"A.pub2()\n"; }
    virtual void pub3() { cout<<"A.pub3()\n"; }
    virtual void pub4() { cout<<"A.pub4()\n"; }
    virtual void pub5() { cout<<"A.pub5()\n"; }
    virtual void pub6() { cout<<"A.pub6()\n"; }
    virtual void pub7() { cout<<"A.pub7()\n"; }
    virtual void pub8() { cout<<"A.pub8()\n"; }
    void pub9() { cout<<"A.pub9()\n"; }
    virtual void pub10() { cout<<"A.pub10()\n"; }
    void pub11() { cout<<"A.pub11()\n"; }
    explicit A() {}
    virtual ~A() {}
};

class B : public A {
private:
    void pri() { cout<<"B.pri()\n"; }
protected:
    virtual void pub4() { cout<<"B.pub4()\n"; }
    void pub6() { cout<<"B.pub6()\n"; }
public:
    void pro() { cout<<"B.pro() "; B::pri(); }
    void pub1() { cout<<"B.pub1()\n"; }
    void pub2() { cout<<"B.pub2()\n"; }
    void pub5() { cout<<"B.pub5()\n"; }
    virtual void pub7() { cout<<"B.pub7()\n"; }
    virtual void pub8() { cout<<"B.pub8()\n"; }
    virtual void pub9() { cout<<"B.pub9()\n"; }
    void pub10() { cout<<"B.pub10()\n"; }
    void pub11() { cout<<"B.pub11()\n"; }
    explicit B() {}
};

class C : protected B {
public:
    void pub4_() { cout<<"C.pub4_() "; B::pub4(); }
    virtual void pub5() { cout<<"C.pub5()\n"; }
};

class D : private B {
public:
    void pub4_() { cout<<"D.pub4_() "; B::pub4(); }
};

class E : public B {
public:
    virtual void pub4() { cout<<"E.pub4()\n"; }
    virtual void pub7() { cout<<"E.pub7()\n"; }
    virtual void pub8() { cout<<"E.pub8()\n"; }
    virtual void pub9() { cout<<"E.pub9()\n"; }
    virtual void pub10() { cout<<"E.pub10()\n"; }
    virtual void pub11() { cout<<"E.pub11()\n"; }
};

void testClasses() {
    A* ap=new B();
    ap->pub1(); // == A::pub1() //important
    // (new B()).pub1() can't override non-virtual A::pub1() for an A* pointer.
    ap->pub2(); // == B::pub2() //important
    // (new B()).pub1() can override virtual A::pub1() for an A* pointer.
    B b;
    b.A::pub1();
    b.pro();
    B* bp=new B;
    bp->pub3();
    C c;
    //c.pub3(); //error
    //c.pub4(); //error
    c.pub4_();
    c.pub5();
    D d;
    //d.pub3(); //error
    //d.pub4(); //error
    d.pub4_();
    E e;
    //e.pub4(); //error
    delete ap;
    ap = new E();
    ap->pub4();
    ap->pub5();
    ap->pub6();
    ap->pub7();
    delete bp;
    bp = new E();
    e.pub8();
    e.A::pub8();
    e.B::A::pub8();
    e.B::pub8();
    ap->pub8();
    bp->pub8();
    e.pub9();
    e.A::pub9();
    e.B::A::pub9();
    e.B::pub9();
    ap->pub9(); // important
    bp->pub9();
    e.pub10();
    e.A::pub10();
    e.B::A::pub10();
    e.B::pub10();
    ap->pub10(); // important
    bp->pub10(); // very important... eventhough B::pub10() is non-virtual,
                 // bp->pub10() != b.pub10();
    e.pub11();
    e.A::pub11();
    e.B::A::pub11();
    e.B::pub11();
    ap->pub11();
    bp->pub11();
    delete ap;
    delete bp;
    return;
}

int main() {
    testClasses();
    return 0;
}









/////////////////////////////////////////
........
Result :
........

A.pub1()
B.pub2()
A.pub1()
B.pro() B.pri()
A.pub3()
C.pub4_() B.pub4()
C.pub5()
D.pub4_() B.pub4()
E.pub4()
B.pub5()
B.pub6()
E.pub7()
E.pub8()
A.pub8()
A.pub8()
B.pub8()
E.pub8()
E.pub8()
E.pub9()
A.pub9()
A.pub9()
B.pub9()
A.pub9()
E.pub9()
E.pub10()
A.pub10()
A.pub10()
B.pub10()
E.pub10()
E.pub10()
E.pub11()
A.pub11()
A.pub11()
B.pub11()
A.pub11()
B.pub11()