Наследование: '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++? Выглядит совершенно безобидно.

578   5  

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 типа "указатель на cvD", где D тип класса, может быть преобразованы в prvalue типа "указатель на cv B", где B-базовый класс D. Если B является недоступным или неоднозначным базовым классом D программа, которая требует такого преобразования является некорректным.

Это довольно просто: дело в том, что A наследуется частным образом означает, что тот факт, что B extends A - Это секрет, и только B "знает" это. Это само определение частного наследования.

частное наследование означает, что вне производного класса информация о наследовании скрыта. Это означает, что вы не можете привести производный класс к базовому классу: связь не известна вызывающему объекту.

Comments

    Ничего не найдено.