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