Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Паттерн стратегия - скрыть одну из реализаций


Автор: Tiarwe 17.9.2014, 23:39
Добрый день!

Есть такой вот интерфейс:
Код

//DecoderInterface.h
class DecoderInterface
{
public:
    virtual void Decode() = 0;
};


От него наследуются реализации:
Код

//DecoderA.h
class DecoderA final : public DecoderInterface
{
public:
    virtual void Decode() override {};
};

//DecoderB.h
class DecoderB final : public DecoderInterface
{
public:
    virtual void Decode() override {}
};


Идея следующая: DecoderA был создан изначально программистом и его реализация скрыта от глаз (.h недоступен), DecoderB - добавлен в дальнейшем в процессе работы (.h доступен).

Этим всем делом заведует некий Decoder:
Код

//Decoder.h
class Decoder
{
public:
    template<typename T>
    void Initialize()
    {
        T* lT = new T();
        decoder = lT;
    }

private:
    DecoderInterface* decoder;
};


Соответственно, используется это дело так:
Код

// Main.cpp
int main()
{
    Decoder lDecoder1;
    lDecoder1.Initialize<DecoderA>();

    Decoder lDecoder2;
    lDecoder2.Initialize<DecoderB>();

    return 0;
}


Теперь мне нужно скрыть реализацию DecoderA с глаз:
Код

// Decoder.h
class DecoderA;

class Decoder
{
public:
    template<typename T>
    void Initialize()
    {
        T* lT = new T();
        decoder = lT;
    }

private:
    DecoderInterface* decoder;
};


Соответственно, при компиляции сыпятся ошибки, что для DecoderA не найден конструктор. Делаем специализацию, которую помещаем в .cpp (откуда будет виден DecoderA.h и виден конструктор этого класса):

Код

// Decoder.cpp
template<>
void Decoder::Initialize<DecoderA>()
{
    DecoderA* lDecoder = new DecoderA();
    decoder = lDecoder;
}


Снова ошибки при компиляции. Изменяем код следующим образом:
Код

// Decoder.h
class DecoderA;

class Decoder
{
public:
    template<typename T>
    void Initialize();

private:
    DecoderInterface* decoder;
};

// Decoder.cpp
template<>
void Decoder::Initialize<DecoderA>()
{
    DecoderA* lDecoder = new DecoderA();
    decoder = lDecoder;
}

// Main.cpp
int main()
{
    Decoder lDecoder1;
    lDecoder1.Initialize<DecoderA>();

    return 0;
}


Теперь реализация DecoderA работает, но инициализировать Decoder другими реализациями интерфейса нельзя, т.к. функции Initialize() определена лишь для спецификации DecoderA... Как, а главное можно-ли, заставить шаблон работать со всеми реализациями интерфейса, включая те, что скрыты от глаз разработчика (например DecoderA)?

Автор: Guinness 18.9.2014, 07:00
Цитата(Tiarwe @  18.9.2014,  00:39 Найти цитируемый пост)
 DecoderA был создан изначально программистом и его реализация скрыта от глаз (.h недоступен)

Я себе тяжело эту ситуацию представляю. Зачем и главное как потом с этим классом работать? Обычно интерфейс доступен, и он описывается в .h, а реализация прячется в .cpp. Допустим программист написал какую-то библиотеку, собрал её в виде lib или so. Реализация скрыта, но интейрфейс он в любом случае предоставляет с помощью файлов .h. Короче, я похоже не особо понял, что хочет ТС.
И ещё вопрос, а не проще сделать шаблонным весь класс, а не только функцию Initialize()?

Автор: baldina 18.9.2014, 10:48
явно инстанцируйте шаблон в .cpp
http://ideone.com/3edSvg

Автор: Tiarwe 18.9.2014, 15:07
Цитата(Guinness @ 18.9.2014,  07:00)
Цитата(Tiarwe @  18.9.2014,  00:39 Найти цитируемый пост)
 DecoderA был создан изначально программистом и его реализация скрыта от глаз (.h недоступен)

Я себе тяжело эту ситуацию представляю. Зачем и главное как потом с этим классом работать? Обычно интерфейс доступен, и он описывается в .h, а реализация прячется в .cpp. Допустим программист написал какую-то библиотеку, собрал её в виде lib или so. Реализация скрыта, но интейрфейс он в любом случае предоставляет с помощью файлов .h. Короче, я похоже не особо понял, что хочет ТС.
И ещё вопрос, а не проще сделать шаблонным весь класс, а не только функцию Initialize()?

Объясняю) Есть интерфейс для, например, рендера графики. Его реализации используют всякие OpenGL и DirectX функции. Если их засунуть в сорцы, затем собрать статическую библиотеку, то в дальнейшем, когда создаём какой-то новый проект и хотим рисовать графику, нет нужны таскать с собой хедеры DX, OpenGL и писать по 20 раз к ним пути. Достаточно просто прилинковать библиотеку и выбрать реализацию. Сейчас всё так и работает, но нет возможности указывать с какой именно реализацией мы хотим работать - она выбирается через перечисление, передаваемое в Initialize(). А если мне хочется использовать какую-то ещё новую реализацию, то приходится перегружать эту функцию и передавать в неё указатель.

Добавлено через 13 минут и 35 секунд
Цитата(baldina @ 18.9.2014,  10:48)
явно инстанцируйте шаблон в .cpp
http://ideone.com/3edSvg

Думал, не подходит. Допустим, у нас есть класс A, в котором есть Decoder. Его реализация может выбираться в зависимости от платформы.

Автор: math64 19.9.2014, 08:05
Тогда нужно писать плагин. реализация класса в плагине, интерфейс в заголовке, используемом в основной программе и плагине.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)