Я бы предложил что-то другое. Объявите функцию как чисто виртуальную функцию, а затем просто тривиально реализуйте ее в производных классах, перенаправив вызов:
class A {
public:
virtual void foo() = 0;
};
void A::foo() {}
class B : public A {
void foo() { A::foo(); }
};
Но это не значит, что вы не можете достичь того, что пытаетесь сделать. Если вы хотите реализовать эту операцию в другом классе и использовать наследование, вы можете сделать это двумя различными способами:
Промежуточный тип:
Реализуйте промежуточный тип, который обеспечивает функциональность, тогда каждый производный тип может расширять либо исходный A
, либо промежуточный I
тип:
class I : public A {
public:
void foo() {}
};
class B : public I {}; // inherits the implementation
class C : public A { // needs to provide it's own implementation
void foo() {}
};
Виртуальное наследование:
В качестве альтернативы вы можете использовать виртуальное наследование (из трех вариантов я бы избежал этого). Таким образом, вы можете создать иерархию, в которой V
фактически наследует от A
и обеспечивает реализацию. Остальные классы могут либо наследоваться от A
напрямую, либо виртуально наследоваться от A
, а также наследоваться от V
. Используя виртуальное наследование, вы гарантируете, что в вашей иерархии есть единственный подобъект A
:
class V : public virtual A {
public:
void foo() {}
};
class B : public virtual A, V { // Inheritance from V is a detail, can be private
// no need to provide foo
};
Обратите внимание, что этот подход является избыточным для этой конкретной ограниченной проблемы, и что у него есть побочные эффекты (расположение объектов будет другим, и они будут немного больше по размеру). Опять же, если вы не хотите смешивать и сопоставлять функции из разных классов sibling , я бы избегал этого.
Что не так в вашем коде
Проблема в вашем коде заключается в том, что вы наследуете от A
несколько раз, от одного до D
и от другого напрямую. В то время как в пути из D
виртуальная функция более не является чистой, в прямом пути из A
виртуальная функция все еще не определена.
Это также вызывает вторую проблему в сообщении об ошибке: неоднозначность. Поскольку существует два подобъекта A
, при попытке вызвать foo
для самого производного типа компилятор не может определить, для какого из двух подобъектов A
вы хотите выполнить запрос. Подобные проблемы неоднозначности возникнут, если вы попытаетесь преобразовать самый производный тип в A
напрямую, так как компилятор не будет знать, к какому A
вы хотите обратиться.