利用map动态创建C++类对象

          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 
#include 

#define DECLARE_DYNBASE(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));}};

#define IMPLEMENT_DYNBASE(base) \
	std::map base::class_set; \
	base* base::create(const std::string& class_name){ \
		std::map::iterator it; \
		it = class_set.find(class_name); \
		if(it != class_set.end()){ \
			return (it->second)();} \
		return NULL; }

#define	DECLARE_DYNCREATE(derived,base) \
public: \
	static base* create(){ \
		return (base*)(new derived); }

#define IMPLEMENT_DYNCREATE(derived) \
	static derived::_auto_register _register_##derived(#derived,derived::create); 

#endif

有了这些宏,base.h,  base.cpp, derived.h和derived.cpp就可以变成以下这样子。

/*
* 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 
#include 

#define DECLARE_DYNBASE(base)	\
public: \
	typedef base* (*class_creator)(); \
	static base* create(const std::string& class_name); \
	static std::map& get_class_set(){ \
		static std::map class_set; \
		return class_set;} \
	struct _auto_register { \
		_auto_register(const std::string& name, base::class_creator creator){ \
		base::get_class_set().insert(std::pair(name,creator));}};

#define IMPLEMENT_DYNBASE(base) \
	base* base::create(const std::string& class_name){ \
		std::map::iterator it; \
		it = get_class_set().find(class_name); \
		if(it != get_class_set().end()){ \
			return (it->second)();} \
		return NULL; }

#define	DECLARE_DYNCREATE(derived,base) \
public: \
	static base* create(){ \
		return (base*)(new derived); }

#define IMPLEMENT_DYNCREATE(derived) \
	static derived::_auto_register _register_##derived(#derived,derived::create); 

#endif

       编写测试文件

/*
* 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对象都已经创建?期待高手指点。。。





你可能感兴趣的:(C++)