шаблон фабрики c ++ - PullRequest
       2

шаблон фабрики c ++

0 голосов
/ 10 ноября 2011

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

Я хотел бы создать систему обработчиков событий с триггером.У меня будет несколько модулей обработчиков.Основная идея заключается в том, что во время инициализации эти модули будут регистрироваться для обработки событий, которые они обрабатывают (зарегистрировать (module, eventItGetsCalledFor)) в списке событий.В случае, если событие инициируется, оно ищется в списке событий, и все перечисленные там модули создаются и запускаются.Для достижения этого все модули имеют интерфейс.

Мои два вопроса:

  1. Поскольку я хочу создавать экземпляры модулей только при фактическом событии, мне нужен любой способхранить указатель на конструктор («виртуальный конструктор»), поскольку, насколько я знаю, нет виртуальных конструкторов, я использую метод Factory, который я хотел бы добавить в интерфейс.Классический подход, о котором я знаю, был бы:

    class myInterface {
    public:
       ...
       static virtual *myInterface builder() = 0; //is static (pure) virtual possible?
    };
    
    class example : public myInterface {
    public:
       ...
       static virtual *myInterface builder() { return new example(); }
    };
    

    Затем мне пришлось бы хранить указатели на функции builder () в списке событий и выполнять функции в случае возникновения события для создания объектов.Мне интересно, есть ли способ написать static virtual *myInterface builder() { return new example(); } для каждого примера модуля.Шаблонный подход будет выглядеть так:

    шаблон статического виртуального * myInterface builder () {return new T ();}

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

    register (eventName, builder ())

    учитывая, что я хотел бы создать только одну функцию статического регистра в каждом модуле, вот так:

    class example: public myInterface {
        static void registerMe {
            register(event1,builder<example>());
            register(event2,builder<example>());
            ...
            register(eventn,builder<example>());
        }
    };
    

    было бы гораздо удобнее, если бы достаточно было вызова типа register(event).я мог бы добавить register(event) к интерфейсу, но я не хочу переписывать функцию регистра для каждого шаблона, который будет читать

    void register(event) { getListForEvent(event).pushBack(builder<example>()); }
    

    (параметр инстанцирования шаблона компоновщика меняется), и сделать его самим шаблономтоже нехорошо, так как это заставляет меня снова и снова писать register<myclass>().

    Так есть ли более убедительный способ?(Во время обдумывания и написания этого я придумал наследовать от шаблонного класса. Если полиморфизм работает с шаблонными классами с различными параметрами создания экземпляров. В противном случае я должен использовать класс Interface, обернуть его в шаблон и наследовать от него)

  2. Второй вопрос: у меня есть разные классы, полученные из моего интерфейсного класса.Однако у них есть члены, которые не определены в интерфейсе.Я хотел бы сохранить указатель на функцию-член, как мне это сделать?Тип должен принимать разные базовые классы, но остальная часть сигнатуры функции одинакова (см. Пример ниже)

    class A : public interface {
         void myFunc()
    };
    
    class A : public interface {
         void yourFunc()
    };
    
    whatType* a = &A::myFunc;
    whatType* b = &B::yourFunc;
    

Ответы [ 2 ]

3 голосов
/ 10 ноября 2011

// возможно ли статическое (чистое) виртуальное?

Нет

CRTP (Любопытно повторяющийся шаблон) на помощь

template <class Derived>
class myInterface {
public:
    ...
    virtual *myInterface builder() = 0; 

    Derived* buildDerived() 
    { 
         return dynamic_cast<Derived*>(builder());
    }

};
1 голос
/ 10 ноября 2011
  1. Статические функции-члены не принимают этот указатель в качестве первого параметра, в то время как это делают нестатические функции-члены, поэтому статическая функция-член может рассматриваться как глобальная функция в определенном пространстве имен. Вот почему вы не можете написать так:

    статический виртуальный * myInterface builder () = 0;

  2. Нет способа определить тип функции подобным образом. Если есть функции в разных классах, но с одинаковой сигнатурой, подумайте, чтобы новый интерфейс унаследовал ваш первый интерфейс и добавьте виртуальных членов в новый интерфейс. Когда вы получите указатель базового интерфейса, используйте dynamic_cast , чтобы получить указатель исходного типа из указателя базового интерфейса, а затем вызовите новую функцию-член. Также вы можете попробовать Boost :: Bind . Это кажется полезным в вашей ситуации.

...