Есть ли примеры, в которых мы нуждаемся в * защищенном наследовании на С++?
Пока я видел редкие случаи, когда частное наследование было необходимо, я никогда не сталкивался с ситуацией, когда требуется защищенное наследование. Есть ли у кого-нибудь пример?
Ответы
Ответ 1
Люди здесь, кажется, ошибочно считают защищенное наследование классов и защищенные методы.
FWIW, я никогда не видел, чтобы кто-либо использовал защищенное наследование класса, и если я правильно помню, я думаю, что Страуструп даже считал "защищенный" уровень ошибкой в С++. Там очень мало вы не можете сделать, если вы удалите этот уровень защиты и будете полагаться только на общественные и частные.
Ответ 2
Существует очень редкий случай защищенного наследования. Здесь вы хотите использовать covariance:
struct base {
virtual ~base() {}
virtual base & getBase() = 0;
};
struct d1 : private /* protected */ base {
virtual base & getBase() {
return this;
}
};
struct d2 : private /* protected */ d1 {
virtual d1 & getBase () {
return this;
}
};
Предыдущий фрагмент попытался скрыть базовый класс и обеспечить контролируемую видимость баз и их функций по любой причине, предоставляя функцию "getBase".
Однако в struct d2
он не сработает, так как d2
не знает, что d1
получен из base
. Таким образом, covariance
не будет работать. Выход из этого заключается в том, что они защищают их, так что наследование видно в d2.
Аналогичным примером использования этого является то, что вы получаете от std::ostream
, но не хотите, чтобы случайные люди записывали в ваш поток. Вы можете предоставить виртуальную функцию getStream
, которая возвращает std::ostream&
. Эта функция может выполнить некоторую подготовку потока для следующей операции. Например, вставьте определенные манипуляторы.
std::ostream& d2::getStream() {
this->width(10);
return *this;
}
logger.getStream() << "we are padded";
Ответ 3
С++ FAQ Lite упоминает случай, когда использование частного наследования является законным решением (см. [24.3.] Кому я предпочитаю: состав или личное наследование?). Это когда вы хотите вызвать производный класс из частного базового класса с помощью виртуальной функции (в данном случае derivedFunction()
):
class SomeImplementationClass
{
protected:
void service() {
derivedFunction();
}
virtual void derivedFunction() = 0;
// virtual destructor etc
};
class Derived : private SomeImplementationClass
{
void someFunction() {
service();
}
virtual void derivedFunction() {
// ...
}
// ...
};
Теперь, если вы хотите получить из класса Derived и хотите использовать Base::service()
из производного класса (скажем, вы хотите переместить Derived::someFunction()
в производный класс), самый простой способ выполнить это: измените частное наследование Base
на защищенное наследование.
Извините, не могу придумать более конкретного примера. Лично я хотел бы сделать все наследование общедоступным, чтобы избежать траты времени на "должен ли я защищать отношения наследования или частные".