Необработанные указатели функций совместимы только по присваиванию, когда типы точно совпадают.
Однако вы можете использовать std::function
:
#include <functional>
struct Base{};
struct Derived: Base{};
auto f1( Derived* ) -> Base* { return 0; }
auto f2( Derived* ) -> Derived* { return 0; } // covariant
auto f3( Base* ) -> Base* { return 0; } // contravariant
auto f4( Base* ) -> Derived* { return 0; } // covariant & contravariant
auto main()
-> int
{
using Callback = std::function<auto( Derived* ) -> Base*>;
Callback pfunc1 = f1; // works
Callback pfunc2 = f2; // works
Callback pfunc3 = f3; // works
Callback pfunc4 = f4; // works
}
Правила для переопределения виртуальных функций менее строгие:ковариантные результаты необработанного указателя и ссылочного типа поддерживаются, но это все.Нет различий.
#include <functional>
struct Base{};
struct Derived: Base{};
struct F{ virtual auto f( Derived* ) -> Base* = 0; };
#define R override { return 0; }
struct F1: F { auto f( Derived* ) -> Base* R };
struct F2: F { auto f( Derived* ) -> Derived* R }; // covariant, OK
struct F3: F { auto f( Base* ) -> Base* R }; // !contravariant
struct F4: F { auto f( Base* ) -> Derived* R }; // !covariant & contravariant
Результат компиляции с MinGW g ++ 7.3.0:
> g++ -c 2.cpp
2.cpp:11:21: error: 'Base* F3::f(Base*)' marked 'override', but does not override
struct F3: F { auto f( Base* ) -> Base* R }; // !contravariant
^
2.cpp:12:21: error: 'Derived* F4::f(Base*)' marked 'override', but does not override
struct F4: F { auto f( Base* ) -> Derived* R }; // !covariant & contravariant
Ограничение необработанных указателей и ссылочных типов результатов для ковариации не является проблемой на практике,Например, очевидно ковариантная функция с результатом интеллектуального указателя может быть легко выражена как не виртуальная перегрузка, вызывающая виртуальную функцию с результатом необработанного указателя.Отсутствие поддержки противоречивости также не является проблемой на практике, но по той простой причине, что она никогда не нужна.