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

StackOverflow https://stackoverflow.com/questions/2410532

  •  18-09-2019
  •  | 
  •  

Question

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)?

Was it helpful?

Solution

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).

OTHER TIPS

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.

You can't do this due to client side expectation. When using a C instance, you can't tell which kind of C it is (a D or something else). Thus, if you store the B pointer (resulting from a call to the derived class but you don't know it at compile time) into a A pointer, I'm not sure that all the memory stuff will be right.

When you call a method on a polymorphic type, the runtime environment has to check the dynamic type of the object and it moves pointers to suit to your class hierarchy. I'm not sure that you should rely on covariance. Have a look at this

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top