Фабричный шаблон в C ++: генерация явного createInstance () - PullRequest
1 голос
/ 05 июля 2011

У меня есть проблема при написании фреймворка C ++, что пользователи должны иметь меньше накладных расходов, чем это возможно. Пользователи могут публиковать свои работы в каркасах, создав общую библиотеку, которая содержит класс, производный от BaseClass платформ, и реализовав метод exIn createInstance () extern для возврата экземпляру его производного класса. Таким образом, инфраструктура может получить доступ к пользовательскому классу, вызвав метод createInstance через общую библиотеку с помощью dlsym ().

class BaseClass{}
class UserClass : public BaseClass{}

extern "C"{  
   BaseClass* UserXcreateInstance(){
    return new UserClass();
   }                        
}

В рамках:

typedef BaseClass* (*CreateInstance) ();
void* handle;
CreateInstance createInstance;
handle = dlopen( "libUserLibrary.so", RTLD_LAZY | RTLD_GLOBAL );
createInstance = reinterpret_cast <CreateInstance*> dlsym( handle, "UserXcreateInstance" );
BaseClass* userX = createInstance();

Мой вопрос: возможно ли сгенерировать метод UserXcreateInstance (), который является избыточным в каждой пользовательской библиотеке, чтобы пользователю не приходилось об этом думать?

Я думал, что это будет возможно с помощью шаблонов + макросов, но я пока не нашел способа сделать это ...

Другой подход, о котором я подумал, - это напрямую вызывать конструктор любого пользовательского класса через dlsym и подбирать подходящие имена. (Я знаю любое пространство имен + имя класса из файла конфигурации) Но я не думаю, что это правильное решение, особенно вызов конструктора - это не то же самое, что обычный вызов функции ... но очень интересно ...

Ответы [ 2 ]

4 голосов
/ 05 июля 2011

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

#define OBJECT_CREATOR(X) \
    extern "C" {          \
         BaseClass *UserXCreateInstance() {\
             return new X(); \
         }\
    }

А пользователю просто нужно поставить свой файл cpp:

OBJECT_CREATOR(UserClass);
3 голосов
/ 05 июля 2011

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

То, что вы хотите, легко достичь с помощью CRTP . Затем конструктор статического вспомогательного объекта регистрирует соответствующие данные в центральном хранилище. Это должно идти так:

template <typename UserClass>
class BaseClass
{
  private:
    class UserObjectFactory
    {
      UserObjectFactory()
      {
        std::string myname = typeid(UserClass).name();
        CentralObjectFactory::instance()->register(this, myname);
      }
      BaseClass* XUserCreateInstance()
      {
        return new UserClass;
      }            
    };
    static UserObjectFactory factory; 
};

Пользовательский код прост:

class MyClass : public BaseClass<MyClass>
{
  // whatever
};

Предположительно, экземпляр CentralObjectFactory содержит какую-то (мульти) карту от std::string до UserObjectFactory.

myname может быть инициализирован для некоторой уникально сгенерированной строки вместо typeid(UserClass).name(), чтобы избежать коллизий.

Если все, что вам нужно, это отдельный объект каждого класса пользователя, вы можете UserObjectFactory создать экземпляр UserClass и зарегистрировать его вместо этого.

   std::string myname = typeid(UserClass).name();
   CentralObjectRepository::instance()->register(XUserCreateInstance(), myname);

Соответствует ли этот дизайн вашим потребностям?

...