![ba641fd5d67111d5ce6bb67095fc383e.png](https://img-blog.csdnimg.cn/img_convert/ba641fd5d67111d5ce6bb67095fc383e.png)
反射机制总览
反射在Java和C#等语言中比较常见,概况的说,反射数据描述了类在运行时的内容。这些数据所存储的信息包括类的名称、类中的数据成员、每个数据成员的类型、每个成员位于对象内存映像的偏移(offset),此外,它也包含类的所有成员函数信息。
C++本身不支持反射,UE4在C++基础上搭建了自己的一套反射机制。之前对于反射的描述可能比较抽象,具体来看,对于一个类(UClass),我们可以获得这个类的所有属性和方法,而对于一个类对象(UObject),我们可以调用它所拥有的方法和属性,前提是这些属性和方法被纳入到UE4的反射系统。于是,虚幻4使用反射可以实现序列化、editor的details panel、垃圾回收、网络复制、蓝图/C++通信和相互调用等功能。
反射系统是选择加入的,只有主动标记的类型、属性、方法会被反射系统追踪,UnrealHeaderTool会收集这些信息,生成用于支持反射机制的C++代码,然后再编译工程。
反射系统实现原理
UObject是反射系统的核心。每一个继承UObject且支持反射系统的类型都有一个相应的UClass,或者它的子类,UClass中包含了该类的描述信息。UObject与UClass也组成了UE4对象系统的基石,相关内容可以查看UE4对象系统的分析。
标记
为了标记一个包含反射类型的头文件,需要添加一个特殊的include,这时UHT知道需要处理这个文件。
#include "FileName.generated.h"
可以使用UENUM()、UCLASS()、USTRUCT()、UFUNCTION()、UPROPERTY()来标记不同的类型和成员变量,标记也可以包含额外的描述关键字。
也可以声明非反射类型的属性,这些属性对反射系统是非可见的(因此存储一个引用UObject的裸指针是非常危险的,因为垃圾回收系统看不到这个引用,但UE4也提供了FReferenceCollector来手动添加对UObject的引用)
每个描述的关键字(例如EditAnywhere或BlueprintCallable)都在ObjectMacros.h中有一个镜像,有一个简短的描述。当不知道一个关键字的意思时,可以去ObjectBase.h中去查看
UnrealHeaderTool和UnrealBuildTool
刚接触UE4时,我会产生一些疑问,比如Class里的GENERATED_BODY()到底包含了哪些内容,cpp中的XXX_Implementation函数在头文件中没有定义,又是怎么编译通过的?其实这些都是UnrealHeaderTool帮我们做的事情。
反射C++代码是由Unreal Build Tool和Unreal Header Tool产生的。UBT通过扫描头文件,记录所有包含反射类型的modules,当其中有头文件改变时,就会用UHT更新反射数据。UHT解析头文件,扫描标记,生成用于支持反射的C++代码。举个例子,对于一个文件filename.h,反射代码包括两部分:filename.generated.h和filename.gen.cpp,前者正是我们在filename.h中必须#include的头文件。下文