Наследование интерфейса в C ++

У меня есть следующая структура класса:

class InterfaceA
{ 
   virtual void methodA =0;
}

class ClassA : public InterfaceA
{
   void methodA();
}

class InterfaceB : public InterfaceA
{
   virtual void methodB =0;
}

class ClassAB : public ClassA, public InterfaceB
{ 
   void methodB(); 
}

Теперь следующий код не компилируется:

int main()
{
    InterfaceB* test = new ClassAB();
    test->methodA();
}

Компилятор говорит, что методmethodA() является виртуальным и не реализован. Я думал, что это реализовано вClassA (который реализуетInterfaceA). Кто-нибудь знает, где моя вина?

Ответы на вопрос(4)

Эта проблема существует, потому что C ++ неу него действительно есть интерфейсы, только чисто виртуальные классы с множественным наследованием. Компилятор нене знаю, где найти реализациюmethodA() потому что это реализуется другим базовым классомClassAB, Вы можете обойти это путем реализацииmethodA() вClassAB() Для вызова базовой реализации:

class ClassAB : public ClassA, public InterfaceB
{ 
    void methodA()
    {
        ClassA::methodA();
    }

    void methodB(); 
}
 stonemetal12 нояб. 2009 г., 17:37
InterfaceB наследуется от interfaceA, поэтому он должен иметь метод A
 MOnsDaR16 нояб. 2009 г., 07:23
Приведенное выше решение было моим первым подходом к решению проблемы. Это сработало, но с этим было очень плохо справляться. (Если Интерфейс A изменяется, я должен был сделать изменения также в каждом унаследованном классе)
 Michael Myers12 нояб. 2009 г., 17:28
Если С ++правила похожи на Javas, компилятор все еще нене знаю об этом, потому что указатель был объявлен какInterfaceB, который не имеет.methodA
 Michael Myers12 нояб. 2009 г., 17:45
К сожалению, я полностью прочитал этот код неправильно.
 jmucchiello12 нояб. 2009 г., 17:37
ммерс: ЭтоЭто неправильно для C ++ и Java. InterfaceB наследуется от InterfaceA, где определен methodA.

У вас есть страшный алмаз здесь. InterfaceB и ClassA должны фактически наследоваться от InterfaceA. В противном случае у вас в ClassAB есть две копии MethodA, одна из которых все еще является чисто виртуальной. Вы не должны быть в состоянии создать экземпляр этого класса. И даже если бы вы были - компилятор не смог бы решить, какой метод вызывать.

Решение Вопроса

Это потому, что у вас есть две копииInterfaceA, Смотрите это для большего объяснения:https://isocpp.org/wiki/faq/multiple-inheritance (ваша ситуация похожа на 'страшный бриллиант).

Вам нужно добавить ключевое словоvirtual когда вы наследуете ClassA от InterfaceA. Вы также должны добавитьvirtual когда вы наследуете InterfaceB от InterfaceA.

 johnbakers21 мая 2013 г., 11:53
Я думал, что когда-то объявлена функцияvirtual всегда виртуален во всей иерархии классов, используют ли производные классыvirtual или нет при определении
 Daniel Rodriguez12 нояб. 2009 г., 17:40
Спасибо за разъяснения, Лора.

Виртуальное наследование, которое предложила Лора, - это, конечно, решение проблемы. Но это нев конечном итоге иметь только один InterfaceA. Она имеет "побочные эффекты" тоже, например увидетьhttps://isocpp.org/wiki/faq/multiple-inheritance#mi-delegate-to-sister, Но если к этому привыкнуть, это может пригодиться.

Если вы неЕсли вы хотите побочные эффекты, вы можете использовать шаблон:

struct InterfaceA
{ 
  virtual void methodA() = 0;
};

template
struct ClassA : public IA //IA is expected to extend InterfaceA
{
  void methodA() { 5+1;}
};

struct InterfaceB : public InterfaceA
{
  virtual void methodB() = 0;
};

struct ClassAB 
  : public ClassA
{ 
  void methodB() {}
};

int main()
{
  InterfaceB* test = new ClassAB();
  test->methodA();
}

Итак, у нас ровно один родительский класс.

Но выглядит более некрасиво, когда их больше одного »общий" класс (InterfaceA есть "общий", потому что это на вершинестрашный бриллиант ", посмотреть здесьhttps://isocpp.org/wiki/faq/multiple-inheritance как отправлено Лорой). Смотрите пример (что будет, если ClassA также реализует interfaceC):

struct InterfaceC
{
  virtual void methodC() = 0;
};

struct InterfaceD : public InterfaceC
{
  virtual void methodD() = 0;
};

template
struct ClassA
  : public IA //IA is expected to extend InterfaceA
  , public IC //IC is expected to extend InterfaceC
{
  void methodA() { 5+1;}
  void methodC() { 1+2; }
};

struct InterfaceB : public InterfaceA
{
  virtual void methodB() = 0;
};

struct ClassAB
  : public ClassA //we had to modify existing ClassAB!
{ 
  void methodB() {}
};

struct ClassBD //new class, which needs ClassA to implement InterfaceD partially
  : public ClassA
{
  void methodB() {}
  void methodD() {}
};

Плохо то, что вам нужно было модифицировать существующий ClassAB. Но вы можете написать:

template
struct ClassA

Тогда ClassAB остается без изменений:

struct ClassAB 
      : public ClassA

И у вас есть реализация по умолчанию для параметра шаблона IC.

Какой способ использовать - решать вам. Я предпочитаю шаблон, когда его легко понять. Довольно сложно привыкнуть, что B :: incrementAndPrint () и C :: incrementAndPrint () будут печатать разные значения (не ваш пример), смотрите это:

class A
{
public:
  void incrementAndPrint() { cout

Ваш ответ на вопрос