简单来说,本文实现了在C++中由类名字符串动态创建对象的功能。
设计目的
实现C++对象的动态绑定。
开发项目时,我们有需要将类名信息放在配置文件中,以在运行时,依据读取的类名信息实现对应对象的创建,从而提高程序功能和配置的灵活性。
C++提供了动态绑定特性,但貌似没有提供现成的根据类名进行动态绑定的接口(也多半是我读书太少没发现)。在MFC10中,使用CRuntimeClass以及配套的信息提供了此功能,但对问题领域的实现来说,多半不应该需要MFC,而是基于C++来形成多IDE开发或跨平台的实现方案。
此外,本文也算是对单件模式进行一个示例。
设计方案
在程序初始化时,使用双构造方式完成类名信息与类创建操作的关联与保存,双构造保证单件模式的对象工厂类——CObjectFactory的静态对象总是先于为其他被收集类而定义的全局结构对象被创建,从而保证实现类信息收集。
借鉴MFC的设计方式,定义了一对声明与实现宏:DECLARE_CORE_DYNCREATE和IMPLEMENTE_CORE_DYNCREATE。DECLARE_CORE_DYNCREATE完成类的静态创建操作的声明,IMPLEMENTE_CORE_DYNCREATE完成类名信息的收集与类的静态创建操作的定义。
使用方法
将源程序(源程序是个.h文件)包含到目标工程中后,在需要动态绑定的类的声明中,包含DECLARE_CORE_DYNCREATE,对应类的实现文件中包含IMPLEMENTE_CORE_DYNCREATE,这样,便为此类提供了依据其类名字符串信息创建对应类对象的能力。
从某处读取到类名后,使用CObjectFactory::createObject方法,将类名作为其参数,便可返回创建好的类对象指针。
最后,用完对象后,记得释放资源。释放资源操作由用户来完成,本动态绑定设计并未实现。
使用方法真的很简单,懒得贴demo了。
//coreDynCreate.h源程序
#ifndef _H_COREDYNCREATE_332A5F22_79B2_440B_A57B_A88F8D654010
#define _H_COREDYNCREATE_332A5F22_79B2_440B_A57B_A88F8D654010
#pragma warning(disable:4786)
#include <map>
#include <string>
class CObjectFactory
{
public:
typedef void* (*PCreateObject)();
protected:
std::map<std::string, PCreateObject> m_mapClassInfo;
protected:
CObjectFactory() {}
public:
static CObjectFactory* getInstance()
{
static CObjectFactory obj;
return &obj;
}
public:
void addClassInfo(std::string strClassName, PCreateObject pCreateObj)
{
m_mapClassInfo[strClassName] = pCreateObj;
}
void* createObject(std::string strClassName)
{
std::map<std::string, PCreateObject>::const_iterator it = m_mapClassInfo.find(strClassName);
if (it != m_mapClassInfo.end())
{
PCreateObject pObj = (PCreateObject)((*it).second);
if (pObj)
return pObj();
}
return 0;
}
};
struct tClassInfo
{
tClassInfo(std::string strClassName, CObjectFactory::PCreateObject pCreateObj)
{
CObjectFactory::getInstance()->addClassInfo(strClassName, pCreateObj);
}
};
#define DECLARE_CORE_DYNCREATE(classname) \
public: \
static void* createObject();
#define IMPLEMENTE_CORE_DYNCREATE(classname) \
void* classname::createObject() { return (void*)(new classname); } \
tClassInfo _init##classname(#classname, classname::createObject);
#endif //_H_COREDYNCREATE_332A5F22_79B2_440B_A57B_A88F8D654010