В общем случае ковариация позволяет вам выразить больше информации в интерфейсе производного класса, чем в интерфейсе базового класса. Поведение производного класса более специфично, чем поведение базового класса, и ковариация выражает (один из аспектов) разницу.
Это полезно, когда у вас есть связанные иерархии gubbins, в ситуациях, когда некоторые клиенты захотят использовать интерфейс базового класса, но другие клиенты будут использовать интерфейс производного класса. С опущенной константностью:
class URI { /* stuff */ };
class HttpAddress : public URI {
bool hasQueryParam(string);
string &getQueryParam(string);
};
class Resource {
virtual URI &getIdentifier();
};
class WebPage : public Resource {
virtual HttpAddress &getIdentifier();
};
Клиенты, которые знают, что у них есть веб-страница (возможно, браузеры), знают, что имеет смысл смотреть на параметры запроса. Клиенты, использующие базовый класс Resource, не знают об этом. Они всегда будут привязывать возвращенную HttpAddress&
к переменной URI&
или к временной.
Если они подозревают, но не знают, что у их объекта Resource есть HttpAddress, тогда они могут dynamic_cast
. Но ковариация превосходит «просто знать» и выполнять приведение по той же причине, что статическая типизация вообще полезна.
Есть альтернативы - прикрепите функцию getQueryParam
к URI
, но заставьте hasQueryParam
вернуть false для всего (загромождает интерфейс URI). Оставьте WebPage::getIdentifier
определенным, чтобы возвращать URL&
, фактически возвращая HttpIdentifier&
, и заставьте вызывающих абонентов делать бессмысленно dynamic_cast
(загромождает вызывающий код, и документация WebPage, где вы говорите "возвращаемый URL гарантированно будет динамически castable to HttpAddress "). Добавьте функцию getHttpIdentifier
к WebPage
(загромождает интерфейс WebPage
). Или просто используйте ковариацию для того, что он должен делать, что выражается в том факте, что WebPage
не имеет FtpAddress
или MailtoAddress
, он имеет HttpAddress
.
Наконец, есть разумный аргумент, что у вас не должно быть иерархий губбин, не говоря уже о связанных иерархиях губбин. Но эти классы также могут быть интерфейсами с чисто виртуальными методами, поэтому я не думаю, что это влияет на достоверность использования ковариации.