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() {};
     ^

http://ideone.com/PAgTdX

Я полагаю, что мог бы написать что-то в классе 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 {};

В целом, тип возвращаемого значения не может быть единственным отличием для перегрузки.

Другие вопросы по тегам