Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ crosswise covariant: return type differs due to incomplete type

Tags:

c++

covariance

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?

like image 605
Myon Avatar asked Nov 09 '20 14:11

Myon


People also ask

What is covariant return type Mcq?

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.

Can we have different return type in method overriding?

Yes. It is possible for overridden methods to have different return type .

What is the covariant return type explain with an example?

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.

What do you understand by 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++.


2 Answers

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.

like image 187
cigien Avatar answered Sep 19 '22 21:09

cigien


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());
}
like image 27
Artyer Avatar answered Sep 23 '22 21:09

Artyer