Наследование C ++ с интерфейсом и реализацией по умолчанию - PullRequest
0 голосов
/ 04 сентября 2018

Я не совсем уверен, как назвать эту схему наследования, но я пытаюсь использовать интерфейс cloneable с реализацией по умолчанию. У меня проблемы с получением правильной схемы.

Я основываю это на клонируемом интерфейсе, определенном в C #.

Сначала у меня есть интерфейс и реализации по умолчанию:

template<class BaseType>
class ICloneable
{
public:
    virtual std::shared_ptr<BaseType> Clone() const = 0;
};

template<class BaseType, class DerivedType>
class Cloneable : public ICloneable<BaseType>
{
public:
    virtual std::shared_ptr<BaseType> Clone() const
    {
        return std::shared_ptr<BaseType>(new DerivedType(*(DerivedType*)this));
    }
};

Мое желание - иметь следующую схему.

// A pure virtual base interface
class Base : public ICloneable<Base>
{
public:
    virtual void SomeFunc() = 0;
}

// Another implementation
class Imp1 : public Base, Cloneable<Base, Imp1>
{
    public:
        virtual void SomeFunc() {}
}
// An implementation
class Imp2 : public Cloneable<Base, Imp2>
{
    public:
        virtual void SomeFunc() {}
}

Если у меня есть список объектов `std :: shared_ptr ', я могу вызывать функцию Clone, когда я хочу сделать глубокую копию, без необходимости вручную писать функцию в каждой из реализаций.

Прямо сейчас я понимаю, что Imp - это абстрактный класс, который меня не удивляет. Кто-нибудь знает, как заставить эту идею реализации по умолчанию работать? Смысл в том, что не нужно вручную писать функцию клона для каждой из реализаций. Возможно, это не выполнимо, но у меня нет идей, чтобы попробовать.

1 Ответ

0 голосов
/ 04 сентября 2018

Вы можете сделать следующее:

#include <memory>

template<typename InterfaceType_>
struct ICloneable
{
    using InterfaceType = InterfaceType_;

    virtual ~ICloneable() = default;

    virtual std::shared_ptr<InterfaceType> clone() const = 0;
};

template<typename T, typename Base = ICloneable<T>>
struct CloneableMixin : public Base
{
    using InterfaceType = typename Base::InterfaceType;

    // With the following line uncommented, code does not compile in MSVC
    //using typename Base::InterfaceType;

    std::shared_ptr<InterfaceType> clone() const override
    { return std::make_shared<T>(*static_cast<const T*>(this)); }
};

Теперь это можно использовать следующим образом:

struct SomeBaseClass : public CloneableMixin<SomeBaseClass> { /*...*/ };

struct SomeDerivedClass : public CloneableMixin<SomeDerivedClass, SomeBaseClass> { /*...*/ };

Две ноты:

  • Чтобы получить доступ к InterfaceType_ шаблонному параметру ICloneable, необходимо сделать его псевдонимом шаблона, а затем использовать using typename Base::InterfaceType (так как это тип, зависящий от параметра шаблона).

  • Я предоставил тип по умолчанию для Base параметра шаблона CloneableMixin - это позволяет использовать его для базовых классов, для которых вы хотите реализовать clone.

Более того, два несвязанных комментария:

  • Вам не нужно вводить virtual - это подразумевается. Рекомендуется добавить override в конце (это гарантирует, что метод на самом деле что-то переопределяет, иначе компилятор сообщит об ошибке).

  • Вы можете рассмотреть возможность использования std::make_shared вместо new.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...