从名称实例化类?

puc*_*cio 29 c++ macros class

想象我有一堆C++相关的类(所有扩展相同的基类并提供相同的构造函数),我在一个公共头文件(我包括)中声明,以及它们在其他一些文件中的实现(我编译和链接静态作为我的程序构建的一部分).

我希望能够实例化其中一个传递名称,这是一个必须传递给我的程序的参数(作为命令行或编译宏).

我看到唯一可行的解​​决方案是使用宏:

#ifndef CLASS_NAME
#define CLASS_NAME MyDefaultClassToUse
#endif

BaseClass* o = new CLASS_NAME(param1, param2, ..);
Run Code Online (Sandbox Code Playgroud)

这是唯一有价值的方法吗?

180*_*ION 39

这是一个通常使用注册表模式解决的问题:

这是Registry Pattern描述的情况:

对象需要联系另一个对象,只知道对象的名称或它提供的服务的名称,而不知道如何联系它.提供一个服务,该服务获取对象,服务或角色的名称,并返回一个远程代理,该代理封装了如何联系命名对象的知识.

它是构成面向服务的体系结构(SOA)和OSGi中的服务层的基础的基本发布/查找模型.

通常使用单例对象实现注册表,单例对象在编译时或启动时通知对象的名称以及构造它们的方式.然后,您可以使用它来按需创建对象.

例如:

template<class T>
class Registry
{
    typedef boost::function0<T *> Creator;
    typedef std::map<std::string, Creator> Creators;
    Creators _creators;

  public:
    void register(const std::string &className, const Creator &creator);
    T *create(const std::string &className);
}
Run Code Online (Sandbox Code Playgroud)

您可以注册对象的名称和创建函数,如下所示:

Registry<I> registry;
registry.register("MyClass", &MyClass::Creator);

std::auto_ptr<T> myT(registry.create("MyClass"));
Run Code Online (Sandbox Code Playgroud)

然后,我们可以使用聪明的宏来简化它,以便在编译时完成它.ATL使用CoClasses的注册表模式,可以在运行时按名称创建 - 注册就像使用类似下面的代码一样简单:

OBJECT_ENTRY_AUTO(someClassID, SomeClassName);
Run Code Online (Sandbox Code Playgroud)

这个宏放在你的头文件中,magic使它在COM服务器启动时向单例注册.


xto*_*ofl 10

实现这一点的一种方法是硬编码从类'名称'到工厂函数的映射.模板可以缩短代码.STL可以使编码更容易.

#include "BaseObject.h"
#include "CommonClasses.h"

template< typename T > BaseObject* fCreate( int param1, bool param2 ) {
    return new T( param1, param2 );
}

typedef BaseObject* (*tConstructor)( int param1, bool param2 );
struct Mapping { string classname; tConstructor constructor; 
    pair<string,tConstructor> makepair()const { 
        return make_pair( classname, constructor ); 
    }
} mapping[] = 
{ { "class1", &fCreate<Class1> }
, { "class2", &fCreate<Class2> }
// , ...
};

map< string, constructor > constructors;
transform( mapping, mapping+_countof(mapping), 
    inserter( constructors, constructors.begin() ), 
    mem_fun_ref( &Mapping::makepair ) );
Run Code Online (Sandbox Code Playgroud)

编辑 - 一般要求:)一点点返工,使事情看起来更顺畅(石头自由的信用,他可能不想自己添加答案)

typedef BaseObject* (*tConstructor)( int param1, bool param2 );
struct Mapping { 
    string classname; 
    tConstructor constructor; 

    operator pair<string,tConstructor> () const { 
        return make_pair( classname, constructor ); 
    }
} mapping[] = 
{ { "class1", &fCreate<Class1> }
, { "class2", &fCreate<Class2> }
// , ...
};

static const map< string, constructor > constructors( 
      begin(mapping), end(mapping) ); // added a flavor of C++0x, too.
Run Code Online (Sandbox Code Playgroud)


man*_*ake 5

为什么不使用对象工厂?

最简单的形式:

BaseClass* myFactory(std::string const& classname, params...)
{
    if(classname == "Class1"){
        return new Class1(params...);
    }else if(...){
        return new ...;
    }else{
       //Throw or return null
    }
    return NULL;
}
Run Code Online (Sandbox Code Playgroud)