C ++中的工厂模式:自动生成显式createInstance() - 方法

时间:2011-07-05 11:34:41

标签: c++ design-patterns factory createinstance dlsym

我在编写C ++框架时遇到了问题,用户应该比使用它的开销更少。用户可以通过创建包含类的共享库将其工作发布到框架,该类由框架的BaseClass派生并实现extern“C”createInstance()方法,以便返回实例的派生类。因此,框架可以通过使用dlsym()通过共享库调用createInstance-Method来访问用户类。

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 个答案:

答案 0 :(得分:4)

我无法想象一种自动创建此方法而无需对用户的每个部分进行任何编码的方法。我可以设想简化它的方法,也许使用宏:

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

用户只需要放上他的cpp文件:

OBJECT_CREATOR(UserClass);

答案 1 :(得分:3)

我假设通过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::stringUserObjectFactory的某种(多)地图。

myname可以初始化为一些唯一生成的字符串而不是typeid(UserClass).name(),以避免冲突。

如果您需要的只是每个用户类的单个对象,则可以UserObjectFactory创建UserClass的实例并进行注册。

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

这种设计是否满足您的需求?