天天看点

C++反射通过字符串创建类对象

1、前言

    之前一直想通过配置文件如xml,配置一个类名,通过这个类名创建对象,通过基类指针来指向派生类,管理一系列这样对象,继承,这样的可以不修改管理咧,直接添加或修改配置文件来动态创建管理类,非常方便。由于C++没有反射机制,但是可以实现。

2、实现 

(1)为需要反射的类中定义一个创建该类对象的一个回调函数;

(2)设计一个工厂类,类中有一个std::map,用于保存类名和创建实例的回调函数。通过类工厂来动态创建类对象;

(3)RegisterAction类,实际上没什么用,只是在构造函数中把 key,value加入到ClassFactory的map中去,所以需要定义一个对象来执行构造函数,为了简化定义了REGISTER宏

#include <iostream>
#include <string>
#include <map>
using namespace std;
 
 
typedef void* (*PCreateObject)(void);
 
 
class ClassFactory 
{
private:
	map<string, PCreateObject> m_classMap;
	ClassFactory() {};  
 
public:
	void* CreateObjectByName(string className)
	{
		map<string, PCreateObject>::const_iterator iter;
		iter = m_classMap.find(className);
		if (iter == m_classMap.end())
			return NULL;
		else
			return iter->second(); //函数指针的调用
	}
	void registClass(string name, PCreateObject method)
	{
		m_classMap.insert(pair<string, PCreateObject>(name, method));
	}
	static ClassFactory& getInstance()
	{
		{
			static ClassFactory cf;
			return cf;
		}
	} 
};
 

class RegisterAction{
public:
    RegisterAction(string className,PCreateObject ptrCreateFn){
        ClassFactory::getInstance().registClass(className,ptrCreateFn);
    }
};

#define REGISTER(className)                                             \
    className* objectCreator##className(){                              \
        return new className;                                           \
    }                                                                   \
    RegisterAction g_creatorRegister##className(                        \
        #className,(PCreateObject)objectCreator##className)

 
 


class  Base
{
public :
	virtual  void  print() = 0; 
}; 
 
 
class  ClassA :public  Base
{
public:
	void  print()
	{
		cout << "Print  ClassA" << endl;
	}  
 
	
}; 
REGISTER(ClassA);
 
 
class  ClassB :public  Base
{
public:
	void  print()
	{
		cout << "Print  ClassB" << endl;
	}
	
};
REGISTER(ClassB);
 
int main()
{    
	Base  *p = NULL;
	
	 p= (Base *)ClassFactory::getInstance().CreateObjectByName("ClassA");
	 p->print();
 
     p = (Base *)ClassFactory::getInstance().CreateObjectByName("ClassB");
	 p->print();
	 
	 return 0; 
}
           

3、xml配置文件设计和读取

<?xml version="1.0" encoding="UTF-8"?>
 <config> 
    <className>ClassA</className>
    <className>ClassB</className>
 </config>
           

可以使用开源tinyxml来解析获取类名,进而通过工厂类创建对象。

继续阅读