иерархические интерфейсы и реализации

следующий код работает только если вы раскомментируйте строку

  virtual void FuncA() { ImplA::FuncA(); }

в классе ImplB, иначе я получаю ошибку компилятора:

не удается создать экземпляр абстрактного класса ... FuncA (void)': is abstract

вопрос в том, почему он не получает реализацию для FuncA() от наследуемой ImplA?

class InterfaceA  {
public: 
  virtual void FuncA()=0;
};

class InterfaceB : public InterfaceA {
public: 
  virtual void FuncB()=0;
};

class ImplA : public InterfaceA  {
public: 
  virtual void FuncA() { printf("FuncA()n"); }
};

class ImplB : public ImplA, public InterfaceB {
public: 
  // virtual void FuncA() { ImplA::FuncA(); }
  virtual void FuncB() { printf("FuncB()n"); }
};

{
  ImplB *b = new ImplB();
  InterfaceA *A= b; 
  A->FuncA();
  InterfaceB *B= b;
  B->FuncB();
  B->FuncA();
}

2 ответов


вы попали в экземпляр проблемы "алмаз" в множественном наследовании. Вам нужно будет использовать" виртуальное " наследование (что равносильно добавлению ключевого слова virtual при наследовании)

проблема в том, что ImplB имеет два пути к интерфейсу базового класса. Однако ваше намерение заключается в том, что интерфейсы не обеспечивают никакой реализации. Таким образом, вам нужно указать это компилятору, чтобы он мог унифицировать чистые виртуальные функции.

гораздо лучше объяснение: http://www.cprogramming.com/tutorial/virtual_inheritance.html

Я изменил ваш код, чтобы добавить виртуальный, когда вы наследуете от интерфейсов. Теперь он компилируется, даже с комментариями строки. Также обратите внимание, я думаю, что вам не хватает виртуальных деструкторов, поэтому у вас будут некоторые другие проблемы. Этот код компилируется без раскомментирования FuncA.

#include <cstdio>

class InterfaceA  {
public: 
  virtual void FuncA()=0;
};

class InterfaceB : public virtual InterfaceA {
public: 
  virtual void FuncB()=0;
};

class ImplA : public virtual InterfaceA  {
public: 
  virtual void FuncA() { printf("FuncA()\n"); }
};

class ImplB : public ImplA, public virtual InterfaceB {
public: 
  // virtual void FuncA() { ImplA::FuncA(); }
  virtual void FuncB() { printf("FuncB()\n"); }
};

int main()
{
  ImplB *b = new ImplB();
  InterfaceA *A= b; 
  A->FuncA();
  InterfaceB *B= b;
  B->FuncB();
  B->FuncA();
}

множественное наследование не является "mixins"

вы можете наследовать от нескольких классов, которые имеют методы с одинаковыми именами, но это не делает их одинаковыми.

вещь, которая наследуется от виртуального класса, должна реализовать чистые виртуальные функции своих родителей.

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

Я немного удивлен, что поставив using ImplA::FuncA; в ImplB это не решает, хотя:https://gcc.godbolt.org/