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

发布于 2024-11-18 07:19:34 字数 949 浏览 5 评论 0原文

我在编写 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 和适当的名称修改直接调用任何用户类的构造函数。 (我知道配置文件中的任何名称空间+类名)但我认为这不是一个正确的解决方案,特别是构造函数调用与常规函数调用不同......但非常有趣......

i have the problem in writing a C++ framework, that users should have less overhead than possible to use it. Users can publish their work to the frameworks by creating a shared library that contains a class, which is derived by a frameworks' BaseClass and implementing an extern "C" createInstance()-method in order to return an instance its' derived class. So the framework can access the user class by calling the createInstance-Method through the shared library with dlsym().

class BaseClass{}
class UserClass : public BaseClass{}

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

In framework:

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();

My Question: Is it possible to generate the UserXcreateInstance()-method, which is redundant in each user library, so that the user don`t have to think about it?

I thought it would be possible with templates+macros, but I haven't yet found a way to do this...

Another approach, I was thinking is directly call the constructor of any user class via dlsym and appropiate name mangling. (I know any namespace + class name from a config file) But I don`t think this a proper solution, especially a constructor call is not the same as a regular function call... but very interesting...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浮生未歇 2024-11-25 07:19:34

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

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

并且用户只需要放入他的 cpp 文件:

OBJECT_CREATOR(UserClass);

I can't imagine a way to create this automatically without any coding per part of the user. I can imagine ways to simplify it, perhaps using a macro:

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

And the user just need to put on his cpp file:

OBJECT_CREATOR(UserClass);
祁梦 2024-11-25 07:19:34

我假设通过 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);

这个设计能满足您的需求吗?

I'll assume calling the user function via dlsym is not an absolute requirement.

What you want is easy to achieve by using CRTP. A constructor of a static helper object then registers relevant data in a central repository. It should go like this:

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; 
};

Users code is simple:

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

Presumably, the CentralObjectFactory instance contains some kind of (multi)map from std::string to UserObjectFactory.

myname could be initialized to some uniquely generated string instead of typeid(UserClass).name(), in order to avoid collisions.

If all you need is a single object of each user's class, you can make UserObjectFactory create an instance of UserClass and register it instead.

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

Does this design fulfil your needs?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文