Клон абстрактный базовый класс (без вмешательства в производную) - PullRequest
0 голосов
/ 17 августа 2010

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

Прежде всего, у меня есть абстрактный базовый класс, который пользователи могут реализовать, очевидно упрощенный:

class IStateTransit
{
public:
    bool ConnectionPossible(void) = 0;
}

// A user defines their own class like so
class MyStateTransit : public IStateTransit
{
public:
    bool ConnectionPossible(void){ return true; }
}

Далее я определяю фабричный класс.Пользователи могут зарегистрировать свои собственные объекты транзита состояний и обращаться к ним позже, просто используя выбранный ими строковый идентификатор:

class TransitFactory : public Singleton<TransitFactory>
{
public:
    template<typename T> void RegisterStateTransit(const string& name)
    {
        // If the transit type is not already registered, add it.
        if(transits.find(name) == transits.end())
        {
            transits.insert(pair<string, IStateTransit*>(name, new T()));
        };
    }

    IStateTransit* TransitFactory::GetStateTransit(const string& type) const
    {
        return transits.find(type)->second;
    };

private:
    map<string, IStateTransit*> transits;
}

Теперь проблема (вероятно, очевидно) заключается в том, что всякий раз, когда пользователь запрашивает транзит, вызываяGetStateTransit система в настоящее время продолжает возвращать один и тот же объект - указатель на тот же объект, который есть.Я хочу изменить это.

ПРОБЛЕМА: Как я могу вернуть новый (клон) исходного объекта IStateTransit без необходимости определения пользователем собственного конструктора копирования или виртуальный конструктор .В идеале мне бы хотелось, чтобы метод GetStateTransit мог приводить объект IStateTransit к производному типу, который находится во время выполнения, и возвращать клон этого экземпляра.Самым большим препятствием является то, что я не хочу, чтобы пользователю приходилось реализовывать какие-либо дополнительные (и, вероятно, сложные) методы.

4 часа поиска в Google и попыток ни к чему не привели.Тот, у кого есть ответ, герой!

Ответы [ 3 ]

5 голосов
/ 17 августа 2010

Проблема в том, что у вас нет информации о типе для выполнения клонирования, поскольку у вас есть только указатель на тип базового класса и нет знаний о том, какие производные типы были реализованы и доступны.

Я думаю, что есть причина, по которой 4 часа поиска в Google ничего не показали. Если вы хотите, чтобы IStateTransit был клонируемым, вы должны иметь интерфейс, в котором разработчик производного класса предоставляет своего рода реализацию метода клонирования.

Извините, если это не то, что вы хотели услышать.

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

Base* clone() const
{
    return new MyType(*this);
}

Вы могли бы даже макро-alize это; хотя я бы не стал.

1 голос
/ 18 августа 2010

Если я правильно понимаю проблему, вы не должны вставлять new T -ы в карту, а скорее объекты, которые создают новые T-ы.

struct ICreateTransit
{
    virtual ~ICreateTransit() {}
    virtual IStateTransite* create() const = 0;

};

template <class T>
struct CreateTransit: public ICreateTransit
{
    virtual IStateTransit* create() const { return new T(); }
};

А теперь вставьте:

transits.insert(pair<string, ICreateTransit*>(name, new CreateTransit<T>()));

И получить «копии» с:

return transits.find(type)->second->create(); //hopefully with error handling

Не может быть невозможным изменить StateTransit<T>, поэтому он содержит T, из которого можно делать копии, если по умолчанию это не так.

Я думаю, что общее название для таких методов называется «стирание типов» (производные типы «запоминают» конкретные типы, хотя базовый класс о них не знает).

0 голосов
/ 17 августа 2010

Эта проблема для меня звучит так: шаблон abstract factory может помочь.Используя этот шаблон, клиент библиотеки может определить, как ваша платформа создает свои типы.Клиент может внедрить свой собственный подкласс фабрики в платформу и определить там, какие типы должны быть собраны.

Что вам нужно (дополнительно) Базовый класс для фабрики Как клиент: Получите конкретную фабрику Aспособ внедрения (в качестве клиента) подтипа фабрики в структуру. Вызовите фабричные методы для создания новых типов.

Помогает ли это вам?

...