I am experimenting with covariance and came up with the following example that does at least not compile with clang 11 and on VS2015:
class Number {
public:
virtual ~Number () = default;
virtual Number const * increment()const = 0;
};
class Even;
class Odd : public Number {
public:
// error: increment() is not covariant because Even is incomplete
Even const * increment()const;
};
class Even : public Number {
public:
Odd const * increment()const;
};
It is related to Covariant return types, const-ness, and incomplete classes but not a duplicate because the constness is the same in both overwritten functions.
Is that even supported by the standard?
Is there a way to get around this problem or any suggestions to achieve a similar behavior?
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.
Yes. It is possible for overridden methods to have different return type .
Simple example of Covariant Return Type As you can see in the above example, the return type of the get() method of A class is A but the return type of the get() method of B class is B. Both methods have different return type but it is method overriding. This is known as covariant return type.
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++.
While there may be workaround for what you're trying to achieve, the shown code is invalid.
According to class.virtual#9:
If the class type in the covariant return type of D::f differs from that 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. ...
There's an example for this rule in the linked text.
In your case, since the return type of Odd::increment
is not Number
, and Even
is incomplete at the point of declaring Odd::increment
, the code is ill-formed.
I found the answer in this incorrect, and hence deleted answer written by @Brian in response to the question you've linked to.
You can achieve a similar thing with a non-virtual interface (though it has more lines and seems easier to mess up):
class Number {
public:
virtual ~Number() = default;
Number const * increment() const { return do_increment(); }
private:
virtual Number const * do_increment() const = 0;
};
class Even;
class Odd : public Number {
public:
Even const * increment() const;
private:
Number const * do_increment() const override;
};
class Even : public Number {
public:
Odd const * increment() const { return do_increment(); }
private:
Odd const * do_increment() const override;
};
inline Even const * Odd::increment() const {
return static_cast<Even const *>(do_increment());
}
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