Domanda

Derived<T> inherits from Base<T>. Derived<T>::m should return an Derived<T>::Inner object. Whats the mistake, I don't get it.

Consider the following code:

template <typename T>
class Base {
public:
    class Inner {
    public:
        virtual void x() = 0;
    };
    virtual Inner m(std::string arg) = 0;
};

template <typename U>
class Derived : Base<U> {
public:

    class Inner : Base<U>::Inner {
    public:
        virtual void x();
    };
    virtual Inner m(std::string arg);
};

template <typename U>
Derived<U>::Inner Derived<U>::m(std::string arg) {
    std::cout << "calling Derived::m() " << arg << std::endl;
    return new Inner();
}

template <typename U>
void Derived<U>::Inner::x() {
    std::cout << "calling x" << std::endl;
}

Derived<std::string>* d = new Derived<std::string>();
Derived<std::string>::Inner* inner = d->m("test");
inner->x();

I get the following error:

invalid covariant return type for 
   'Derived<U>::Inner Derived<U>::m(std::string) [with U = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]'
overriding 'Base<T>::Inner Base<T>::m(std::string) [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]'
È stato utile?

Soluzione

You try to override a function based on return type. The class Base::Inner is not the same as Derived::Inner, and so you can't override the m method in the base class from the derived class.

The m method in the Derived class needs to return Base::Inner. However, that will lead to object slicing so you can't do that directly. Instead you either have to return a reference or a pointer.

I suggest the latter, by using std::unique_ptr.

Maybe something like:

template<typename U>
class Base
{
public:
    class Inner { ... };

    using inner_ptr = std::unique_ptr<Base<U>::Inner>;

    virtual inner_ptr m(const std::string&) = 0;
};

template<typename U>
class Derived : public Base<U>
{
public:
    Base<U>::inner_ptr m(const std::string&);

    class LocalInner : public Base<U>::Inner { ... };
};

template<typename U>
inline Base<U>::inner_ptr m(const std::string& arg)
{
    return Base<U>::inner_ptr(new LocalInner);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top