Подтвердить что ты не робот

Неоднозначное наследование абстрактных базовых классов:

У меня есть гораздо более сложная структура классов, чем эта, но кипящая проблема до ее сути, это описывает мой сценарий: у меня есть два класса: A и B, которые реализуют чистые виртуальные базовые классы, которые имеют общий предок, и затем третий класс C, который компилирует A и B. Наконец, класс шаблона, который заполняет общие методы в чистой виртуальной базе:

struct I {
  virtual void r()=0;
};

struct A : I {};
struct B : I {};

struct C : A, B {
  void q(){
    r();              // the problem is here.
  }
};

struct D : C {
  virtual void r(){
  }
};

C* c = new D;
c->q();

Моя проблема в том, что я не вижу никакого способа заставить C:: q вызвать r().

void C::q(){
  r();    // is ambiguous
  A::r(); // is pure virtual
  B::r(); // also is pure virtual
  D::r(); // C doesn't know about D
  ((D*)this)->r(); // is dubious and requires C to know about D.
}

Как я могу вызвать метод r() из C, чтобы вызвать правильный виртуальный метод?


Извините, я должен был уточнить, что виртуальное наследование нельзя использовать здесь. Я нашел два решения:

struct C : A, B {
  virtual void r()=0;
  ...

ИЛИ

struct C : A, B {
   using A::r;
   ...

Оба кажутся для того, чтобы все проблемы решались для устранения неоднозначности вызова r().

4b9b3361

Ответ 1

Метод Redeclare r как чистый виртуальный в C:

struct C : A, B {
  void q(){
    r();              // the problem is here.
  }

  virtual void r()=0;
};

Ответ 2

Попробуйте виртуальное наследование

struct A : virtual  I {};
struct B : virtual I {};

Ответ 3

Расскажите компилятору, какая часть иерархии следует:

struct C : A, B {
  void q(){
    A * p = this;
    p->r();              // recent GCC compiles this
  }
};

Ответ 4

Это неоднозначно, потому что компилятор не знает, к какому r() нужно вызвать, тот, который исходит от A или того, что происходит от B.

Простым способом является запись:

static_cast<A*>(this)->r();

или

static_cast<B*>(this)->r();

Но я думаю, что ни один из них не является ответом, который вы ищете. Вы очищаете ситуацию, наследуя через virtual интерфейс I:

struct A : virtual I {};
struct B : virtual I {};

Теперь вы можете позвонить

void C::q() { r(); }

как и следовало ожидать. Простое объяснение этого заключается в том, что с помощью виртуального класса C получает только одну "копию" интерфейса I, а не две. Это устраняет ваш код.

Ответ 5

Вы не перегружали r() в дочерних структурах, поэтому он по-прежнему является чисто виртуальным. у меня нет реализации.