music unfamous original game design efficient software wtf
life ui algorithm fix programming

c++ reflection

作者:trinity  C/C++    2015-8-19  标签:  programming 

一,什么是 reflection(反射)

    C#,Java 程序员对这个肯定不陌生。看看维基百科的解释

    简而言之,反射的意义就是程序中的调用不再是硬编码。

二,已知C++支持反射的 Library

    XCppRefl

    OpenC++

    xrtti

    都没用过,因为我也是刚刚找到的。目测第一个会好用点)

三,C++中,手动实现简单的反射框架

    直白点说,反射就是通过字符串格式的函数名去调用函数,比如,有一个函数

void func(int param){ return 0;}

可以这么调用

call("func",2);

C++的类型系统决定这必须做一个映射表才能实现(到底有没其他途径呢),通过某个类似“工厂”的设施来根据字符串完成查找,然后调用函数。大体思路是这样,但实际上要稍微复杂一点。如果刨除C++中C 的部分不说,只说 class ,当然是语法层面的 class,那么可能会需要一个基类,能够支持反射的类继承自这个基类。

现在,这是基类的声明代码:

#ifndef REFLECTABLE_H
#define REFLECTABLE_H

#include <string>
#include <vector>
#include <map>

//type convertion
template <typename dest_type,typename src_type>
dest_type union_cast(src_type a)
{
	union ui_cvt{
		dest_type dt;
		src_type st;
	}ui;
	ui.st = a;
	return ui.dt;
}

class CReflectorFactory;
class CReflectable;

// virtual base class
class CReflectable
{
public:
	CReflectable(void);
	~CReflectable(void);

	virtual bool RegisterMemberFun()=0;
	virtual int CallMemFun(std::string name,int param)=0;
	void GetSupport(std::vector<std::string>& funs);

protected:
	typedef std::map<std::string,long> MAPRFOR;
	typedef MAPRFOR::iterator MAPRFOR_IT;
	MAPRFOR m_mem_funs;
};

#define DECLARE_REFLECT(class_name) static bool m_auto;\
	public:\
	static CReflectable* CreateInstance(){ return new class_name();}\
	bool RegisterMemberFun()\
	{\
		long addr = 0;
#define ADD_MEMBER_FUN(name,fun_addr) addr = union_cast<long>(fun_addr);\
	m_mem_funs.insert(std::make_pair<std::string,long>(name,addr));

#define DECLARE_REFLECT_END() return true;\
	}\
	int CallMemFun(std::string name,int param);


#define IMPLEMENT_REFLECT(class_name) bool class_name::m_auto = \
	CReflectorFactory::GetInstance()->Register(#class_name,class_name::CreateInstance);\
	int class_name::CallMemFun(std::string name,int param)\
	{\
		MAPRFOR_IT it = m_mem_funs.find(name);\
		if( it != m_mem_funs.end()){\
			typedef int (class_name::*Fun)(int);\
			Fun f = union_cast<Fun>(it->second);\
			return (this->*f)(param);\
		}else{\
			return 0xfe;\
		}\
	}
#endif

实际上,上面的宏可以更复杂一些,逻辑才会更清晰,我是懒省事了。

我也不喜欢用宏,除了这次,用宏会在以后让代码更简单一点,虽然可读性会差一些。CPP文件很简单

#include "Reflactable.h"

CReflectable::CReflectable(void)
{
}

CReflectable::~CReflectable(void)
{
}
void CReflectable::GetSupport(std::vector<std::string>& funs)
{
	MAPRFOR_IT it = m_mem_funs.begin();
	for(; it != m_mem_funs.end(); it++){
		funs.push_back(it->first);
	}
}

这是工厂类的代码:

#ifndef RELECTOR_FACTORY_H
#define RELECTOR_FACTORY_H

#include "Reflactable.h"

//Singleton simplify
#define DECLARE_SINGLETON(class_name) private:\
	static class_name* m_inst;\
	class_name(){}\
public:\
	virtual ~class_name(){}\
	static class_name* GetInstance(){\
	if(!m_inst)\
	m_inst = new class_name();\
	return m_inst;\
	}

#define IMPLEMENT_SINGLETON(class_name) class_name* class_name::m_inst;


typedef CReflectable * (*CreateFun)();

class CReflectorFactory
{
	DECLARE_SINGLETON(CReflectorFactory)
public:
	bool Register(std::string name,CreateFun fun);
	CReflectable* GetObjectByName(std::string name);
protected:
	typedef std::map<std::string,CreateFun> MAPRF;
	typedef MAPRF::iterator MAPRF_IT;
	MAPRF m_objs;
};

#endif
CPP文件
#include "ReflectorFactory.h"

IMPLEMENT_SINGLETON(CReflectorFactory)
bool CReflectorFactory::Register(std::string name,CreateFun fun)
{
	std::pair<MAPRF_IT,bool> ret = m_objs.insert(make_pair(name,fun));
	return ret.second;
}
CReflectable* CReflectorFactory::GetObjectByName(std::string name)
{
	std::map<std::string,CreateFun>::const_iterator it = m_objs.find(name);
	if(it == m_objs.end())
		return 0;
	return it->second();
}

使用示例:

struct student_t{
	int id;
	char name[32];
};
class CTest:public CReflectable{
	DECLARE_REFLECT(CTest)
	ADD_MEMBER_FUN("Hello",&CTest::Hello);
	ADD_MEMBER_FUN("SetStr",&CTest::SetStr);
	ADD_MEMBER_FUN("SetInfo",&CTest::SetInfo);
	DECLARE_REFLECT_END();

	int Hello(int param){
		TCHAR tmp[8]={0};
		wsprintf (tmp,L"%d",param);
		MessageBox(0,tmp,L"",MB_OK);
		return 0;
	}
	int SetStr(int addr){
		char* str = (char*)addr;
		strcpy_s(m_str,64,str);
		return 0;
	}
	int SetInfo(int astudent){
		student_t* stu =(student_t*)astudent;
		if(stu)
			memcpy(&m_stu,stu,sizeof(student_t));
		return 0;
	}

	char m_str[64];
	student_t m_stu;
};

int main(){
        CReflectable* t = CReflectorFactory::GetInstance()->GetObjectByName("CTest");
	if(!t){
		return;
	}
	// add member functions to map list
	t->RegisterMemberFun();
	// get function in string format
	std::vector<std::string> funs;
	t->GetSupport(funs);
	//// call
	//Hello(1)
	int a = t->CallMemFun(funs[0].c_str(),1);
	char* str = "Hello World";
	//SetStr("Hello World");
	a = t->CallMemFun(funs[2].c_str(),(int)str);
	student_t s;
	s.id = 1;
	strcpy_s(s.name,32,"your name");
	//SetInfo(*student)
	a = t->CallMemFun(funs[1].c_str(),(int)&s);
}

可以看到,在使用的时候并没有出现 CTest 常规调用的任何东西,一切都是字符串,意味着可以通过配置文件来调用。一个 int 型的参数可以转换为任何复杂参数的地址,对于多参数可以用一个结构体。

四,未完成

    这个简单的框架并没有支持全局函数和类成员变量,以及类的 public static 的函数。同时不支持多种参数类型。毕竟,最主要的原因也是C++用到反射技术的场景不是太多,对此有依赖的可能要换语言了。