Делая наследование частным, вы в основном говорите, что даже тот факт, что B наследует от A (вообще), является частным - недоступным / видимым для внешнего мира.
Не вдаваясь в долгое обсуждение того, что произошло бы, если бы это было разрешено, простой факт в том, что это не разрешено. Если вы хотите использовать указатель на базу для ссылки на объект производного типа, вы в значительной степени застряли в использовании общедоступного наследования.
Частное наследование не обязательно (или даже обычно) должно следовать принципу замещения Лискова . Публичное наследование утверждает, что производный объект может быть заменен объектом базового класса, и правильная семантика все равно будет результатом. Однако частное наследование этого не утверждает. Обычное описание отношений, подразумеваемых частным наследованием, - «реализовано в терминах».
Открытое наследование означает, что производный класс поддерживает все возможности базового класса и потенциально добавляет больше. Частное наследование часто означает более или менее противоположное: производный класс использует общий базовый класс для реализации чего-либо с более ограниченным интерфейсом.
Например, предположим, что контейнеры в стандартной библиотеке C ++ были реализованы с использованием наследования, а не шаблонов. В текущей системе std::deque
и std::vector
- это контейнеры, и std::stack
- это адаптер контейнера, который предоставляет более ограниченный интерфейс. Поскольку она основана на шаблонах, можно использовать в std::stack
качестве адаптера для любого std::deque
илиstd::vector
.
Если бы мы хотели предоставить по существу то же самое с наследованием, мы, вероятно, использовали бы частное наследование, поэтому std::stack
было бы что-то вроде:
class stack : private vector {
};
В этом случае мы определенно не хотим, чтобы пользователь мог манипулировать нашим файлом, stack
как если бы он был vector
. Это может (и, вероятно, будет) нарушить ожидания стека (например, пользователь может вставлять / удалять элементы посередине, а не чисто стеклоподобным способом, как задумано). Мы в основном используем vector
как удобный способ реализации нашего стека, но если (например) мы изменили реализацию на stack
автономную (без зависимости от базового класса) или повторно реализовали ее в терминах std::deque
, мы не хотим, чтобы это чтобы воздействовать на любой клиентский код - для клиентского кода это должен быть просто стек, а не какой-то специализированный вариант вектора (или двухсторонней очереди).
protected