Search code examples
c++multiple-inheritancecrtpcloneablecovariant

Invalid covariant type with CRTP clonable class


I'm trying to implement a Clonable class with the CRTP. However, I need to have abstract class that have a pure virtual clone method, overridden by child classes. To make this happen, I need the clone function to return a covariant return type. I made this code below, and the compiler shout at me this error:

main.cpp:12:5: error: return type of virtual function 'clone' is not covariant with the return type of the function it overrides ('B *' is not derived from 'AbstractClonable *')

The class 'B' seems to be a child class of AbstractClonable, and even by two way! How can I solve this? Thank you very much. I tried with both with clang 3.6 and GCC 4.9.2

struct AbstractClonable {
    virtual AbstractClonable* clone() const = 0;
};

template<typename T>
struct Clonable : virtual AbstractClonable {
    T* clone() const override {
        return new T{*dynamic_cast<const T*>(this)};
    }
};

struct A : virtual AbstractClonable {

};

struct B : A, Clonable<B> {

};

Solution

  • Even if B is indeed derived from Clonable<B>, the problem here is that Clonable<B> construction is not valid, as it defines

    B* clone() const override
    

    which of course is not an override of AbstractClonable::clone(), since the compiler doesn't see B at this point as a child of AbstractClonable. So I believe the issue lays in the fact that the compiler cannot build the Clonable<B> base of B.

    A workaround (but not really the same as what you want) is to define

    Clonable* clone() const override
    

    in Clonable. As you mentioned in the comment, you can also define a free function

    template<typename T> 
    T* clone(const T* object) 
    { 
        return static_cast<T*>(object->clone()); 
    }
    

    Related: Derived curiously recurring templates and covariance