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