Like in the example below, what is allowed, how and why?
class Shape {
public:
//...
virtual Shape *clone() const = 0; // Prototype
//...
};
class Circle : public Shape {
public:
Circle *clone() const;
//...
};
Covariant return type refers to return type of an overriding method. It allows to narrow down return type of an overridden method without any need to cast the type or check the return type. Covariant return type works only for non-primitive return types.
In object-oriented programming, a covariant return type of a method is one that can be replaced by a "narrower" type when the method is overridden in a subclass. A notable language in which this is a fairly common paradigm is C++. C# supports return type covariance as of version 9.0.
How is Covariant return types implemented? Java doesn't allow the return type-based overloading, but JVM always allows return type-based overloading. JVM uses the full signature of a method for lookup/resolution. Full signature means it includes return type in addition to argument types.
C++'s classical OOP system supports “covariant return types,” but it does not support “contravariant parameter types.”
C++ Standard 2003. 10.3.5
The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria:
— both are pointers to classes or references to classes
— the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f
— both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.
If the return type of D::f differs from the return type of B::f, the class type in the return type of D::f shall be complete at the point of declaration of D::f or shall be the class type D. When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function (5.2.2).
Example:
class B {};
class D : private B { friend class Derived; };
struct Base {
virtual B* vf4();
virtual B* vf5();
};
class A;
struct Derived : public Base {
D* vf4(); // OK: returns pointer to derived class
A* vf5(); // error: returns pointer to incomplete class
};
Pff, too long standard quoting.
You can use another type as covariant if (a) it is a pointer/reference (b) it can be casted to the prior return type by mere addition of a constant known at compilation time (c) it is compliant to all constant-volatile qualifiers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With