C++ ковариантная ошибка возвращаемого типа с множественным наследованием
У меня есть код, который эквивалентен этому:
class X {};
class Y {};
template< typename T>
class C {
public:
virtual T * foo() = 0;
};
class A : public C< X> {
public:
X * foo() {};
};
class B : public A {};
class D : public B, public C< Y> {
public:
Y * foo() {}; //this is the only one method I need here. Not A::foo!
};
Я получил это ошибки:
error: invalid covariant return type for 'virtual Y* D::foo()'
Y * foo() {};
^
а также:
error: overriding 'virtual X* A::foo()'
X * foo() {};
^
Я полагаю, что мог бы написать что-то в классе B или D, чтобы предотвратить наследование A:: foo, но я не знаю что. Может быть, есть какая-то функция для переименования имен конфликтов в C++?
PS> Я не могу использовать C++11, только старый добрый C++98.
3 ответа
TL;DR
Переопределение foo
в классе D
, foo
методы не могут быть ковариантными из-за несвязанных X
а также Y
возвращаемые типы. Ни один, не может перегрузить из-за разных типов возврата, но одной и той же подписи
объяснение
Давайте очистим код до меньшего фрагмента с той же проблемой:
class X {};
class Y {};
template<typename T>
class C {
public:
virtual T * foo() = 0;
};
class A : public C<X> {
public:
// Your code:
// X * foo() {}; <---- This method is irrelevant to the problem
// virtual X * foo() {};
// ^^^^^^^^^^^^^^^^^^^^^
// This method declared via inheritance and template
// and implicitly exists in this class, (look at keyword `virtual`)
};
class D : public A, public C<Y> {
public:
/*virtual*/ Y * foo() {}; // `virtual` comes from C<X>
};
Ну класс D
наследует два foo
методы из A
а также C<Y>
, Эти два импортированных метода могут сосуществовать, потому что они происходят от разных родителей и могут вызываться, например, квалифицированными вызовами D d; d.A::foo();
,
Но в этой ситуации проблема проявляется, когда вы пытаетесь переопределить foo
в классе D
:
/*virtual*/ Y * foo() {};
В классе D
есть метод с подписью X * foo()
унаследованный от A
и ты переопределяешь метод Y * foo()
, Эти не могут быть ковариантными, потому что Y
не является производным от X
, С другой стороны, это foo
не может перегрузить другой, потому что возвращаемый тип не является частью сигнатуры функции.
Хорошо прочитать сообщение об ошибке clang:
ошибка: тип возврата виртуальной функции 'foo' не ковариантен с типом возврата функции, которую она переопределяет ('Y *' не является производным от 'X *')
virtual Y * foo() {};
Решение
Лучшее решение - упростить ваш дизайн и избавиться от этих сложных методов наследования, шаблонов и имен!
Вы говорите, что вам не нужно foo
метод, который вы объявляете в C<X>
и внедрить в A
, но так как ваш класс D
также является A
и C<X>
клиенты могут зависеть от доступности этого метода и возврата X
, C++ не поддерживает удаление унаследованных методов AFAIK, и на то есть веская причина, поскольку это нарушит принцип подстановки Лискова.
Если вы удалили или скрыли C<X>::foo
здесь, то экземпляр D
не может быть использован там, где экземпляр A
, B
, или же C<X>
ожидается. Поэтому я боюсь, что здесь нет хорошего решения этой проблемы. Если вы только пытаетесь повторно использовать реализацию из A
или же B
в D
, тогда, возможно, вам следует рассмотреть композицию вместо наследования в этом случае.
Вы можете использовать частное наследство для А.
class B : private A {};
В целом, тип возвращаемого значения не может быть единственным отличием для перегрузки.