UE4中反射用於什麼情況?
#define UPROPERTY(...)
#define UFUNCTION(...)
#define USTRUCT(...)
#define UMETA(...)
#define UPARAM(...)
#define UENUM(...)
#define UDELEGATE(...)
// This pair of macros is used to help implement GENERATED_BODY() and GENERATED_USTRUCT_BODY()
#define BODY_MACRO_COMBINE_INNER(A,B,C,D) A##B##C##D
#define BODY_MACRO_COMBINE(A,B,C,D) BODY_MACRO_COMBINE_INNER(A,B,C,D)
// Include a redundant semicolon at the end of the generated code block, so that intellisense parsers can start parsing
// a new declaration if the line number/generated code is out of date.
#define GENERATED_BODY_LEGACY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY_LEGACY);
#define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY);
當我們給變量/函數/類/結構體添加U###的時候,UHT就會幫助我們實現反射機制
C++與藍圖交互,UE4的變量回收系統,幾乎UE4所有的Module都利用了反射機制
UBT和UHT介紹
UnrealBuildTool(UBT):UE4來編譯各個模塊之間的依賴
UnrealHeaderTool(UHT,C++編譯器強化版):UE4 C++代碼編譯。UHT利用.generated.h信息生成C++反射代碼。完成後,再調用普通的C++編譯器
啓動UE4編譯時,UE4首先調用UHT,檢索.h中的UCLASS、GENERATED_BODY、UPROPERTY、UFUNTION等關鍵字,然後生成generate.h和generate.cpp文件
生成階段
helloworld.generated.h文件中
GENERATED_BODY
#define GENERATED_BODY_LEGACY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY_LEGACY);
對於某個類的GENERATED_BODY來說,CURRENT_FILE_ID定義在該文件的.generated.h文件中
DECLARE_FUNCTION
- NavtiveFuncTest定義BlueprintNativeEvent,藍圖和C++均可以實現。在C++中實現的方法要加上NavtiveFuncTest_Implementation(),因爲UBT內部已經實現這部分的定義?(理由見下)
- DECLARE_FUNCTION(execNavtiveFuncTest)。聲明一個函數爲execNavtiveFuncTest,會優先調用藍圖方法,如果不存在的話再調用C++的NavtiveFuncTest_Implementation()
DECLARE_CLASS
private: \
static void StaticRegisterNativesAHelloGameMode(); \
friend struct Z_Construct_UClass_AHelloGameMode_Statics; \
public: \
DECLARE_CLASS(AHelloGameMode, AGameModeBase, COMPILED_IN_FLAGS(0 | CLASS_Transient), CASTCLASS_None, TEXT("/Script/helloworld"), NO_API) \
DECLARE_SERIALIZER(AHelloGameMode)
Generated.cpp文件中
ProcessEvent
static FName NAME_AHelloGameMode_NavtiveFuncTest = FName(TEXT("NavtiveFuncTest"));
void AHelloGameMode::NavtiveFuncTest()
{
ProcessEvent(FindFunctionChecked(NAME_AHelloGameMode_NavtiveFuncTest),NULL);
}
很明顯,在.cpp文件中,NativeFuncTest函數已經被自動生成。因此對於都可用&&藍圖>C++優先級的情況下,需要加上_Implementablement來聲明,否則會報錯已經定義
IMPLEMENT_CLASS
MPLEMENT_CLASS(AHelloGameMode, 3705664059);
template<> HELLOWORLD_API UClass* StaticClass<AHelloGameMode>()
{
return AHelloGameMode::StaticClass();
}
收集階段(利用Static自動註冊方式,將UCLASS登記,放進Array統一管理)
在收集階段(上一階段)在IMPLEMENT_CLASS和ConstructClass兩個函數中靜態聲明瞭兩個變量
#define IMPLEMENT_CLASS(TClass, TClassCrc) \
static TClassCompiledInDefer<TClass> AutoInitialize##TClass(TEXT(#TClass), sizeof(TClass), TClassCrc); \
和
static FCompiledInDefer Z_CompiledInDefer_UClass_##TClass(Z_Construct_UClass_##TClass, &TClass::StaticClass, TEXT(TPackage), TEXT(#TClass), false);
- TClassCompiledInDefer(調用UClassCompiledInDefer收集數據)是分配空間
- FCompiledInDefer(調用UObjectCompiledInDefer收集數據),調用初始化函數
- 並且將註冊信息放入ClassInfo延遲註冊,如果類太多,全部都要註冊會很卡
void ProcessNewlyLoadedUObjects(FName Package, bool bCanProcessNewlyLoadedObjects)
{
UClassRegisterAllCompiledInClasses();
const TArray<UClass* (*)()>& DeferredCompiledInRegistration = GetDeferredCompiledInRegistration();
const TArray<FPendingStructRegistrant>& DeferredCompiledInStructRegistration = GetDeferredCompiledInStructRegistration();
const TArray<FPendingEnumRegistrant>& DeferredCompiledInEnumRegistration = GetDeferredCompiledInEnumRegistration();
bool bNewUObjects = false;
while (GFirstPendingRegistrant || DeferredCompiledInRegistration.Num() || DeferredCompiledInStructRegistration.Num() || DeferredCompiledInEnumRegistration.Num())
{
bNewUObjects = true;
UObjectProcessRegistrants();
UObjectLoadAllCompiledInStructs();
UObjectLoadAllCompiledInDefaultProperties();
}
}
ProcessNewlyLoadedUObjects用於註冊類,結構體,枚舉的反射信息
收集階段
通過UClassCompiledInDefer收集