运行时反射
类对象反射
-
首先实现一个内部静态变量的懒汉单例
单例模式的使用template<class T> class Singleton{ public: static T* instance(){ static T m_instance; return &m_instance; } private: Singleton(){}; ~Singleton(){}; Singleton(const Singleton<T> &); Singleton<T>& operator= (const Singleton<T> &); }; -
工厂类提供注册和创建类的函数
使用map来记录类的名称和对应创建该类的函数指针,该指针所指函数 使用new创建相应的类对象并返回
using create_obj = void*(*)(void); class ClassFactory{ public: //注册函数 void register_class(const std::string& className, create_obj method); //创建函数 void* create_class(const std::string & className); private: ClassFactory(){} ~ClassFactory(){} private: //使用map来记录类的名称和对应创建类的函数 std::map<std::string, create_obj> m_classMap; friend class utility::Singleton<ClassFactory>; }; -
使用:创建类之前需要注册类
int main(){ //1.获取工厂单例 ClassFactory* factory = Singleton<ClassFactory>::instance(); //2.注册类 factory->register_class("A", [](){ A* a = new A; return static_cast<void*>(a); }); //3.创建类 A* a = static_cast<A*>(factory->create_class("A")); a->show(); return 0; } -
实现注册类:将调用函数进行注册的步骤写成宏函数,在A.h末尾调用
注意:宏定义不能放在命名空间内,因为宏定义属于预处理指令;在预处理阶段执行,而 在编译阶段执行。宏定义早在编译之前的预处理阶段就已执行完毕。class ClassRegister{ public: ClassRegister(const std::string& className, create_obj method){ auto factory = utility::Singleton<ClassFactory>::instance(); factory->register_class(className, method); } }; #define REGISTER_CLASS(className)\ void* createObject##className(){\ void* obj = new className();\ return obj;\ }\ ClassRegister classRegister##className(#className, createObject##className) } -
在实际创建类时将void* 强转为A* 是不合理的,因为根本不知道是要使用的A类还是B类
写一个A类、B类的公共基类:class Object,这样使用时直接用父类指针即可
class Object{ public: Object(){}; virtual void show() = 0; virtual ~Object(){};//使用虚析构才能确保 正确调用派生类的析构函数 }; //使用 int main(){ ClassFactory* factory = Singleton<ClassFactory>::instance(); Object* a = factory->create_class("A"); a->show(); return 0; }
类成员数据反射
-
通过数据成员在类中的偏移量获取数据
#include <string> #include <iostream> class Test{ public: Test(const std::string& name, int age):m_name(name), m_age(age){ } public: std::string m_name; int m_age; }; int main(){ Test t("yx", 12); std::cout<<*(reinterpret_cast<std::string*>(&t))<<std::endl;//yx auto offset = &(static_cast<Test*>(nullptr)->m_age); int age = *( reinterpret_cast<int*>((size_t)&t + (size_t)offset) );//(size_t)offset)是32,因为std::string占32字节 std::cout<<age<<std::endl; return 0; }获取偏移量简写为如下宏(实际上标准库stddef.h有该函数offsetof)
#define OFFSET(className, fieldName)\ ((size_t)(&((className*)0)->fieldName)) -
定义一个 字段数据结构
保存 字段名、字段类型、字段在类中的偏移量
class ClassField{ public: ClassField(): m_name(""), m_type(""), m_offset(0){ } ClassField(const std::string& name, const std::string& type, size_t offset):m_name(name), m_type(type), m_offset(offset){ } ~ClassField(){} public: std::string m_name; std::string m_type; size_t m_offset; }; -
字段的注册与获取
注册就是 将类名:字段信息 保存到map中。获取就是从map中取出字段信息,然后根据其中的偏移量获取到成员变量的值。
template <class T> inline void Object::get(const std::string &fieldName, T &value) { ClassFactory* factory = utility::Singleton<ClassFactory>::instance(); auto field = factory->get_field(m_className, fieldName);//从map中找 size_t offset = field->m_offset; value = *(T*)((size_t)(this)+offset); }
函数指针的使用
class Test{
public:
int f2(int m){
std::cout<<"Test2::ff "<<m<<std::endl;
return m;
}
};
int f1(int m){
std::cout<<"ff "<<m<<std::endl;
return m;
}
int main(){
//1.普通函数指针
using f1_ptr_type = int(*)(int);
f1_ptr_type f1_ptr = f1;
f1_ptr(3);
//2.成员函数指针:使用function
using f2_ptr_type = std::function<int(Test*, int)>;
f2_ptr_type f2_ptr = &Test::f2;
Test t;
f2_ptr(&t, 4);
//3.成员函数指针:通过对象调函数
using f3_ptr_type = int(Test::*)(int);
f3_ptr_type f3_ptr = &Test::f2;
Test t2;
(t2.*f3_ptr)(5);
}

5063

被折叠的 条评论
为什么被折叠?



