Делая наследование частным, вы в основном говорите, что даже тот факт, что 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
Оно делает. И если
A* p = new B;
были разрешены, то к унаследованным членам any
B
можно было получить доступ из внешнего мира, просто создав файлA*
. Поскольку они наследуются в частном порядке, такой доступ является незаконным, как и апкастинг.источник
clang++
дает более понятное сообщение об ошибке:example.cpp:9:13: error: cannot cast 'B' to its private base class 'A' A* ab = new B; ^ example.cpp:6:11: note: declared private here class B : private A { }; ^~~~~~~~~ 1 error generated.
Я не специалист по C ++, но, похоже, это просто недопустимо. Пойду покопаюсь в спецификации и посмотрю, что у меня получится.
Изменить: вот соответствующая ссылка из спецификации - Раздел 4.10 Преобразования указателей , параграф 3:
источник
Это довольно просто: тот факт, что
A
наследуется частным образом, означает, что фактB
расширенияA
является секретом и толькоB
«знает» его. Это само определение частного наследования.источник
private
наprotected
.B
и подклассами (и друзьями)B
. "A* ab = new B;
" будет законным в гипотетическом классеC
, являющемся подклассомB
.Частное наследование означает, что за пределами производного класса информация о наследовании скрыта. Это означает, что вы не можете привести производный класс к базовому классу: связь неизвестна вызывающему.
источник
private
Единственное дело должно заключаться в том, чтобы контролировать поведение членов. Какой будет вред, если информация о наследовании не будет скрыта?Это работает
#include <iostream> using namespace std; class A{ public: virtual void update() = 0; }; class B: public A{ public: virtual void update(){std::cout<<"hello";}; }; int main() { A *a = new B(); a->update(); return 0; }
источник