Наследование: 'A' является недоступной базой 'B'
$ cat inheritance.cpp
#include <iostream>
using namespace std;
class A { };
class B : private A { };
int main() {
A* ab = new B;
}
$
$ g++ inheritance.cpp
inheritance.cpp: In function 'int main()':
inheritance.cpp:9: error: 'A' is an inaccessible base of 'B'
$
Я просто не понимаю эту ошибку.
как я понимаю, и как в этом уроке подтверждает, что private наследование должно только изменить, как члены class B видны внешнему миру.
Я думаю, что частный спецификатор делает больше, чем просто изменить видимость class B здесь члены.
- что я получаю эту ошибку и что это значит?
- в принципе, что не так с разрешением этого типа кода на C++? Выглядит совершенно безобидно.
5 ответов:
делая наследование частным, вы в основном говорите, что даже тот факт, что 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, мы не хотите, чтобы это повлияло на любой клиентский код-для клиентского кода это должен быть просто стек, а не какая-то специализированная разновидность вектора (или deque).
частное наследование должно изменить только то, как члены класса B видны внешнему миру
это делает. А если
A* p = new B;были разрешены, то унаследованные члены любого
Bможно получить доступ из внешнего мира, просто сделавA*. Так как они унаследованы частным образом, этот доступ является незаконным, и так же как и upcast.
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++, но похоже, что это просто не разрешено. Я пойду покопаюсь в спецификации и посмотрю, что я придумаю.
Edit: вот соответствующая ссылка из раздела spec-Section 4.10 преобразования указателя пункт 3:
prvalue типа "указатель на cv
D", гдеDтип класса, может быть преобразованы в prvalue типа "указатель на cvB", где B-базовый классD. ЕслиBявляется недоступным или неоднозначным базовым классомDпрограмма, которая требует такого преобразования является некорректным.
Это довольно просто: дело в том, что
Aнаследуется частным образом означает, что тот факт, чтоBextendsA- Это секрет, и толькоB"знает" это. Это само определение частного наследования.
частное наследование означает, что вне производного класса информация о наследовании скрыта. Это означает, что вы не можете привести производный класс к базовому классу: связь не известна вызывающему объекту.
Comments