【UE4】反射系统分析(一)

一、反射的宏标记

  在编写UE4 C++代码时,我们经常使用UCLASS()、USTRUCT()、UENUM()、UFUNCTION()、UPROPERTY()等宏去标记我们的类和成员变量,只有添加这些宏的类或成员才能将其添加到反射系统。这样,基于UE4反射的GC系统等可以管理我们的反射数据。举例而言,当一个继承UObject的类对象指针被声明时,如果不使用UPROPERTY将其标记,则GC不能察觉到它的存在,也就不能对其进行管理。当GC认为没有其它对象包含该对象的指针引用时,将对其回收,那么此成员变量将会成为野指针,这个操作是有风险的。所以,我们应该主动用UPROPERTY标记,由UE4的GC帮我们管理该成员指针。或者使用AddToRoot方法,防止GC。
  在宏标记中,我们可以选择性的添加标识符,以决定被反射数据可以在哪里使用、如何被使用。有选择性添加标识符,可以减少不必要的反射数据,这样做可以节省元数据所占用的内存。

二、反射数据

  被反射的类或变量等数据将会被保存在元数据当中。也就是说通过元数据对象,我们可以获取到被反射类或成员的所有数据,比如类名、继承关系、包含的成员变量、类型信息等。元数据类的继承关系如下:
UE4反射元数据类图

UObject
UField
UStruct
UClass
UScriptStruct
UFunction
UEnum
UProperty
  • UClass: C++类,UClass将会包含成员变量、成员函数和继承的子类等数据。
  • UStructStruct: C++结构体。
  • UFunction:C++函数方法。
  • UEnum:C++枚举类。
  • UProperty:C++类或结构体的成员变量。注意:嵌套模板和部分类型不能被反射,如TArray、TMap的嵌套。

获取类和结构体的元数据
  对于继承UObject类的子类,我们可以使用静态方法StaticClass()获取该类的反射对象(元数据)。而对于结构体,可以使用StaticStruct()获取结构体的反射数据。继承UObject类的实例,也可以使用GetClass()来获取元数据,而结构体对象则可以。
获取被反射的成员变量的元数据
继承UStruct的UClass和UScriptStruct是聚合结构体的元数据,可以通过它们得到类包含的成员,例如遍历获取类包含的被反射的成员变量:

for(TFieldIterator<UProperty> It(GetClass()); It; ++It)
{
	UProperty* Prop = *It;
}

获取被反射方法的元数据
  上面是通过类的元数据获取类的成员变量元数据的方法,那如果要获取类的反射方法,可以调用类对象的FindFunction方法或者类元数据的FindFunctionByName方法来获取反射方法的元数据。

UFunction* Func = ObjectSelf->FindFunction(FName FuncName);
UFunction* Func = ObjectSelf->GetClass()->FindFunctionByName(FName FuncName);

获取被反射枚举的元数据
  通过FindObject可以获取任意的UObject类对象,枚举的反射数据被保存在UEnum类实例中,而UObject又是UEnum的(祖)父类。所以,我们可以通过FindObject来获取枚举类的反射数据对象。

//所所有包中查找名为EnumName的枚举类的反射数据,并精准匹配。
UEnum* EnumPtr = FindObject<UEnum>(ANY_PACKAGE, *EnumName, true);

三、UBT和UHT

UBT主要负责各模块的编译及各模块之间的依赖关系,比如解析Build.cs等文件。而UHT则会为我们编写的UE4 C++代码进行反射处理,比如在gen.cpp和generated.h文件中生成反射代码等。

UBT

UBT可以解析项目的Target.cs和模块的build.cs等文件,这些文件代码使用C#进行编码配置。UBT还会从以下XML配置文件中读取配置数据,然后用于构建编译项目:

  • Engine/Saved/UnrealBuildTool/BuildConfiguration.xml
  • User Folder/AppData/Roaming/Unreal Engine/UnrealBuildTool/BuildConfiguration.xml
  • My Documents/Unreal Engine/UnrealBuildTool/BuildConfiguration.xml

项目Target.cs
下面是项目的一般的Target.cs文件的一般结构:

using UnrealBuildTool;
using System.Collections.Generic;
public class MyProjectTarget : TargetRules
{
    public MyProjectTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;
        ExtraModuleNames.AddRange( new string[] { "StartWork", "ProjectEditor" } );
        // 其它属性配置
    }
}

UBT支持构建以下类型的项目,对应于配置文件中的Type值:

  • Game 游戏项目
  • Client 和Game相似,但是不包含服务器代码
  • Server 不包含客户端代码
  • Editor 编辑器模块
  • Program 独立程序

ExtraModuleNames是一个字符串数组列表,被包含在此列表中的模块将被编译到Target中。这些模块就是项目源码目录下的模块内容。
其它属性变量

模块build.cs
build.cs中属性变量说明
编译配置
编译配置文件中的设置说明

UHT

UHT是支持对UObject系统的代码解析和生成工具。它可以C++头文件中引擎相关的类元数据,并生成反射代码。可以在generated.h和gen.cpp文件中查看生成的反射代码。更详细的generated文件的解析,后续介绍。

参考文章

深入研究虚幻4反射系统实现原理(一)
UnrealBuildTools

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章