【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

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