C++实现反射机制

话不多说,先上段代码的运行结果:

class TestA:public Object
{
	DECLARE_CLASS()
public:
	TestA() {std::cout << "TestA constructor" << std::endl;}
	~TestA(){std::cout << "TestA destructor" << std::endl;}
};

IMPLEMENT_CLASS("testA_interface", TestA)

int main()  
{  
	Object* obj = Object::CreateObject("testA_interface");
    delete obj;
	return 0;  
} 

关键就一个功能——根据字符串创建了类对象

开发中经常会遇到根据不同借口创建不同类实例的情况,一般的做法就是if......else if...else if这样一直判断。比如说接口名是testA_interface,就创建一个TestA对象。如果接口不多还好办,如果接口有成千上万呢?维护起来都难办。那么有没有一种简单的方法?下面慢慢探究。

先说一下一般的思路:

常规的思路就是说建立一个map表,以接口名未key,构造函数为value。但有个问题——我们没办法定义一个构造函数的函数指针!

虽然用map的方法不可行,但这确是一个稚形,以这个为基础,一步一步解决问题(如果是C语言,这里没法用map,其实顶一个结构体就可以了)。

问题一:没法定义构造函数的函数指针

直接从构造函数指针不行,那就加一个中间层,没有什么是不能通过加一层来解决的,如果有,那就加两层。具体的做法就是map中不存构造函数了,而是存另一个类的对象,类的定义如下:

class ClassInfo
{
public:
    ClassInfo(){}
    ClassInfo(const std::string &interface_name, ObjectConstructorFn ctor)
    {
        m_interface_name = interface_name;
        m_object_constructor = ctor;
        Object::Register(this);
    }
    Object *CreateObject()const
    {
        return m_object_constructor ? (*m_object_constructor)() : 0; 
    }
public:
	std::string          m_interface_name;
	ObjectConstructorFn  m_object_constructor;
}; 

明显,我们把接口名跟构造函数聚合到了一个结构里面,ObjectConstructorFn是定义的一个函数指针,指向了每个类的构造函数。其实这个地方我们把原来map中的key和value一起当做value了。由此我们可以定义一个map

std::map<std::string, ClassInfo *> *class_info_map = new std::map<std::string, ClassInfo*>();
在调用的时候只需要find()->CreateObject()就可以了。

问题二:接口类的管理

就算这个问题不放这里我们也知道,各个接口对应的类它们肯定有一个公有的基类,其次这个地方恩把所有类继承一公有基类也方便我们管理。所有最简基类的定义如下:

class Object
{
public:  
    Object(){}
    virtual ~Object(){}
    static void Register(ClassInfo* ci);
    static Object* CreateObject(const std::string &interface_name);
};
关键成员函数有两个,register和createobject,本来是想把这个类设置成单例的,也就是说构造函数应该设为private,但是由于这个类是基类,在创建子类对象的时候会调用基类的构造函数,所以这儿就设成了public,如果createobject来创建对象。而对于register成员函数,它就是根据接口把ClassInfo插入到class_info_map,最简单粗暴的方法就是class_info_map[ci->interface_name] = ci。由前面ClassInfo定义可知,ci已经保存了接口名返回实例的函数。

    问题三:子类的实现

        目前为止其他都可以了,就差子类的实现了,前面说了,ClassInfo标示了一个接口名和接口的对应关系。所以子类需要包含一个ClassInfo的成员变量。定义两个宏:

#define DECLARE_CLASS() \
    protected: \
        static ClassInfo ms_classinfo; \
    public:  \
        static Object* CreateObject();  

#define IMPLEMENT_CLASS(interface_name, class_name)            \
	ClassInfo class_name::ms_classinfo(interface_name,(ObjectConstructorFn)class_name::CreateObject);\
        Object* class_name::CreateObject() \
            { return new class_name;} 
    这两个宏定义了所有子类需要实现的部分,所以只要直接引入这两个宏就可以了,在宏中定义了唯一标示接口名与类对应关系的ms_classinfo变量,此外有实现了返回每一个类型对象的CreateObject函数。

    下面贴一下完整的代码

#include <iostream>
#include <string>
#include <map>
using namespace std;

#define DECLARE_CLASS() \
    protected: \
        static ClassInfo ms_classinfo; \
    public:  \
        static Object* CreateObject();  

#define IMPLEMENT_CLASS(interface_name, class_name)            \
	ClassInfo class_name::ms_classinfo(interface_name,(ObjectConstructorFn)class_name::CreateObject);\
    Object* class_name::CreateObject() \
        { return new class_name;} 

class ClassInfo;
class Object;
typedef Object* (*ObjectConstructorFn)();

class Object  
{ 
protected:
    Object(){}
public:  
    virtual ~Object(){}
    static void Register(ClassInfo* ci);         
    static Object* CreateObject(std::string name);     
    static std::map<std::string, ClassInfo *> *classInfoMap;
};  

class ClassInfo  
{  
public:  
	ClassInfo(const std::string className, ObjectConstructorFn ctor);
	ClassInfo();
	Object *CreateObject()const;

public:  
	std::string m_className;
	ObjectConstructorFn m_objectConstructor;
}; 

std::map<std::string, ClassInfo *> *Object::classInfoMap = new std::map<std::string, ClassInfo*>();

void Object::Register(ClassInfo* ci)  
{   
	if (NULL != ci && classInfoMap->find(ci->m_className) == classInfoMap->end())
	{  
		classInfoMap->insert(std::map<std::string, ClassInfo*>::value_type(ci->m_className, ci)); 
	}  
}

Object* Object::CreateObject(std::string name)  
{
	std::map<std::string, ClassInfo*>::const_iterator iter = classInfoMap->find(name);  
	if (iter != classInfoMap->end())
	{
		return iter->second->CreateObject();
	}
	return NULL;  
}  

ClassInfo::ClassInfo(const std::string className, ObjectConstructorFn ctor):m_className(className), m_objectConstructor(ctor)  
{  
	Object::Register(this);
}

ClassInfo::ClassInfo()
{
}

Object *ClassInfo::CreateObject()const 
{ 
	return m_objectConstructor ? (*m_objectConstructor)() : 0; 
}

class Test:public Object
{
        DECLARE_CLASS()
public:
        Test(){cout << "Test constructor" << endl;}
        ~Test(){cout << "Test destructor" << endl;}
};

IMPLEMENT_CLASS("xxxx", Test)

int main()  
{
    Object* obj = Object::CreateObject("xxxx");
    delete obj;
    return 0;  
}  
   熟悉MFC的同学应该知道,MFC中有一个BEGIN_MESSAGE_MAP,它也是实现了不同消息ID与不同处理函数的映射,实现原理和这个类似。


    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值