Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: How can I avoid "invalid covariant return type" in inherited classes without casting?

I have a quite complex class hierarchy in which the classes are cross-like depending on each other: There are two abstract classes A and C containing a method that returns an instance of C and A, respectively. In their inherited classes I want to use a co-variant type, which is in this case a problem since I don't know a way to forward-declare the inheritance relation ship.

I obtain a "test.cpp:22: error: invalid covariant return type for ‘virtual D* B::outC()’"-error since the compiler does not know that D is a subclass of C.

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

If I change the return type of B::outC() to C* the example compiles. Is there any way to keep B* and D* as return types in the inherited classes (it would be intuitive to me that there is a way)?

like image 836
Searles Avatar asked Mar 09 '10 16:03

Searles


People also ask

What is the best possible reason to use covariant return type?

1) Covariant return type assists to stay away from the confusing type casts in the class hierarchy and makes the code more usable, readable, and maintainable. 2) In the method overriding, the covariant return type provides the liberty to have more to the point return types.

Is it possible to override co variant return types?

Covariant return type works only for non-primitive return types. From Java 5 onwards, we can override a method by changing its return type only by abiding the condition that return type is a subclass of that of overridden method return type.

What is covariant return type in method overriding?

Covariant Method overriding means that when overriding a method in the child class, the return type may vary. Before java 5 it was not allowed to override any function if the return type is changed in the child class. But now it is possible only return type is subtype class.

Is covariant return types available in C ++ 17?

C++'s classical OOP system supports “covariant return types,” but it does not support “contravariant parameter types.”


2 Answers

I know of no way of having directly coupled covariant members in C++. You'll have either to add a layer, or implement covariant return yourself.

For the first option

class C;

class A {
public:
        virtual C* outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class BI : public A {
public:
};

class D : public C {
public:
        BI* outA();
};

class B: public BI {
public:
        D* outC();
};

D* B::outC() {
        return new D();
}

BI* D::outA() {
        return new B();
}

and for the second

class C;

class A {
public:
        C* outC() { return do_outC(); }
        virtual C* do_outC() = 0;
};

class C {
public:
        virtual A* outA() = 0;
};


class D;

class B : public A {
public:
        D* outC();
        virtual C* do_outC();
};

class D : public C {
public:
        B* outA();
};

D* B::outC() {
        return static_cast<D*>(do_outC());
}

C* B::do_outC() {
        return new D();
}

B* D::outA() {
        return new B();
}

Note that this second option is what is done implicitly by the compiler (with some static checks that the static_cast is valid).

like image 86
AProgrammer Avatar answered Oct 25 '22 18:10

AProgrammer


As far as I know, there's no way to do this without explicit casting. The problem is that the definition of class B can't know that D is a subclass of C until it sees a full definition of class D, but the definition of class D can't know that B is a subclass of A until it sees a full definition of class B, and so you have a circular dependency. This can't be resolved with forward-declarations because a forward declaration unfortunately cannot specify an inheritance relationship.

There's a similar problem with trying to implement a covariant clone() method using templates, which I found can be solved, but the analogous solution still fails here because the circular reference remains impossible to resolve.

like image 33
Tyler McHenry Avatar answered Oct 25 '22 18:10

Tyler McHenry