Возврат внутреннего класса из унаследованного класса виртуального шаблона в переполнении стека

Derived<T> наследуется от Base<T>, Derived<T>::m должен вернуть Derived<T>::Inner объект. В чем ошибка, я не понимаю.

Рассмотрим следующий код:

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();

Я получаю следующую ошибку:

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> >]'

1

Решение

Вы пытаетесь переопределить функцию, основанную на типе возвращаемого значения. Класс Base::Inner это не то же самое, что Derived::Innerи поэтому вы не можете переопределить m Метод в базовом классе из производного класса.

m метод в Derived класс должен вернуться Base::Inner, Однако это приведет к нарезка объектов так что вы не можете сделать это напрямую. Вместо этого вы должны либо вернуть ссылку или указатель.

Я предлагаю последнее, используя std::unique_ptr.

Может быть что-то вроде:

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);
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]