Первая итерация задачи (простая, на внимательность):
#include <iostream> class Base { protected: virtual void protectedVirtualMethod() = 0; }; class A: public Base { public: A(): Base() { } protected: void protectedVirtualMethod() { std::cout << "A" << std::endl; } }; class B : public Base { public: B(): Base() { a = new A(); } void callProtected() { protectedVirtualMethod(); } protected: void protectedVirtualMethod() { std::cout << "B" << std::endl; a->protectedVirtualMethod(); } private: Base *a; }; int main() { B b; b.callProtected(); return 0; }Скомпилируется ли этот код? Почему? Если скомпилируется, то какой будет вывод?
Ответ (надо выделить): Нет, не скомпилируется, ошибка доступа к a->protectedVirtualMethod(), нельзя вызывать protected методы не из своей иерархии.
Вторая итерация задачи (на чутье):
Изменим Base таким образом
class Base { friend class B; protected: virtual void protectedVirtualMethod() = 0; };
Теперь скомпилируется? Почему? Что выведет?
Ответ (надо выделить): Скомпилируется, B теперь друг класса Base и может вызывать любые его методы, Виртуальные методы будут работать как им и положено, выведет: B A.
Третья итерация задачи (закрепляем материал):
Меняем в классе B тип *a на A
class B : public Base { //....... private: A *a; };
Вопросы те же.
Ответ (надо выделить): Не скомпилируется, по той же причине, что и в первом случае, потому что друзья не наследуются.
Результат третьего варианта не совсем очевиден. Думал, будет идентичен второму, там ведь, по сути, та же реализация класса А вызывается.
ReplyDeleteВ этом вся и соль, в третьем случае вызывается объект типа A а не объект типа Base, а для объекта A не объявлен друг
Delete