Согласно стандарту:
Тип возврата переопределяемой функции должен быть либо идентичным типу возврата переопределенной функции, либо ковариантно классам функций. Если функция D :: f переопределяет функцию B :: f, возвращаемые типы функций ковариантны, если они удовлетворяют следующим критериям:
- оба являются указателями на классы или ссылками на классы
- класс в возвращаемом типе B :: f является тем же классом, что и класс в возвращаемом типе D :: f или, является однозначным прямым или косвенным базовым классом класса в возвращаемом типе D: : f и доступен в D
- и указатели, и ссылки имеют одинаковую квалификацию cv, а тип класса в возвращаемом типе D :: f имеет ту же квалификацию cv, что и квалификационная квалификация cv или меньше, чем тип класса в возвращаемом типе B :: е.
Таким образом, в вашем примере возвращаемые типы не являются ковариантными (они не являются ни указателями, ни ссылками), и, кроме того, Ptr<B>
и Ptr<A>
являются несвязанными типами.
Таким образом, сохранение виртуального foo и возврат Ptr<A>
в A и Ptr<B>
в B невозможно. Если вы можете / хотите отказаться от виртуального, вы можете использовать что-то в соответствии с предложением Джема Калионку или его вариантом.