Алмазное наследование - наследование от абстрактного класса, а также от конкретного класса, в котором реализован разделяемый класс - PullRequest
0 голосов
/ 05 марта 2019

Обратите внимание:

IReferenceCounting - чистый абстрактный класс с методами AddRef и RemoveRef

virtual void AddRef() noexcept = 0;
virtual void RemoveRef() noexcept = 0;

Я не создавал этот класс и не могу его изменить.

Теперь у меня есть другой класс, который я создал, который называется ISoundComponent, который наследуется от IReferenceCounting.Класс ISoundComponent также является абстрактным (для начала он не содержит определения для AddRef или Release).

Поскольку каждый компонент, который наследуется от IReferenceCounting, должен будет реализовывать AddRef и RemoveRef, существует ReferenceCountingImpl, который наследует отIReferenceCounted.Я не создавал этот класс и не могу его изменить.

Наконец, у меня есть еще один класс, который я создал, например SoundDiagnostics, который наследуется от ISoundComponent и ReferenceCountingImpl

Многие из вас уже видели его- У меня проблема с наследованием бриллиантов.Поскольку я не предоставляю свои собственные AddRef и RemoveRef и вместо этого использую ReferenceCountingImpl, мне нужно, чтобы ISoundComponent и ReferenceCountingImpl унаследовали виртуально от IReferenceCounting ... правильно?

К сожалению, я не могу редактировать ReferenceCountingImpl только ISoundComponent.Это связано с тем, что IReferenceCounting и ISoundComponent живут во многих проектах в нашей кодовой базе, а ReferenceCountingImpl живет только в одном проекте (живет тот же проект SoundDiagnostics).Это имеет смысл, поскольку проект может принять решение о том, как он хочет реализовать IReferenceCounting, и мы должны иметь возможность повторно использовать его внутри различных классов в этом проекте.

К сожалению, поскольку я не могу пойти и отредактировать ReferenceCountingImpl, яне может построить это из-за проблемы наследования алмазов (SoundDiagnostics не будет знать, вызывать ли ReferenceCountingImpl :: AddRef или ISoundComponent :: AddRef).

Мне кажется, что я лаю не на том дереве, упускаю что-то очевидное, попадаю в детали виртуального наследования и / или мой дизайн испорчен.Организация кодовой базы должна быть независимой от этой проблемы.Кто-нибудь может дать мне несколько советов о том, как это должно быть спроектировано?Я не думаю, что ReferenceCountingImpl, унаследованное фактически от IReferenceCounting, является решением - например, существуют причины производительности, которые следует учитывать при выполнении этого.

Заинтересованы, чтобы узнать, как справиться с этим.

РЕДАКТИРОВАТЬ:

// available across all projects in code base
class IReferenceCounted
{
    virtual void AddRef() = 0;
    virtual void RemoveRef() = 0;
};

// available across a few select projects in the codebase (ones that wish to use some kind of sound component)
class ISoundComponent : public virtual IReferenceCounted
{
    virtual void Play() const = 0;
};

// available within one specific project, SoundDiagnostics. I cannot modify this
class ReferenceCountedImpl : public IReferenceCounted
{
    void AddRef() override
    {
        m_refcount++;
    }

    void RemoveRef() override
    {
        if (--m_refcount == 0)
        {
            delete this;
        }

    }

    int m_refcount = 0;
};

// available within one specific project, SoundDiagnostics.
class SoundDiagnostics : public ISoundComponent, public ReferenceCountedImpl
{
    void Play() const override
    {
        return;
    }

    void RunDiagnostics()
    {

    }
};

// function within my SoundDiagnostics project
int main()
{
    SoundDiagnostics soundDiagnostics;
    return 0;
}

Попытка скомпилировать это приведет к

объекту абстрактного класса типа "SoundDiagnostics" не разрешено:
чисто виртуальная функция "IReferenceCounting :: AddRef" не имеет переопределителя чисто виртуальногофункция "IReferenceCounting :: RemoveRef" не имеет переопределения

Если ReferenceCountingImpl фактически наследует от IReferenceCounts, этот код успешно компилируется.

1 Ответ

0 голосов
/ 05 марта 2019

Я пытался превратить ваше описание в код.Это работает.

class IReferenceCounting {
public:
    virtual void AddRef() const noexcept = 0;
    virtual void RemoveRef() const noexcept = 0;
};
class IComponentPublicHeader :public virtual IReferenceCounting {};
class ReferenceCountedImpl :public virtual IReferenceCounting {
public:
    void AddRef() const noexcept override {};
    void RemoveRef() const noexcept override {};
};
class MyAmazingClass : IComponentPublicHeader, ReferenceCountedImpl {
    MyAmazingClass() {
        AddRef();// ReferenceCountedImpl::AddRef
    }
};

Обновление: я прочитал ваш фрагмент кода. Если AddRef и RemoveRef общедоступны, вы можете попробовать реализовать свой класс следующим образом.

class SoundDiagnostics : public ISoundComponent, public ReferenceCountedImpl
{
    void Play() const override
    {
        return;
    }
    void AddRef() override
    {
        ReferenceCountedImpl::AddRef();
    }

    void RemoveRef() override
    {
        ReferenceCountedImpl::RemoveRef();
    }
    void RunDiagnostics()
    {

    }
};

Если AddRef и RemoveRefявляется частным, пусть ISoundComponent не наследует IReferenceCounting.

class ISoundComponent
{
    virtual void Play() const = 0;
};
...