Вопрос 26: Закрытое наследование и его альтернатива - включение.
От того, с каким спецификатором доступа объявляется наследование базового класса, зависит статус доступа к членам производного класса.
Общая форма наследования классов имеет следующий вид:
class имя_класса: доступ имя_класса {....};
Здесь доступ определяет, каким способом наследуется базовый класс. Закрытое наследование - это когда спецификатор доступа принимает значение private, при этом все публичные и защищенные члены базового класса становятся частными членами производного класса.
ДЛЯ СПРАВКИ:Спецификатор доступа может принимать три значения — private, public и protected. В случае, если спецификатор доступ опущен, то по умолчанию подразумевается на его месте спецификатор private. Если спецификатор доступ принимает значение public, то все публичные и защищенные члены базового класса становятся соответственно публичными и защищенными членами производного класса. Если спецификатор доступ принимает значение protected, то все публичные и защищенные члены базового класса становятся защищенными членами производного класса.
Закрытое наследование означает реализацию посредством - т.е. от базового класса необходимо взять какую-то функциональность, базовый класс и потомок не имеют како-либо концептуальной связи.Закрытое наследование не носит характера отношения подтипов.Закрытое (также как и защищенное) наследование не создает иерархии типов.
ПРИМЕР
#include <iostream.h>
class X {
protected: int i;
}
class Y: private X {...};// i преобразовано к частному члену Y
class Z: public Y {public:void f();};
//поскольку i является частным для Y, оно не может наследоваться в Z (не создается иерархии объектов)
void Z::f(){ i = 2;}// данная функция не работает т.к. i не доступна
Агрегация или включение – это когда членом одного класса становится объект другого:
Пример использования включения:
Пусть класс D имеет член класса B.
class D
{
public:
B b;
...
};
В свою очередь класс B имеет член класса C.
class В
{
public:
С с;
...
};
Таким образом, используя включение мы строим иерархию объектов. С точки зрения проектирования закрытое наследование равносильно включению, если не считать вопроса с замещением функци
В общем случае между включением и наследованием(не закрытым) есть принципиальная разница:
Включение — это отношение has a (имеет).Используя включение мы строим иерархию объектов.
Наследование — это отношение is a (является). Используя наследование (не закрытое), мы сторим иерархию классов.
Пример (для понимания): автомобиль имеет руль, колеса и т.д. и т.п.
И автомобиль является транспортным средством.
Есть несколько сценариев, когда стоит применять закрытое наследование вместо включения:
Необходимо переопределение абстрактных и/или виртуальных методов.
Необходимо использовать экземпляр наследника полиморфным образом в ограниченном окружении (например, в дружественной функции). Но в общем смысле отношение ЯВЛЯЕТСЯ между наследником и базовым классом отсутствует.
При закрытом наследовании, наследник может обращаться к защищенным членом базового класса.
Закрытое наследование позволяет реализовать "сужающее" наследование. Когда наследник содержит лишь несколько методов базового класса (путем поднятия види-мости с помощью using Base::ProtectedMethod).
Если все это нужно, то закрытое наследование будет более предпочтительнее включения.
Пример:
class A
{
public: void PublicFoo() {}
virtual void VirtualPublicFoo() {}
protected: void ProtectedFoo() {}
private: void PrivateFoo() {}
};
class B : private A
{
friend void CrazyPolymorphicMethod(const A* a);
public: using A::ProtectedFoo;
void Foo(){ // Поднимаем видимость одного из методов базового класса
ProtectedFoo();// Вызываем закрытый метод!
CrazyPolymorphicMethod(this);// Пример ограниченного полиморфизма
}
private: virtual void VirtualPublicFoo()
override{/* Переопределяем виртуальный метод!*/}
};
void CrazyPolymorphicMethod(const A* a)
{/**/}