一、类反射
在分析了简单类和结构体后,可以进一步的分析普通类的反射了,对一个类进行反射,一般有下面几种情况:
1、通过类名进行对象的创建和匹配
2、对类成员变量的反射
3、对类成员函数的反射
4、可以处理类的继承等关系
这里只对基础的部分进行处理,包括继承等复杂的应用暂时不关心。
二、实现机制
类反射机制仍然重点是以分析如何获得类类型、成员函数和变量和进行展开,相关的复杂的应用会在后面进行继续专门的分析。类反射的实现有几种方式:
1、使用基础的STL的相关元库
这种机制一般只能进行判断而无法进行直接的类对象和成员的调用
2、使用宏和模板(含元编程)实现
这种机制实现较为复杂,但可能应用起来比较全面
3、使用开源的框架或库
这种机制其实就是别人封装好的反射调用,但风格可能千奇百异
这里不在严格的以动态或者静态反射区分,而以实现的机制来做分析的方向,至于这种实现属于哪种或者是否是二者结合,自行分辨即可。
三、实现
在前面已经实现过类似于POD类型的成员反射,所以这里先略过这些;而利用Traits STL库来实现对类及成员进行判断的回头也拿出一章来专门分析,其中一些个别的用法也已经在展开具体分析了。
所以,本文主要对反射生成对象和普通成员函数进行反射调用。
四、例程分析
下面看一个初步的实现:
1、基础实例对象管理类
#pragma once
#include <string>
#include <iostream>
class Ins
{
public:
void SetName(const std::string& cName)
{
className = cName;
}
void getName() const
{
std::cout << className << std::endl;
}
public:
void GetFunc(const std::string& FuncName);
public:
std::string className;
};
typedef Ins* (*createIns)(void);
class ClassFunc
{
public:
ClassFunc(const std::string& name, uint64_t Func) : funcName(name), pFunc(Func) {}
const std::string& Name() { return funcName; }
const uint64_t Func() { return pFunc; }
private:
std::string funcName;
uint64_t pFunc;
};
#include "ins.h"
#include <functional>
#include "singleton.h"
#include "factory.h"
void Ins::GetFunc(const std::string& funcName)
{
ClassFunc* ClassFunc = Singleton<Factory>::Instance()->GetMemFunc(className, funcName);
if (ClassFunc == nullptr) {
std::cerr << "get func err!" << std::endl;
return;
}
typedef std::function<void(Ins*)> CFunc;
(*reinterpret_cast<CFunc*>(ClassFunc->Func()))(this);
}
2、一个单例类
#pragma once
#include <mutex>
template<typename T>
class Singleton
{
public:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton& other) = delete;
Singleton& operator=(const Singleton& other) = delete;
public:
static T* Instance()
{
static T* t = new T();
return t;
}
};
注意:c++0x以后安全.
3、注册工厂
#pragma once
#include <map>
#include <string>
#include <vector>
#include "singleton.h"
#include "ins.h"
class Factory
{
public:
Factory() = default;
virtual ~Factory() = default;
public:
void ClassReg(const std::string& className, createIns func);
Ins* GetObject(const std::string& className);
void RegMemFunc(const std::string& className, ClassFunc* func);
ClassFunc* GetMemFunc(const std::string& className, const std::string& funcName);
private:
std::map<std::string, createIns> mapClassName;
std::map<std::string, std::vector<ClassFunc*>> mapClassFunc;
};
#include "factory.h"
void Factory::ClassReg(const std::string& className, createIns func)
{
this->mapClassName.emplace(className,func);
}
Ins* Factory::GetObject(const std::string& className)
{
if (this->mapClassName.count(className) > 0) {
return this->mapClassName[className]();
}
return nullptr;
}
void Factory::RegMemFunc(const std::string& className, ClassFunc* func)
{
mapClassFunc[className].emplace_back(func);
}
ClassFunc* Factory::GetMemFunc(const std::string& className, const std::string& funcName)
{
if (this->mapClassFunc.count(className) > 0)
{
for (auto func : mapClassFunc[className])
{
if (func->Name()==funcName)
{
return func;
}
}
}
return nullptr;
}
4、注册和测试类
#include <iostream>
#include <mutex>
#include <map>
#include <vector>
#include <functional>
#include "singleton.h"
#include "factory.h"
class RegClass
{
public:
RegClass(const std::string& className, createIns func)
{
Singleton<Factory>::Instance()->ClassReg(className, func);
}
public:
RegClass(const std::string& className, const std::string& funcName, uint64_t func)
{
auto factory = Singleton<Factory>::Instance();
factory->RegMemFunc(className, new ClassFunc(funcName, func));
}
};
#define REG_CLASS(class_name) \
Ins* createIns##class_name() \
{ \
Ins* o = new class_name(); \
o->SetName(#class_name); \
return o; \
} \
RegClass RegClass##class_name(#class_name, createIns##class_name)
#define REG_CLASS_FUNC(class_name, func_name) \
std::function<void(class_name*)> class_name##func_name = &class_name::func_name; \
RegClass RegClass##class_name##func_name(#class_name, #func_name, (uint64_t)&(class_name##func_name))
class Ex0 :public Ins
{
};
REG_CLASS(Ex0);
class Ex1 : public Ins
{
};
REG_CLASS(Ex1);
void testClassRegister()
{
auto factory = Singleton<Factory>::Instance();
auto i0 = factory->GetObject("Ex0");
i0->getName();
auto i1 = factory->GetObject("Ex1");
i1->getName();
}
class Ex2 :public Ins
{
public:
void Test()
{
std::cout << "Ex2 Test!" << std::endl;
}
};
REG_CLASS(Ex2);
REG_CLASS_FUNC(Ex2, Test);
class Ex3 : public Ins
{
public:
void Test()
{
std::cout << "Ex3 Test!" << std::endl;
}
};
REG_CLASS(Ex3);
REG_CLASS_FUNC(Ex3, Test);
void testFunc()
{
auto factory = Singleton<Factory>::Instance();
Ins* i2 = factory->GetObject("Ex2");
Ins* i3 = factory->GetObject("Ex3");
i2->GetFunc("Test");
i3->GetFunc("Test");
}
int main()
{
testClassRegister();
testFunc();
return 0;
}
对类反射生成对象采用的是注册一个创建实例对象的函数指针;对成员函数的处理则是将其地址保存到Map中,在需要时进行调用。有一个比较难理解的是使用整形来替代类成员指针,这个没有什么,毕竟指针就是一个地址,地址就是一个整形的变量类型指向的位置。
上面的代码很清晰就不进一步的解释了,它主要是借鉴了QT中的类反射实现方式。
这个代码改进的究竟还相当大,但这里只是为了展示反射实现的过程,所以力求简单明了。比如注册类生成对象的函数可以使用模板函数,这样更灵活。以后有时间会进一步的进行优化。
五、总结
反射对c++是不是一种鸡肋,这个还真不好说。不过有一句话可以引入进来,“发展是硬道理”,只要是不断的发展,就会有机会。而停滞不前的空谈理论,一定是没有前途的。至于以后反射在c++后续标准里会成为什么样子,大家拭目以待即可。