MFC的CRuntimeClass利用链表实现了C++类的动态创建。但是如果项目中对动态创建的要求比较低,我们完全可以利用map实现简单的动态创建。以下三个文件做了一个简单的实现。
/*
* Author: yejingx
* Date: 2011-12-29
* File: base.h
*/
#ifndef BASE_H_
#define BASE_H_
#include "dyncreate.h"
class base
{
public:
typedef base* (*class_creator)(); // 声明类的创建函数指针
static base* create(const std::string& class_name); // 由类名创建类
static std::map class_set; // 保存类名与类创建函数
struct _auto_register // 用于自动注册
{
_auto_register(const std::string& name, base::class_creator creator){
base::class_set.insert(std::pair(name,creator));}
};
public:
base(void);
virtual ~base(void);
virtual void run();
};
#endif
/*
* Author: yejingx
* Date: 2011-12-29
* File: base.cpp
*/
#include
#include "base.h"
std::map base::class_set;
base* base::create(const std::string& class_name) // 动态创建函数实现
{
std::map::iterator it;
it = class_set.find(class_name); // 在map中查找类名
if(it != class_set.end()){
return (it->second)();
}
return NULL;
}
base::base(void){
std::cout<<"base constructor called"<
/*
* Author: yejingx
* Date: 2011-12-29
* File: derived.h
*/
#ifndef DERIVED_H_
#define DERIVED_H_
#include "base.h"
class derived :
public base
{
public:
static base* create(){ // 类创建函数
return (base*)(new derived);
}
public:
derived(void);
virtual ~derived(void);
void run();
};
#endif
/*
* Author: yejingx
* Date: 2011-12-29
* File: derived.cpp
*/
#include
#include "derived.h"
static derived::_auto_register _register_derived("derived",derived::create); // 声明一个静态变量,自动调用它的构造函数对类进行自动注册
derived::derived(void){
std::cout<<"derived constructor called"<
void derived::run(){
std::cout<<"derived class run"<
/*
* Author: yejingx
* Date: 2011-12-29
* File: dyncreate.h
*/
#ifndef DYNCREATE_H_
#define DYNCREATE_H_
#include
/*
* Author: yejingx
* Date: 2011-12-29
* File: base.h
*/
#ifndef BASE_H_
#define BASE_H_
#include "dyncreate.h"
class base
{
DECLARE_DYNBASE(base) // 声明动态创建基类
DECLARE_DYNCREATE(base,base) // 基类也可以动态创建
public:
base(void);
virtual ~base(void);
virtual void run();
};
#endif
/*
* Author: yejingx
* Date: 2011-12-29
* File: base.cpp
*/
#include
#include "base.h"
IMPLEMENT_DYNBASE(base) // 实现动态创建基类
IMPLEMENT_DYNCREATE(base) // 实现基类的动态创建
base::base(void){
std::cout<<"base constructor called"<
/*
* Author: yejingx
* Date: 2011-12-29
* File: derived.h
*/
#ifndef DERIVED_H_
#define DERIVED_H_
#include "base.h"
class derived :
public base
{
DECLARE_DYNCREATE(derived,base) // 声明动态创建子类
public:
derived(void);
virtual ~derived(void);
void run();
};
#endif
/*
* Author: yejingx
* Date: 2011-12-29
* File: derived.cpp
*/
#include
#include "derived.h"
IMPLEMENT_DYNCREATE(derived) // 实现动态创建子类
derived::derived(void){
std::cout<<"derived constructor called"<
这样子不但看起来简洁,使用起来也更加方便。
以上实现还存在一个问题。由于基类中存在静态的class_set成员,子类的cpp文件中也存在静态的_auto_register对像,且两个静成变量分布在不同的文件中。编译器对静态变量的初始化顺序是不确定的。如果静态_auto_register对像的构造函数被自动调用,也就是需要往class_set中添子类的时候,class_set还没有被创建或者初始化,那么就会出现错误。对此的解决办法是将class_set放入一个静态成员函数get_class_set中,以保证第一次调用get_class_set的时候初始化class_set。
/*
* Author: yejingx
* Date: 2011-12-29
* File: dyncreate.h
*/
#ifndef DYNCREATE_H_
#define DYNCREATE_H_
#include
编写测试文件
/*
* Author: yejingx
* Date: 2011-12-29
* File: dyn_test.cpp
*/
#include "derived.h"
int main()
{
base* ptr;
ptr = base::create("derived");
ptr->run();
delete ptr;
ptr = base::create("base");
ptr->run();
delete ptr;
return 0;
}
输出
base constructor called
derived constructor called
derived class run
derived destructor called
base destructor called
base constructor called
base class run
base destructor called
到此,我们已经保证在第一次使用class_set前对其进行创建并初始化,但是仍然存在一个问题。设想,假如我们编写的程序在_auto_register对象初始化前调用了base::create(class_name),这时候的base::class_set是空的,base::create(class_name)就返回一个空指针!有一次我把base, derived等类打包成一个lib,然后写了另外一个文件调用这个lib中的base::create,就出现了上述问题。之后我用了很土的办法临时解决了这个问题,在此不提也罢。
如何确保第一次调用base::create之前_auto_register对象都已经创建?期待高手指点。。。