【UE4】反射系統分析(二)

一、generated.h代碼分析

這節主要分析一下generated.h文件中的代碼。首選先創建一個繼承AActor的類,並編譯,UHT會生成一個generated.h文件。下邊來分析一下AActor類中的GENERATED_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)
#define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY);

我們可以看到,GENERATED_BODY()的作用是把CURRENT_FILE_ID、_、_LINE_、_GENERATED_BODY這幾個參數。
CURRENT_FILE_ID這個參數被UHT在generated.h中被定義爲具體值,即類文件的id。

#define CURRENT_FILE_ID StartWork_Source_StartWork_Public_MyActor_h

__LINE__表示GENERATED_BODY()在類文件中聲明的行號,此類中該宏在第12行被聲明。
GENERATED_BODY()的聲明
所以,GENERATED_BODY()被替換爲StartWork_Source_StartWork_Public_MyActor_h_12_GENERATED_BODY,而該宏可在MyActor.generated.h中找到拓展。

#define StartWork_Source_StartWork_Public_TTTActor_h_12_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
	StartWork_Source_StartWork_Public_MyActor_h_12_PRIVATE_PROPERTY_OFFSET \
	StartWork_Source_StartWork_Public_MyActor_h_12_SPARSE_DATA \
	StartWork_Source_StartWork_Public_MyActor_h_12_RPC_WRAPPERS_NO_PURE_DECLS \
	StartWork_Source_StartWork_Public_MyActor_h_12_INCLASS_NO_PURE_DECLS \
	StartWork_Source_StartWork_Public_MyActor_h_12_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS

PRAGMA_DISABLE_DEPRECATION_WARNINGS和PRAGMA_ENABLE_DEPRECATION_WARNINGS分別是禁用和啓用棄用警告。而public中的五個宏,前三個暫時是空定義,所以下面分別來展開後邊兩個宏。

1. INCLASS_NO_PURE_DECLS

private:
	//註冊類的成員方法,註冊後則可被藍圖(虛擬機)訪問
	static void StaticRegisterNativesAMyActor();
	//友元結構體,在gen.cpp中定義,它用來描述該類的屬性和成員數據等
	friend struct Z_Construct_UClass_AMyActor_Statics;
public:
	//定義類的常用方法與別名,如StaticClass、StaticPackage等方法,Super、ThisClass等。
	DECLARE_CLASS(AMyActor, AActor, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/StartWork"), NO_API)
	//定義該類的序列化方法
	DECLARE_SERIALIZER(AMyActor)

StaticRegisterNativesAMyActor
該靜態方法將會把在C++類中定義並加入反射的函數方法進行註冊。後邊章節分析反射方法時再做具體介紹。

Z_Construct_UClass_AMyActor_Statics
將Z_Construct_UClass_AMyActor_Statics結構體聲明爲友元,友元類可以訪問該類的private方法。該友元結構體被UHT在該類的gen.cpp中定義。該結構體包含該類的成員信息,可以理解爲對該類的靜態描述。

struct Z_Construct_UClass_AMyActor_Statics
{
	/********************************************************************************************/
	/*	DependentSingletons是一個空入參返回值是UObject指針的函數指針靜態常量數組。					*/
	/*	UObject* (*const Z_Construct_UClass_ATTTActor_Statics::DependentSingletons[])() = {		*/
	/*	(UObject* (*)())Z_Construct_UClass_AActor,												*/
	/*	(UObject* (*)())Z_Construct_UPackage__Script_StartWork,									*/
	/********************************************************************************************/
	};
	static UObject* (*const DependentSingletons[])();	//依賴的單例函數指針數組
#if WITH_METADATA	//(WITH_EDITORONLY_DATA && WITH_EDITOR)
	//元數據的鍵值對數組,僅在編輯器模式啓用
	static const UE4CodeGen_Private::FMetaDataPairParam Class_MetaDataParams[];
#endif
	//返回是否是抽象類
	static const FCppClassTypeInfoStatic StaticCppClassTypeInfo;
	//該變量包含類的成員參數信息
	static const UE4CodeGen_Private::FClassParams ClassParams;
};
/*	
struct FClassParams
{
	UClass*                                  (*ClassNoRegisterFunc)();
	UObject*                          		 (*const *DependencySingletonFuncArray)();
	int32                                    NumDependencySingletons;
	uint32                                   ClassFlags; // EClassFlags
	const FClassFunctionLinkInfo*            FunctionLinkArray;
	int32                                    NumFunctions;
	const FPropertyParamsBase* const*        PropertyArray;
	int32                                    NumProperties;
	const char*                              ClassConfigNameUTF8;
	const FCppClassTypeInfoStatic*           CppClassInfo;
	const FImplementedInterfaceParams*       ImplementedInterfaceArray;
	int32                                    NumImplementedInterfaces;
#if WITH_METADATA
	const FMetaDataPairParam*                MetaDataArray;
	int32                                    NumMetaData;
#endif
};
*/

DECLARE_CLASS
此宏將會聲明並定義UObject類的常用方法和別名,比如我們常用的靜態方法StaticClass來獲取UClass對象以及Super來指代父類等。

//第一個參數爲類名,第二個爲父類名,第三個該類的標識符,第三個是可以轉換的類,第四個是該類的包名,第四個是導出宏
DECLARE_CLASS(AMyActor, AActor, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/StartWork"), NO_API) 
//此宏展開爲下面代碼:
private: 
	//重載賦值操作符,把右值引用和常量引用賦值操作符放到private作用域下,目的是“禁用”常規的引用初始化方法
	AMyActor& operator=(AMyActor&&);   
	AMyActor& operator=(const AMyActor&);   
	//返回此類的UClass對象,下面的StaticClass調用此方法。該類在gen.cpp中的宏中定義
	NO_API static UClass* GetPrivateStaticClass(); 	
public: 
	/** EClassFlags的位運算適用於此類.*/ 
	enum {StaticClassFlags=EClassFlags::CLASS_Intrinsic}; /**EClassFlags枚舉是用來描述類的標識符*/
	/** 爲此列的父類起別名Super,方便使用 */ 
	typedef AActor Super;
	/** 爲此類類型起別名ThisClass */ 
	typedef AMyActor ThisClass;
	/**返回表示此類運行時狀態的UClass對象 */
	inline static UClass* StaticClass() { return GetPrivateStaticClass(); }
	/** 返回此類所屬包,返回的是包名。可以通過FindPackage方法傳入包名找到該包的UPackage對象。FindObject方法傳入UPackage對象,可以在包的範圍內搜索類 */
	inline static const TCHAR* StaticPackage() { return TEXT("/Script/StartWork"); }
	/** 返回這個類的靜態轉換標識符 */
	inline static EClassCastFlags StaticClassCastFlags()
	{/** EClassCastFlags是類型轉換標識符,類的轉換標識符是可繼承的。*/
		return EClassCastFlags::CASTCLASS_None;
	}
	/** 僅供內部使用,使用StaticConstructObject()創建新的對象. */
	inline void* operator new(const size_t InSize, EInternal InInternalOnly, UObject* InOuter = (UObject*)GetTransientPackage(), FName InName = NAME_None, EObjectFlags InSetFlags = RF_NoFlags)
	{ return StaticAllocateObject(StaticClass(), InOuter, InName, InSetFlags); }
	/** 僅供內部使用,重寫new方法,使用StaticConstructObject()創建新的對象. */
	inline void* operator new( const size_t InSize, EInternal* InMem ) { return (void*)InMem; }

DECLARE_SERIALIZER
此宏主要是定義序列化的方法。

DECLARE_SERIALIZER(AMyActor)
//此宏展開爲下面代碼:
friend FArchive &operator<<( FArchive& Ar, AMyActor*& Res ) { return Ar << (UObject*&)Res; } 
friend void operator<<(FStructuredArchive::FSlot InSlot, AMyActor*& Res) { InSlot << (UObject*&)Res; }

2. ENHANCED_CONSTRUCTORS

#define StartWork_Source_StartWork_Public_MyActor_h_12_ENHANCED_CONSTRUCTORS \
private: \
	/** 將賦值拷貝構造器放在private下,禁止開發者通過此方法創建對象*/ \
	NO_API AMyActor(AMyActor&&); \
	NO_API AMyActor(const AMyActor&); \
public: \
	//用於熱重載的構造方法
	DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, AMyActor); \
	DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(AMyActor); \
	DEFINE_DEFAULT_CONSTRUCTOR_CALL(AMyActor)

DECLARE_VTABLE_PTR_HELPER_CTOR

DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, AMyActor);
//該宏展開後爲下面代碼:
NO_API AMyActor(FVTableHelper& Helper);/** 此構造器僅用於熱重載。*/ 

DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER

DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(AMyActor);
//該宏展開後爲以下代碼:
static UObject* __VTableCtorCaller(FVTableHelper& Helper)
{
	return new (EInternal::EC_InternalUseOnlyConstructor, (UObject*)GetTransientPackage(), NAME_None, RF_NeedLoad | RF_ClassDefaultObject | RF_TagGarbageTemp) AMyActor(Helper); 
}

DEFINE_DEFAULT_CONSTRUCTOR_CALL

DEFINE_DEFAULT_CONSTRUCTOR_CALL(AMyActor)
//該宏展開後代碼爲:
static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())AMyActor; }

二、gen.cpp代碼分析

void EmptyLinkFunctionForGeneratedCodeMyActor() {}
// 方法聲明
STARTWORK_API UClass* Z_Construct_UClass_AMyActor_NoRegister();	//無註冊構造UClass對象,直接返回StaticClass方法
STARTWORK_API UClass* Z_Construct_UClass_AMyActor();			//有註冊構造UClass對象
ENGINE_API UClass* Z_Construct_UClass_AActor();					//AActor類的UClass對象構造方法,定義在Actor.gen.cpp文件中
UPackage* Z_Construct_UPackage__Script_StartWork();				//構造該模塊UPackage對象的方法聲明,該UPackage對象爲靜態成員
/** 該方法在ModuleName.init.gen.cpp中被定義
	UPackage* Z_Construct_UPackage__Script_StartWork()
	{
		static UPackage* ReturnPackage = nullptr;
		if (!ReturnPackage)
		{
			static const UE4CodeGen_Private::FPackageParams PackageParams = {
				"/Script/StartWork",			//NameUTF8,包名
				nullptr,						//SingletonFuncArray,單例函數指針數組
				0,								//NumSingletons,單例函數數量
				PKG_CompiledIn | 0x00000000,	//PackageFlags,包的標識符
				0xC86909DB,						//BodyCRC, 本體校驗碼
				0x2A968D62,						//DeclarationsCRC,聲明校驗碼
				METADATA_PARAMS(nullptr, 0)		//MetaDataArray,NumMetaData,元數據數組和數量
			};
			UE4CodeGen_Private::ConstructUPackage(ReturnPackage, PackageParams);
		}
		return ReturnPackage;
	}
*/
//此函數會將類中使用UFUNCTION宏反射的方法註冊,該方法在generated.h中聲明。具體註冊後續章節成員方法反射時分析。
void AMyActor::StaticRegisterNativesAMyActor(){}
//無註冊構造UClass對象,直接返回StaticClass方法結果,即GetPrivateStaticClass方法構造的UClass對象
UClass* Z_Construct_UClass_AMyActor_NoRegister(){ return AMyActor::StaticClass(); }
//包含對類的描述數據,此結構體會根據類的定義增加更多成員變量,當前成員變量是創建默認Actor類的默認結構體的數據結構
struct Z_Construct_UClass_AMyActor_Statics
{
	static UObject* (*const DependentSingletons[])();
#if WITH_METADATA	//在編輯器模式下啓用
	static const UE4CodeGen_Private::FMetaDataPairParam Class_MetaDataParams[];	//路徑鍵值對參數
#endif
	/*struct FCppClassTypeInfoStatic { bool bIsAbstract; };*/
	static const FCppClassTypeInfoStatic StaticCppClassTypeInfo;
	static const UE4CodeGen_Private::FClassParams ClassParams;
};
/*************************************************************/
/*	後續四個賦值都是對上述結構體的靜態成員變量初始化			 */
/*************************************************************/
//對上述結構體的靜態成員DependentSingletons賦值
UObject* (*const Z_Construct_UClass_AMyActor_Statics::DependentSingletons[])() = {
	(UObject* (*)())Z_Construct_UClass_AActor,
	(UObject* (*)())Z_Construct_UPackage__Script_StartWork,
};
#if WITH_METADATA
//在編輯器模式時,將類文件在模塊的路徑和類文件名賦值到上述結構體的靜態成員
const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UClass_AMyActor_Statics::Class_MetaDataParams[] = {
	{ "IncludePath", "MyActor.h" },
	{ "ModuleRelativePath", "Public/MyActor.h" },
};
#endif
//返回類的類型信息,即該類是否是抽象類
const FCppClassTypeInfoStatic Z_Construct_UClass_AMyActor_Statics::StaticCppClassTypeInfo = {
	TCppClassTypeTraits<AMyActor>::IsAbstract,
};
//初始化類的成員信息
const UE4CodeGen_Private::FClassParams Z_Construct_UClass_AMyActor_Statics::ClassParams = {
	&AMyActor::StaticClass,									//ClassNoRegisterFunc,函數指針,指向StaticClass方法(未註冊方法)
	DependentSingletons, ARRAY_COUNT(DependentSingletons),	//DependencySingletonFuncArray, NumDependencySingletons
	0x009000A0u,				//ClassFlags,類的標識符
	nullptr, 0,					//FunctionLinkArray, NumFunctions分別是該類成員方法的數據數組和方法數量,後續分析
	nullptr, 0,					//PropertyArray, NumProperties分別是該類成員屬性的數據數組和屬性數量。若存在反射屬性,則爲Z_Construct_UClass_AMyActor_Statics::PropPointers, ARRAY_COUNT(Z_Construct_UClass_AMyActor_Statics::PropPointers)
	nullptr,					//ClassConfigNameUTF8,該類的配置名稱,當該類被表示爲config=ConfigName時有值
	&StaticCppClassTypeInfo,	//CppClassInfo,類的類型數據
	nullptr, 0,					//ImplementedInterfaceArray, NumImplementedInterfaces,實現的抽象類數據數組和數量
	METADATA_PARAMS(Z_Construct_UClass_AMyActor_Statics::Class_MetaDataParams, 		//MetaDataArray,只在編輯器模式有效的元數據參數數組
	ARRAY_COUNT(Z_Construct_UClass_AMyActor_Statics::Class_MetaDataParams))			//NumMetaData,元數據數量
};

//構造該類的UClass對象並註冊
UClass* Z_Construct_UClass_AMyActor()
{
	static UClass* OuterClass = nullptr;
	if (!OuterClass)
	{
		UE4CodeGen_Private::ConstructUClass(OuterClass, Z_Construct_UClass_AMyActor_Statics::ClassParams);
	}
	return OuterClass;
}
//在啓動時註冊類
IMPLEMENT_CLASS(AMyActor, 788795244);
//類對象的延遲註冊,IMPLEMENT_CLASS宏裏包含類UClass對象的延遲註冊
static FCompiledInDefer Z_CompiledInDefer_UClass_AMyActor(Z_Construct_UClass_AMyActor, &AMyActor::StaticClass, TEXT("/Script/StartWork"), TEXT("AMyActor"), false, nullptr, nullptr, nullptr);
DEFINE_VTABLE_PTR_HELPER_CTOR(AMyActor);
/* 展開之後爲:AMyActor::AMyActor(FVTableHelper& Helper) : Super(Helper) {};  */

IMPLEMENT_CLASS

包含兩個內容,一個是UClass對象的延遲註冊,一個是(無註冊)構造/獲取類的UClass對象。

//第一個參數是類型名,第二個參數是CRC(校驗碼)
IMPLEMENT_CLASS(AMyActor, 788795244);
//展開宏後:
/*AutoInitializeAMyActor是一個延遲編譯對象。當構造該對象時,若是熱加載模式,
則會通過延遲註冊表獲取舊的延遲編譯對象和當前延遲編譯對象比較,若有修改,則會更新延遲註冊表。
當非熱加載時,則直接創建/更新延遲註冊表。
該變量是一個靜態變量,且變量初始化時會註冊延遲註冊表。所以當啓動程序時,便會執行此方法,將該類註冊,且只執行一遍。*/
static TClassCompiledInDefer<AMyActor> AutoInitializeAMyActor(TEXT("AMyActor"), sizeof(AMyActor), 788795244); 
//StaticClass返回該方法的返回值。創建一個靜態UClass對象,第一次執行時初始化該對象。
UClass* AMyActor::GetPrivateStaticClass() 
{ 
	static UClass* PrivateStaticClass = NULL; 
	if (!PrivateStaticClass) 
	{ 
		GetPrivateStaticClassBody( 
			StaticPackage(), 								//返回包名的方法
			(TCHAR*)TEXT("AMyActor") + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), 	//類名
			PrivateStaticClass, 							//UClass對象指針
			StaticRegisterNativesAMyActor, 					//註冊成員方法的函數指針
			sizeof(AMyActor), 								//該類的大小
			(EClassFlags)AMyActor::StaticClassFlags, 		//類標識符
			AMyActor::StaticClassCastFlags(), 				//類轉換標識符
			AMyActor::StaticConfigName(), 					//類作配置文件時的名稱
			(UClass::ClassConstructorType)InternalConstructor<AMyActor>, 	//UClass對象內部構建函數指針,其實就是__DefaultConstructor方法
			(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<AMyActor>, 	//熱重載回調函數指針,__VTableCtorCaller方法
			&AMyActor::AddReferencedObjects, 				//添加引用對象的函數指針
			&AMyActor::Super::StaticClass, 					//獲取父類UClass對象指針的函數指針
			&AMyActor::WithinClass::StaticClass 			//UObjet的StaticClass方法
		); 
	} 
	return PrivateStaticClass; 
}

三、UClass的構造及註冊

void ConstructUClass(UClass*& OutClass, const FClassParams& Params)
{
	//如果UClass對象有效,且對象包含已構造標識符,則直接返回
	if (OutClass && (OutClass->ClassFlags & CLASS_Constructed)) { return; }	
	//執行依賴函數,創建構造該UClass依賴的父類UClass對象和UPackage包對象。
	for (UObject* (*const *SingletonFunc)() = Params.DependencySingletonFuncArray, *(*const *SingletonFuncEnd)() = SingletonFunc + Params.NumDependencySingletons; SingletonFunc != SingletonFuncEnd; ++SingletonFunc)
	{ (*SingletonFunc)(); }
	//獲取未註冊UClass對象
	UClass* NewClass = Params.ClassNoRegisterFunc();
	OutClass = NewClass;
	//如果獲取的UClass對象已經構造(包含構造完成標識符),則返回
	if (NewClass->ClassFlags & CLASS_Constructed) { return; }	
	//強制註冊類的UClass對象。將等待註冊的對象添加到延遲註冊。
	UObjectForceRegistration(NewClass);							
/**
	//UObjectForceRegistration的代碼爲:
	//獲取等待註冊表
	TMap<UObjectBase*, FPendingRegistrantInfo>& PendingRegistrants = FPendingRegistrantInfo::GetMap();	
	//在等待註冊表中查找是否存在該對象
	FPendingRegistrantInfo* Info = PendingRegistrants.Find(NewClass);
	//如果等待註冊表中存在該UClass對象等待被註冊則將其延遲註冊。
	if (Info)									
	{			
		const TCHAR* PackageName = Info->PackageName;		//獲取UClass對象所在包名
		const TCHAR* Name = Info->Name;						//獲取UClass名稱
		PendingRegistrants.Remove(NewClass);  				//先從等待註冊表中移除,防止重複註冊
		NewClass->DeferredRegister(UClass::StaticClass(),PackageName,Name);		//延遲註冊
	}
*/
	UClass* SuperClass = NewClass->GetSuperClass();	
	//如果父類標識符包含可繼承,則將其添加到當前類的標識符中
	if (SuperClass)	{ NewClass->ClassFlags |= (SuperClass->ClassFlags & CLASS_Inherit); }
	//將Params參數參數中的類標識符和已構造標識符添加到
	NewClass->ClassFlags |= (EClassFlags)(Params.ClassFlags | CLASS_Constructed);	
	// Make sure the reference token stream is empty since it will be reconstructed later on
	// This should not apply to intrinsic classes since they emit native references before AssembleReferenceTokenStream is called.
	if ((NewClass->ClassFlags & CLASS_Intrinsic) != CLASS_Intrinsic)
	{
		check((NewClass->ClassFlags & CLASS_TokenStreamAssembled) != CLASS_TokenStreamAssembled);
		NewClass->ReferenceTokenStream.Empty();
	}
	//創建成員函數鏈接表。構造(獲取)成員函數的UFunction指針,形成鏈表並將UFunction對象保存到函數表(FuncMap)。
	//FindFunction函數即是調用FuncMap,通過函數名進行查找。
	NewClass->CreateLinkAndAddChildFunctionsToMap(Params.FunctionLinkArray, Params.NumFunctions);
	//構造成員屬性,下節分析
	ConstructUProperties(NewClass, Params.PropertyArray, Params.NumProperties);
	//設置配置目錄名,如果沒有設置的話,一般爲類名
	if (Params.ClassConfigNameUTF8) { NewClass->ClassConfigName = FName(UTF8_TO_TCHAR(Params.ClassConfigNameUTF8)); }
	//設置類型信息,是否是抽象類
	NewClass->SetCppTypeInfoStatic(Params.CppClassInfo);
	//遍歷類實現的接口,並獲取它們的UClass對象,將其添加到此類UClass對象中。
	if (int32 NumImplementedInterfaces = Params.NumImplementedInterfaces)
	{
		NewClass->Interfaces.Reserve(NumImplementedInterfaces);
		for (const FImplementedInterfaceParams* ImplementedInterface = Params.ImplementedInterfaceArray, *ImplementedInterfaceEnd = ImplementedInterface + NumImplementedInterfaces; ImplementedInterface != ImplementedInterfaceEnd; ++ImplementedInterface)
		{
			UClass* (*ClassFunc)() = ImplementedInterface->ClassFunc;
			UClass* InterfaceClass = ClassFunc ? ClassFunc() : nullptr;

			NewClass->Interfaces.Emplace(InterfaceClass, ImplementedInterface->Offset, ImplementedInterface->bImplementedByK2);
		}
	}

#if WITH_METADATA	//設置UClass對象的元數據
	AddMetaData(NewClass, Params.MetaDataArray, Params.NumMetaData);
#endif
	//創建屬性鏈接和獲取它們的結構,在運行時使用
	NewClass->StaticLink();

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