Какова разница между публичным, приватным и защищённым наследованием?
Вопрос: Какова разница между public
, private
и protected
наследованием в C++?
Описание проблемы: Я изучаю C++ и пытаюсь разобраться в различных типах наследования, но не могу понять, как именно различаются public
, private
и protected
наследования. Как они влияют на доступ к членам базового класса в производном классе и вне его? Можете ли вы объяснить различия с примерами кода?
5 ответ(ов)
Чтобы ответить на этот вопрос, сначала я хотел бы описать аксессоры членов класса своими словами. Если вы уже это знаете, можете пропустить раздел "дальше:".
Существуют три типа доступа, о которых я знаю: public
, protected
и private
.
Рассмотрим следующий код:
class Base {
public:
int publicMember;
protected:
int protectedMember;
private:
int privateMember;
};
- Все, кто имеет доступ к классу
Base
, также знают о наличииpublicMember
. - Только дочерние классы (и их дочерние классы) знают о наличии
protectedMember
вBase
. - Никто, кроме
Base
, не знает оprivateMember
.
Под "знает" я имею в виду "признает существование и, следовательно, может получить доступ".
дальше:
То же самое происходит с публичным, защищенным и приватным наследованием. Рассмотрим класс Base
и класс Child
, который наследует от Base
.
- Если наследование
public
, то все, кто знает оBase
иChild
, также знают о том, чтоChild
наследуется отBase
. - Если наследование
protected
, толькоChild
и его дочерние классы знают о том, что они наследуют отBase
. - Если наследование
private
, то никто, кромеChild
, не знает о самом наследовании.
Ограничение видимости наследования сделает код неспособным увидеть, что какой-то класс наследует другой класс: не будут работать неявные преобразования от производного к базовому классу, а также static_cast
от базового к производному классу.
Только члены/друзья класса могут видеть приватное наследование, а только члены/друзья и производные классы могут видеть защищенное наследование.
Публичное наследование
Наследование типа IS-A. Кнопка является окном, и везде, где требуется окно, можно использовать и кнопку.
class button : public window { };
Защищенное наследование
Защищенное наследование, реализуемое через. Редко полезно. Используется в
boost::compressed_pair
для наследования от пустых классов и экономии памяти с помощью оптимизации пустых базовых классов (в приведенном ниже примере не используется шаблон для упрощения):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; // обратите внимание, что мы возвращаем *this! } };
Приватное наследование
Реализация через. Использование базового класса предназначено только для реализации производного класса. Полезно с шаблонами и если важен размер (пустые шаблоны, которые содержат только функции, будут использовать оптимизацию пустых базовых классов). Часто решение с содержимым оказывается более эффективным. Размер строк критичен, так что это часто встречается здесь.
template<typename StorageModel> struct string : private StorageModel { public: void realloc() { // использует унаследованную функцию StorageModel::realloc(); } };
Публичный член
Агрегация
class pair { public: First first; Second second; };
Инкапсуляторы
class window { public: int getWidth() const; };
Защищенный член
Обеспечение улучшенного доступа для производных классов
class stack { protected: vector<element> c; }; class window { protected: void registerClass(window_descriptor w); };
Приватный член
Поддержание деталей реализации
class window { private: int width; };
Обратите внимание, что приведение типов в стиле C позволяет намеренно использовать преобразование производного класса в защищенный или приватный базовый класс безопасным способом, а также преобразование в другом направлении. Это следует избегать любой ценой, так как может сделать код зависимым от деталей реализации — однако, если это необходимо, можно использовать такую технику.
Это связано с тем, как публичные члены базового класса доступны из производного класса.
- public - члены публичного класса базового класса будут публичными (обычно это значение по умолчанию).
- protected - члены публичного класса базового класса будут защищенными.
- private - члены публичного класса базового класса будут приватными.
Как указывает litb, публичное наследование — это традиционное наследование, которое вы увидите в большинстве языков программирования. Оно моделирует отношение "Является" (IS-A). Частное наследование, которое, насколько мне известно, является особенностью C++, представляет собой отношение "Реализовано на основе" (IMPLEMENTED IN TERMS OF). То есть, вы хотите использовать публичный интерфейс в производном классе, но не хотите, чтобы пользователь производного класса имел доступ к этому интерфейсу. Многие считают, что в таком случае стоит использовать агрегацию базового класса, то есть вместо того, чтобы делать базовый класс приватным, лучше сделать его членом производного класса, чтобы повторно использовать функциональность базового класса.
В контексте наследования в объектно-ориентированном программировании, доступ к членам базового класса зависит от их уровня доступа. Вот как это выглядит:
Private (Приватный):
- Члены с модификатором доступа
private
недоступны в производном классе. - Их нельзя наследовать.
- Поэтому, в результате, они остаются
private
для производного класса.
- Члены с модификатором доступа
Protected (Защищенный):
- Члены с модификатором доступа
protected
доступны в производном классе и могут быть использованы с тем же уровнем доступа. - Они остаются
protected
в производном классе.
- Члены с модификатором доступа
Public (Публичный):
- Члены с модификатором доступа
public
доступны для всех, включая производные классы. - В производном классе такие члены остаются
public
.
- Члены с модификатором доступа
Итак, результат будет следующим:
Member in base class : Private Protected Public
Тип наследования : Объект наследован как:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
Это означает, что:
- Приватные члены базового класса недоступны в производном классе.
- Защищенные члены доступны в производном классе и сохраняют свой уровень доступа.
- Публичные члены также остаются доступными и публичными.
Наследование в C++: Публичное, Защищенное и Приватное
Публичное наследование (Public Inheritance):
-
- Приватные члены базового класса недоступны в производном классе.
-
- Защищенные члены базового класса остаются защищёнными в производном классе.
-
- Публичные члены базового класса остаются публичными в производном классе.
В результате, другие классы могут использовать публичные члены базового класса через объект производного класса.
-
Защищенное наследование (Protected Inheritance):
-
- Приватные члены базового класса недоступны в производном классе.
-
- Защищенные члены базового класса остаются защищёнными в производном классе.
-
- Публичные члены базового класса также становятся защищёнными членами производного класса.
В этом случае, другие классы не могут использовать публичные члены базового класса через объект производного класса, но они остаются доступны для подклассов производного класса.
-
Приватное наследование (Private Inheritance):
-
- Приватные члены базового класса недоступны в производном классе.
-
- Защищенные и публичные члены базового класса становятся приватными членами производного класса.
Таким образом, никакие члены базового класса не могут быть доступны другим классам через объект производного класса, так как они являются приватными в производном классе. Даже подклассы производного класса не могут получить к ним доступ.
-
Если у вас есть дополнительные вопросы по этому вопросу, не стесняйтесь задавать их!
Что такое Правило трёх?
Разница между const int*, const int * const и int * const?
Новые возможности C++17: что стоит знать?
Имеют ли круглые скобки после имени типа значение при использовании new?
Что означает 'const' в конце объявления метода класса?