Чистое виртуальное множественное наследование С++?
Мне нужна помощь для реализации, которая использует множественное наследование интерфейсов...
Существует существующий код с интерфейсом, который имеет много функций. Экземпляры создаются с помощью factory.
class IBig
{
// Lot of pure virtual functions
};
И его реализация:
class CBig: public IBig
{
// Implementation
}
Я хочу разделить интерфейс на несколько меньших интерфейсов, но он должен оставаться совместимым с существующим кодом в течение некоторого времени.
Вот пример того, что я пытался сделать:
class IBaseA
{
public:
virtual void DoA() = 0;
};
class IBaseB
{
public:
virtual void DoB() = 0;
};
// The same interface, now based on multiple smaller interfaces
class IBig : public IBaseA, public IBaseB
{
};
class CBaseA: public IBaseA
{
public:
virtual void DoA()
{
printf("DoA\n");
}
};
class CBaseB: public IBaseB
{
public:
virtual void DoB()
{
printf("DoB\n");
}
};
// Inherit from base classes where the implementation is, and from IBig as
// the instance of CBig is returned as IBig.
class CBig: public CBaseA, public CBaseB, public IBig
{
};
Проблема заключается в том, что класс CBig не может быть обусловлен. Компилятор говорит, что функции DoA и DoB являются чистыми виртуальными, даже если они реализованы в CBaseA и CBaseB. Что делать, если я не хочу снова реализовать функции, просто чтобы вызвать функцию базового класса?
NB: Я знаю, что дизайн уродлив, но это временно, пока большой интерфейс не может быть заменен, и... Я хочу понять!; -)
Спасибо заранее!
Ответы
Ответ 1
Здесь вы должны использовать виртуальное наследование. Эта функция гарантирует, что при создании экземпляра подкласса существует только один экземпляр вашего фактически унаследованного базового класса. Для вашего примера это будет выглядеть так:
#include <cstdio>
class IBaseA
{
public:
virtual void DoA() = 0;
};
class IBaseB
{
public:
virtual void DoB() = 0;
};
// The same interface, now based on multiple smaller interfaces
class IBig : virtual public IBaseA, virtual public IBaseB
// ^ ^
{
};
class CBaseA: virtual public IBaseA
// ^
{
public:
virtual void DoA()
{
printf("DoA\n");
}
};
class CBaseB: virtual public IBaseB
// ^
{
public:
virtual void DoB()
{
printf("DoB\n");
}
};
// Inherit from base classes where the implementation is, and from IBig as
// the instance of CBig is returned as IBig.
class CBig: public CBaseA, public CBaseB, public IBig
{
};
int main()
{
CBig cb;
}
Вышеуказанные изменения гарантируют, что нет дополнительных объявлений DoA
и DoB
, созданных при наследовании от IBaseA
и IBaseB
несколько раз.
Ответ 2
Это известно как смертельный бриллиант смерти (или просто проблема с алмазом). Это происходит потому, что CBig наследуется от классов, которые имеют общие базовые классы.
Вы можете либо вызвать правильный DoA, префикс его классом, который принадлежит
CBaseA::doA();
или вы используете виртуальное наследование только для одного экземпляра IBaseA и IBaseB
class CBaseA : public virtual IBaseA {};
class CBaseB : public virtual IBaseB {};
class IBig : public virtual IBaseA, public virtual IBaseB {};
и т.д.