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

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

  • Что такое нарезка объектов?
  • 15 Solutions collect form web for “Разница между частным, общественным и защищенным наследованием”

    Чтобы ответить на этот вопрос, я хотел бы сначала описать членство участника в своих собственных словах. Если вы уже знаете это, перейдите к заголовку «next:».

    Есть три аксессора, о которых я знаю: public , protected и private .

    Позволять:

     class Base { public: int publicMember; protected: int protectedMember; private: int privateMember; }; 
    • Все, что известно о Base , также известно, что Base содержит publicMember .
    • Только дети (и их дети) знают, что Base содержит protectedMember .
    • Никто, кроме Base не знает о privateMember .

    «Я знаю», я имею в виду «признать существование и, следовательно, иметь доступ».

    следующий:

    То же самое происходит с государственным, частным и защищенным наследованием. Рассмотрим class Base и class Child который наследует от Base .

    • Если наследование public , все, что известно о Base и Child , также известно, что Child наследует от Base .
    • Если наследование protected , только Child и его дети знают, что они наследуют от Base .
    • Если наследование является private , никто, кроме Child не знает о наследовании.
     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. Это просто вопрос доступа.

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

    Ограничение видимости наследования сделает код неспособным увидеть, что некоторый class наследует другой class: неявные преобразования из производного на базу не будут работать, а static_cast от базы до производной тоже не будет работать.

    Только члены / друзья classа могут видеть личное наследование, и только члены / друзья и производные classы могут видеть защищенное наследование.

    публичное наследование

    1. Наследование IS-A. Кнопка – это окно, и в любом месте, где требуется окно, кнопка также может быть передана.

       class button : public window { }; 

    защищенное наследование

    1. Защищенный реализованный в-условиях. Редко полезно. Используется в boost::compressed_pair для вывода из пустых classов и сохранения памяти с использованием пустых оптимизаций базового classа (пример ниже не использует шаблон для сохранения в точке):

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

    частное наследство

    1. Реализована-в-ухудшений условий. Использование базового classа выполняется только для реализации производного classа. Полезно с чертами и если размер имеет значение (пустые черты, содержащие только функции, будут использовать пустую оптимизацию базового classа). Тем не менее, локализация является лучшим решением. Размер для строк имеет решающее значение, поэтому часто используется здесь

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

    общественный член

    1. заполнитель

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

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

    защищенный член

    1. Обеспечение расширенного доступа для производных classов

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

    частный член

    1. Сохранять детали реализации

       class window { private: int width; }; 

    Обратите внимание, что C-style casts специально позволяет отличать производный class к защищенному или частному базовому classу определенным и безопасным образом и также передавать в другое направление. Этого следует избегать любой ценой, поскольку он может сделать код зависимым от деталей реализации, но при необходимости вы можете использовать этот метод.

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

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

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

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

    В этой таблице собраны все возможные комбинации объявления компонента и модели наследования, представляющие результирующий доступ к компонентам, когда подclass полностью определен.

    введите описание изображения здесь

    Приведенная выше таблица интерпретируется следующим образом (взгляните на первую строку):

    если компонент объявлен как открытый, а его class наследуется как открытый, доступ к нему является общедоступным .

    Пример:

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

    Полученный в результате доступ для переменных p , q , r в classе Subsub не равен.

    Другой пример:

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

    Полученный в результате доступ для переменных y , z в classе Sub защищен, а для переменной xнет .

    Более подробный пример:

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

    Теперь давайте определим подclass:

     class Sub : Super { }; int main(void) { Sub object; object.put(100); object.put(object.get()); cout < < object.get() << endl; return 0; } 

    Определенный class с именем Sub, который является подclassом classа с именем Super или этот Sub class, получен из classа Super . Sub вводит ни новые переменные, ни новые функции. Означает ли это, что любой объект classа Sub наследует все черты после того, как class Super на самом деле является копией объектов classа Super ?

    Нет . Это не так.

    Если мы скомпилируем следующий код, мы получим только ошибки компиляции, говорящие, что методы put и get недоступны. Зачем?

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

    Мы должны сообщить компилятору, что мы хотим сохранить ранее используемую политику доступа.

     class Sub : public Super { }; 

    Не следует вводить в заблуждение : это не означает, что частные компоненты classа Super (например, переменная хранения) станут несколько волшебными способами. Частные компоненты останутся частными , общественность останется открытой .

    Объекты Sub classа могут делать «почти» те же вещи, что и их старшие братья и сестры, созданные из classа Super . «Почти», потому что факт подclassа также означает, что class потерял доступ к частным компонентам суперclassа . Мы не можем написать функцию-член classа Sub которая могла бы напрямую манипулировать переменной хранилища.

    Это очень серьезное ограничение. Есть ли обходной путь?

    Да .

    Третий уровень доступа называется защищенным . Защищенное ключевое слово означает, что компонент, помеченный им, ведет себя как общеansible, когда он используется каким-либо из подclassов и выглядит как частный для остального мира . - Это справедливо только для публично унаследованных classов (например, class Super в нашем примере) -

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

    Как вы видите в примере кода, мы добавляем новую функциональность в Sub class, и это делает одну важную вещь: она обращается к переменной хранения из classа Super .

    Было бы невозможно, если бы переменная была объявлена ​​как закрытая. В области основной функции переменная остается скрытой в любом случае, поэтому, если вы пишете что-нибудь вроде:

     object.storage = 0; 

    Компилятор сообщит вам, что это error: 'int Super::storage' is protected .

    Наконец, последняя программа будет выдавать следующий результат:

     storage = 101 
     Member in base class : Private Protected Public 

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

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

    1) Наследование на государственном уровне :

    а. Частные члены базового classа недоступны в classе Derived.

    б. Защищенные члены базового classа остаются защищенными в classе Derived.

    с. Публичные члены базового classа остаются общедоступными в classе Derived.

    Таким образом, другие classы могут использовать публичные элементы базового classа через объект classа Derived.

    2) Защищенное наследование :

    а. Частные члены базового classа недоступны в classе Derived.

    б. Защищенные члены базового classа остаются защищенными в classе Derived.

    с. Публичные члены базового classа тоже становятся защищенными членами classа Derived.

    Таким образом, другие classы не могут использовать публичные элементы базового classа через Derived class object; но они доступны для подclassа Derived.

    3) Частное наследование :

    а. Частные члены базового classа недоступны в classе Derived.

    б. Защищенные и публичные члены базового classа становятся частными членами classа Derived.

    Таким образом, ни один из членов classа Base не может получить доступ к другим classам через объект classа Derived, поскольку они являются частными в classе Derived. Таким образом, даже подclass classа Derived не может получить к ним доступ.

    Публичное наследование моделирует отношения 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 модели наследования. По крайней мере, я пока не вижу убедительного объяснения.

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

    Если вы наследуете защищенно, только ваши classы детей смогут использовать вас в полиморфном режиме.

    Если вы наследуете конфиденциально, то только вы сможете выполнять методы родительского classа.

    Что в основном символизирует знание остальных classов о ваших отношениях с вашим родительским classом

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

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

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

    Резюме:

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

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

     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 

    На основе этого примера для java … Я думаю, что столик стоит тысячи слов 🙂

    Частный:

    Частным членам базового classа могут быть доступны только члены этого базового classа.

    Общественность:

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

    Защищено:

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


    Вкратце:

    частный : базовый

    protected : base + производные

    public : base + производный + любой другой член

    Я нашел легкий ответ и поэтому подумал о том, чтобы разместить его для моей будущей справки.

    Его из ссылок 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 } 

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

    Давайте будем гением компьютера.