Чистое виртуальное множественное наследование С++?

Мне нужна помощь для реализации, которая использует множественное наследование интерфейсов...

Существует существующий код с интерфейсом, который имеет много функций. Экземпляры создаются с помощью 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 {};

и т.д.