В C ++, как и в других языках OO, подтипы обычно представлены наследованием.
Однако мы не можем моделировать отношения ковариации и контравариантности посредством наследования, потому что нет способа перечислить базовые классы класса(без каких-либо различных предложений по рефлексии, которые еще не проникли в язык).
Самый простой способ разрешить такой тип поведения - это позволить ковариантным и контравариантным шаблонным классам преобразовывать на основе отношениясвязанных типов.
Ковариация
Если Derived
is-a Base
, то Covariant<Derived>
"should-be-a" Covariant<Base>
.
Обычно решением было бы сделать так, чтобы Covariant<Derived>
наследовал от Covariant<Base>
, но в настоящее время у нас нет способа найти Base
, учитывая только Derived
.Однако мы можем включить преобразование, написав конструктор для Covariant<Base>
, взяв любое Covariant<Derived>
:
template <typename T>
struct Covariant {
template <typename Derived>
Covariant(const Covariant<Derived>& derived,
std::enable_if_t<std::is_base_of_v<T, Derived>>* = nullptr)
{
/* Do your conversion here */
}
};
Контравариантность
Если Derived
is-a Base
, затем Contravariant<Base>
"should-be-a" Contravariant<Derived>
Трюк здесь почти такой же - разрешить преобразование любого *От 1042 * до Contravariant<Derived>
:
template <typename T>
struct Contravariant {
template <typename Base>
Contravariant(const Contravariant<Base>& base,
std::enable_if_t<std::is_base_of_v<Base, T>>* = nullptr)
{
/* Do your conversion here */
}
};
Однако
У этого есть один существенный недостаток: вам нужно реализовать преобразования вручную и помнить, что случайное срезание объекта может разрушить вашу способность к обратному преобразованию (например, если вы определите ковариантный тип контейнера, который будет причиной больших головных болей).
По существу, пока рефлексия не позволит нам автоматизировать такого рода отношения наследования, преобразования будутЕдинственный способ сделать это, и я бы не рекомендовал использовать это для чего-то сложного.Как только вы сохраните объекты вашего T
в ковариантном / контравариантном классах, вы попадете в мир боли.
Вот ссылка Godbolt , чтобы показать, чтоэто работает