想象我有一堆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)
为什么不使用对象工厂?
最简单的形式:
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)