Публичное, защищённое и приватное наследование в C++: подробный разбор
Публичное, защищённое и приватное наследование в C++
В этом руководстве мы изучим public, protected и private наследование в C++ на примерах.
В C++ наследовании можно породить дочерний класс от базового в разных режимах доступа. Например:
class Base { .... ... .... };
class Derived : public Base { .... ... .... };
Ключевое слово public в строке
class Derived : public Base
означает, что производный класс создан в публичном режиме. Альтернативно можно использовать protected или private режимы.
Эти три ключевых слова (public, protected, private) называются спецификаторами доступа при наследовании в C++.
Public, protected и private наследование в C++
Public, protected и private наследование имеют следующие свойства:
- Public наследование:
publicчлены базового остаютсяpublicв производном,protected— остаютсяprotected. - Protected наследование:
publicиprotectedчлены базового становятсяprotectedв производном. - Private наследование:
publicиprotectedчлены базового становятсяprivateв производном.
private члены базового класса всегда недоступны производному классу.class Base {
public:
int x;
protected:
int y;
private:
int z;
};
class PublicDerived: public Base {
// x — public
// y — protected
// z — недоступен из PublicDerived
};
class ProtectedDerived: protected Base {
// x — protected
// y — protected
// z — недоступен из ProtectedDerived
};
class PrivateDerived: private Base {
// x — private
// y — private
// z — недоступен из PrivateDerived
}
Пример 1: Публичное наследование в C++
// C++ программа для демонстрации публичного наследования
#include <iostream>
using namespace std;
class Base {
private:
int pvt = 1;
protected:
int prot = 2;
public:
int pub = 3;
// Функция для доступа к private члену
int getPVT() { return pvt; }
};
class PublicDerived : public Base {
public:
// Функция для доступа к protected члену из Base
int getProt() { return prot; }
};
int main() {
PublicDerived object1;
cout << "Private = " << object1.getPVT() << endl;
cout << "Protected = " << object1.getProt() << endl;
cout << "Public = " << object1.pub << endl;
return 0;
}
Вывод
Private = 1 Protected = 2 Public = 3
Здесь PublicDerived наследуется от Base в публичном режиме.
В результате в PublicDerived:
- prot унаследован как protected.
- pub и
getPVT()унаследованы как public. - pvt недоступен, так как он private в
Base.
Так как private и protected члены недоступны из main(), нужны публичные функции getPVT() и getProt() для доступа:
// Ошибка: член "Base::pvt" недоступен
cout << "Private = " << object1.pvt;
// Ошибка: член "Base::prot" недоступен
cout << "Protected = " << object1.prot;
Обратите внимание: getPVT() определена внутри Base, а getProt() — внутри PublicDerived.
Это потому, что pvt (private в Base) недоступен для PublicDerived. А prot доступен для PublicDerived благодаря публичному наследованию, поэтому getProt() может обратиться к нему изнутри PublicDerived.
Доступность при публичном наследовании
| Доступность | private члены | protected члены | public члены |
|---|---|---|---|
| Базовый класс | Да | Да | Да |
| Производный класс | Нет | Да | Да |
Пример 2: Защищённое наследование в C++
// C++ программа для демонстрации защищённого наследования
#include <iostream>
using namespace std;
class Base {
private:
int pvt = 1;
protected:
int prot = 2;
public:
int pub = 3;
int getPVT() { return pvt; }
};
class ProtectedDerived : protected Base {
public:
int getProt() { return prot; }
int getPub() { return pub; }
};
int main() {
ProtectedDerived object1;
cout << "Private cannot be accessed." << endl;
cout << "Protected = " << object1.getProt() << endl;
cout << "Public = " << object1.getPub() << endl;
return 0;
}
Вывод
Private cannot be accessed. Protected = 2 Public = 3
Здесь ProtectedDerived наследуется от Base в защищённом режиме.
В результате в ProtectedDerived:
- prot, pub и
getPVT()унаследованы как protected. - pvt недоступен, так как он private в
Base.
Как известно, protected члены нельзя обращать напрямую извне класса. Поэтому мы не можем использовать getPVT() из ProtectedDerived.
Именно поэтому нужен getPub() в ProtectedDerived для доступа к pub:
// Ошибка: член "Base::getPVT()" недоступен
cout << "Private = " << object1.getPVT();
// Ошибка: член "Base::pub" недоступен
cout << "Public = " << object1.pub;
Доступность при защищённом наследовании
| Доступность | private члены | protected члены | public члены |
|---|---|---|---|
| Базовый класс | Да | Да | Да |
| Производный класс | Нет | Да | Да (унаследованы как protected) |
Пример 3: Приватное наследование в C++
// C++ программа для демонстрации приватного наследования
#include <iostream>
using namespace std;
class Base {
private:
int pvt = 1;
protected:
int prot = 2;
public:
int pub = 3;
int getPVT() { return pvt; }
};
class PrivateDerived : private Base {
public:
int getProt() { return prot; }
int getPub() { return pub; }
};
int main() {
PrivateDerived object1;
cout << "Private cannot be accessed." << endl;
cout << "Protected = " << object1.getProt() << endl;
cout << "Public = " << object1.getPub() << endl;
return 0;
}
Вывод
Private cannot be accessed. Protected = 2 Public = 3
Здесь PrivateDerived наследуется от Base в приватном режиме.
В результате в PrivateDerived:
- prot,
pubиgetPVT()унаследованы как private. - pvt недоступен, так как он private в
Base.
Поскольку private члены недоступны извне, мы не можем использовать getPVT() из PrivateDerived.
Именно поэтому нужен getPub() в PrivateDerived для доступа к pub:
// Ошибка: член "Base::getPVT()" недоступен
cout << "Private = " << object1.getPVT();
// Ошибка: член "Base::pub" недоступен
cout << "Public = " << object1.pub;
Доступность при приватном наследовании
| Доступность | private члены | protected члены | public члены |
|---|---|---|---|
| Базовый класс | Да | Да | Да |
| Производный класс | Нет | Да (унаследованы как private) | Да (унаследованы как private) |
Когда использовать какой режим?
- Public наследование — стандартный случай, моделирует отношение «is-a» (является).
- Protected наследование — редко используется, для внутренней иерархии, где базовый класс не должен быть виден снаружи.
- Private наследование — реализация «has-a» (имеет) через наследование, когда нужно переопределить виртуальные функции или получить доступ к protected членам базы, но не экспортировать интерфейс.
Язык C
- Выбор правильной облачной стратегии: публичное, приватное и гибридное облако
- Публичное облако: преимущества, риски и ключевые соображения
- Приватное облако: преимущества, недостатки и защита бизнес-данных
- Освоение переменных, литералов и констант в C++: подробное руководство
- Классы и объекты в C++: практическое руководство по объектно-ориентированному программированию
- Управление памятью в C++: экспертное использование new и delete
- Дружественные функции и классы в C++: мастерство контроля доступа
- Структуры C++ против классов: практическое руководство для разработчиков встроенных систем
- Sigfox запускает частную сеть (PAN), улучшает геолокацию и расширяет IoT-решения
- C++ Struct vs Class: ключевые отличия, синтаксис и лучшие сценарии использования