Переопределение виртуальной функции может быть выполнено только в том случае, если переопределенная функция имеет ту же сигнатуру (тип аргументов, const
квалификаторы и т. Д. c), что и унаследованную.
Итак
* Возможно 1005 *
, но изменение подписи f()
, как в
struct B : public A
{
virtual void f(Y &);
};
, фактически скрывает унаследованный f()
, а не переопределяет его. С помощью идентификатора override
компилятор обнаружит, что это не переопределение, и диагностирует ошибку.
Можно передать Y
в A::f()
или B::f()
, если правильно переопределить, поскольку ваш Y
является производным от X
. Но невозможно переопределить A::f()
с помощью функции, у которой любой аргумент отличается от A::f()
.
Существует особый случай для функции, которая возвращает указатель (или, альтернативно, ссылку ) к базовому классу - это может быть переопределено функцией, которая возвращает указатель на производный класс. Ограничение на то, что аргументы должны иметь один и тот же тип (ы). Таким образом, ваш B::j()
работает, поскольку Y
является производным от X
. Что касается компилятора, то вызов типа
X*x = pA->j(); // pA is of type A* but points at a B
в порядке, поскольку он по-прежнему возвращает указатель, который может быть корректно преобразован в X *