Есть ли примеры, в которых мы нуждаемся в * защищенном наследовании на С++?

Пока я видел редкие случаи, когда частное наследование было необходимо, я никогда не сталкивался с ситуацией, когда требуется защищенное наследование. Есть ли у кого-нибудь пример?

Ответы

Ответ 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 на защищенное наследование.

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