反射
c++本身是没有反射机制的。反射是什么?我认为是运行时对象信息库,反射就是在需要获取对象信息的时候使用,在做类型转换的时候使用,获取对象实例的时候使用...统一一下就是获取对象信息的时候。
那我们要去做一套反射机制,应该怎么做呢?C#的反射机制是在编译器里收集对象的信息,然后再运行时去读取元数据。ue5也有反射,ue5使用的是通用的编译器,那说明肯定和C#的方式不一样......然后编不下去了,我们还是另辟蹊径去实现把。
反射这个功能的关键点在于怎么去收集数据,收集数据又有几个难点
1.如何确定那些需要被收集(可以仿照UE方案使用宏,宏可以告诉我们那些数据要被收集,但是程序根本不知道谁加了宏)
2.数据收集的时机
下图是一个进程的生命周期
我们会发现C/C++启动函数会初始化静态变量和方法(盲猜变量会先于方法被初始化/或调用方法的时候被初始化)。这时候,我们就可以解决定位宏的问题了,利用静态的特性,我们可以在类里加宏,宏里调用一个专用于初始化数据的类,如果是字段就往数据初始化类里加字段,如果是方法就加方法,这样我们就会有两个列表,字段和方法列表,列表里可能是一个数据结构,有归属类,类型,名称,这样在序列化对象的时候就不用计算了。然后再给需要反射的类里都加一个专用于记录字段和方法的对象指针,用于后续对数据的操作。
反射获取字段/添加字段
如果按照上面的思路,我们可以通过名称直接去获取。一个对象在内存里就是若干个字段在占用内存,方法都在方法区。我们可以重新申请一段内存,把旧的数据先深度拷贝进去,然后把新加的字段加入进去,然后用新的指针替换旧的指针,这样我们就会得到一个被反射添加自定义数据的对象指针。后面可以用序列化把对象本地化,在本地存一份被反射添加过数据的类名,进行检测然后直接反序列化本地的数据,但是没太大必要,直接申请内存更方便,除非是一些本来就想要在本地序列化的数据,比如我们可以用一个类存储一个模型的所有数据,当我们修改模型一些数据后,我们希望永久保存下来,那就可以用序列化+反射去操作。
反射执行方法和添加方法
所有数据都存在pe文件里,都被加载进内存里,在pe文件里所有数据都有一个自己的地址,在被加载的时候通过自身地址+程序基地址得到数据在程序的地址。那这就好办了,我们需要把方法反射添加到一个对象里,那该方法自身肯定也被加了可以被反射的宏,那我们就可以知道该方法的地址(反射收集的就是方法的地址)。然后把这个类添加到该对象的信息存储对象里,这样我们就可以使用反射去执行这个方法了(直接用方法名)。
延展-热更新
有这样一套反射的功能,我们是不是可以直接再这一套的基础上做热更新。我们可以在反射收集完成后,不急于初始化收集的数据(比如,执行用反射添加的Init方法),让主程序直接加载一个需要被热更新的程序集,程序集不是被链接进去的,直接被加载进去的理论上也是要初始化静态数据的,那这样我们就可以用反射去做热更新了。主程序里开一个子程序,然后断开与主程序的关系,子程序负责检测主程序是否在执行,下载被热更新程序集,远程注入dll。与后台服务器连接,根据后台命令下载dll,然后开启远程线程进行dll注入,这样就可以直接让程序不用关机也可以直接更新逻辑,做到C++项目的真热更新,或者说更像一个病毒。
序列化
序列化一个对象的数据和方法就是一个对象的所有了,这里我们是把通过反射功能收集的数据进行本地化。
反序列化
一个对象的地址每次都不一样,对象的地址是程序向堆或栈申请的一块内存。在被反序列化的时候,我们把字段根据序列化时保存的字段和内容填充到内存里。
后面可以在规划为每一个类型设计一个数据代理类负责数据和方法的操作,这只是粗略的思路和一些天马行空的想法,理论上可行。感觉被阳了,发着低烧,晕乎乎的思路比较奇怪,感觉有点理解程序是数据组成的这个说法。
标签:反射,浅谈,收集,对象,方法,序列化,数据 From: https://www.cnblogs.com/zjr0/p/16996214.html