UE4中C++类型生成文件分析

反射类型分析,生成文件分析

Posted by bbkgl on February 7, 2021

我有故人抱剑去

斩尽春风未肯归

要解释UE4 C++中的反射,很难不讲或者少讲生成文件(*.generated.h 和 *.gen.cpp)。这是对于开发者来说,最直接能接触到的部分,也是引擎中C++动态实现的直接表现部分。

因为生成代码中有大量的宏,初见时觉得这不是给人看的23333。。。

但一点点跟着知乎上的教程,还是硬着头皮啃下来了,然后一一展开所有宏,揭开这个反射系统最外层的面纱。

本文仅对提供简单的例子对类型生成文件进行解释,详细的生成文件的解析可以参考 UE4 UObject反射系列 以及 Inside UE4

生成文件展开

简单的示例类

首先在UE4中新建一个类,继承自UObject,名字应该尽量短。。。否则会造成阅读困难,眼花缭乱。

HH.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "HH.generated.h"

/**
 * 
 */
UCLASS()
class CCREFLECTION_API UHH : public UObject
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable)
	int HHFunc(int a);

	UPROPERTY()
	int HHID;
	
};

HH.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "HH.h"

int UHH::HHFunc(int a)
{
}

GENERATED_BODY() 宏进行了拼接。

   GENERATED_BODY()
-> BODY_MACRO_COMBINE()
...
-> CURRENT_FILE_ID##_##__LINE__##_GENERATED_BODY

其中 CURRENT_FILE_ID*.generated.h 中定义。

1612949922211

所以GENERATED_BODY() 宏展开后即:

CCReflection_Source_CCReflection_HH_h_15_GENERATED_BODY

UCLASS()UFUNCTION()UPROPERTY() 的作用更多的是作为UHT分析代码的一种修饰标志,即表示被修饰的类、属性或者函数要支持反射。

HH.generated.h

分析生成文件的内容,首先是HH.generated.h。

HH.generated.h

#include "UObject/ObjectMacros.h"
#include "UObject/ScriptMacros.h"

PRAGMA_DISABLE_DEPRECATION_WARNINGS
#ifdef CCREFLECTION_HH_generated_h
#error "HH.generated.h already included, missing '#pragma once' in HH.h"
#endif
#define CCREFLECTION_HH_generated_h

#define CCReflection_Source_CCReflection_HH_h_15_SPARSE_DATA
#define CCReflection_Source_CCReflection_HH_h_15_RPC_WRAPPERS \
 \
	DECLARE_FUNCTION(execHHFunc);


#define CCReflection_Source_CCReflection_HH_h_15_RPC_WRAPPERS_NO_PURE_DECLS \
 \
	DECLARE_FUNCTION(execHHFunc);


#define CCReflection_Source_CCReflection_HH_h_15_INCLASS_NO_PURE_DECLS \
private: \
	static void StaticRegisterNativesUHH(); \
	friend struct Z_Construct_UClass_UHH_Statics; \
public: \
	DECLARE_CLASS(UHH, UObject, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/CCReflection"), NO_API) \
	DECLARE_SERIALIZER(UHH)


#define CCReflection_Source_CCReflection_HH_h_15_INCLASS \
private: \
	static void StaticRegisterNativesUHH(); \
	friend struct Z_Construct_UClass_UHH_Statics; \
public: \
	DECLARE_CLASS(UHH, UObject, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/CCReflection"), NO_API) \
	DECLARE_SERIALIZER(UHH)


#define CCReflection_Source_CCReflection_HH_h_15_STANDARD_CONSTRUCTORS \
	/** Standard constructor, called after all reflected properties have been initialized */ \
	NO_API UHH(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \
	DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UHH) \
	DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UHH); \
DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UHH); \
private: \
	/** Private move- and copy-constructors, should never be used */ \
	NO_API UHH(UHH&&); \
	NO_API UHH(const UHH&); \
public:


#define CCReflection_Source_CCReflection_HH_h_15_ENHANCED_CONSTRUCTORS \
	/** Standard constructor, called after all reflected properties have been initialized */ \
	NO_API UHH(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \
private: \
	/** Private move- and copy-constructors, should never be used */ \
	NO_API UHH(UHH&&); \
	NO_API UHH(const UHH&); \
public: \
	DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UHH); \
DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UHH); \
	DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UHH)


#define CCReflection_Source_CCReflection_HH_h_15_PRIVATE_PROPERTY_OFFSET
#define CCReflection_Source_CCReflection_HH_h_12_PROLOG
#define CCReflection_Source_CCReflection_HH_h_15_GENERATED_BODY_LEGACY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
	CCReflection_Source_CCReflection_HH_h_15_PRIVATE_PROPERTY_OFFSET \
	CCReflection_Source_CCReflection_HH_h_15_SPARSE_DATA \
	CCReflection_Source_CCReflection_HH_h_15_RPC_WRAPPERS \
	CCReflection_Source_CCReflection_HH_h_15_INCLASS \
	CCReflection_Source_CCReflection_HH_h_15_STANDARD_CONSTRUCTORS \
public: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS


#define CCReflection_Source_CCReflection_HH_h_15_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
	CCReflection_Source_CCReflection_HH_h_15_PRIVATE_PROPERTY_OFFSET \
	CCReflection_Source_CCReflection_HH_h_15_SPARSE_DATA \
	CCReflection_Source_CCReflection_HH_h_15_RPC_WRAPPERS_NO_PURE_DECLS \
	CCReflection_Source_CCReflection_HH_h_15_INCLASS_NO_PURE_DECLS \
	CCReflection_Source_CCReflection_HH_h_15_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS


template<> CCREFLECTION_API UClass* StaticClass<class UHH>();

#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID CCReflection_Source_CCReflection_HH_h

PRAGMA_ENABLE_DEPRECATION_WARNINGS

前面提到的GENERATED_BODY() 宏展开的结果就在该生成文件第79行,其再次展开后得到如下宏:

#define CCReflection_Source_CCReflection_HH_h_15_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
	CCReflection_Source_CCReflection_HH_h_15_PRIVATE_PROPERTY_OFFSET \
	CCReflection_Source_CCReflection_HH_h_15_SPARSE_DATA \
	CCReflection_Source_CCReflection_HH_h_15_RPC_WRAPPERS_NO_PURE_DECLS \
	CCReflection_Source_CCReflection_HH_h_15_INCLASS_NO_PURE_DECLS \
	CCReflection_Source_CCReflection_HH_h_15_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS

将这些宏一一分析:

CCReflection_Source_CCReflection_HH_h_15_PRIVATE_PROPERTY_OFFSET
CCReflection_Source_CCReflection_HH_h_15_SPARSE_DATA

以上这两个宏为空,略过。

展开 CCReflection_Source_CCReflection_HH_h_15_RPC_WRAPPERS_NO_PURE_DECLS 如下:

CCReflection_Source_CCReflection_HH_h_15_RPC_WRAPPERS_NO_PURE_DECLS
-> DECLARE_FUNCTION(execHHFunc);
-> static void execHHFunc( UObject* Context, FFrame& Stack, RESULT_DECL );
-> static void execHHFunc( UObject* Context, FFrame& Stack, void *const Z_Param__Result);

展开 CCReflection_Source_CCReflection_HH_h_15_INCLASS_NO_PURE_DECLS 稍微麻烦,一步步展开如下:

private: \
	static void StaticRegisterNativesUHH(); \
	friend struct Z_Construct_UClass_UHH_Statics; \
public: \
	DECLARE_CLASS(UHH, UObject, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/CCReflection"), NO_API) \
	DECLARE_SERIALIZER(UHH)

首先将 DECLARE_CLASS 展开:

DECLARE_CLASS(UHH, UObject, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/CCReflection"), NO_API)
-> 
private: \
    UHH& operator=(UHH&&);   \
    UHH& operator=(const UHH&);   \
	NO_API static UClass* GetPrivateStaticClass(); \
public: \
	/** Bitwise union of #EClassFlags pertaining to this class.*/ \
	enum {StaticClassFlags=COMPILED_IN_FLAGS(0)}; \
	/** Typedef for the base class () */ \
	typedef UObject Super;\
	/** Typedef for . */ \
	typedef UHH ThisClass;\
	/** Returns a UClass object representing this class at runtime */ \
	inline static UClass* StaticClass() \
	{ \
		return GetPrivateStaticClass(); \
	} \
	/** Returns the package this class belongs in */ \
	inline static const TCHAR* StaticPackage() \
	{ \
		return TEXT("/Script/CCReflection"); \
	} \
	/** Returns the static cast flags for this class */ \
	inline static EClassCastFlags StaticClassCastFlags() \
	{ \
		return CASTCLASS_None; \
	} \
	/** For internal use only; use StaticConstructObject() to create new objects. */ \
	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); \
	} \
	/** For internal use only; use StaticConstructObject() to create new objects. */ \
	inline void* operator new( const size_t InSize, EInternal* InMem ) \
	{ \
		return (void*)InMem; \
	}

然后是DECLARE_SERIALIZER 展开:

	DECLARE_SERIALIZER(UHH)
->
    friend FArchive &operator<<( FArchive& Ar, UHH*& Res ) \
	{ \
		return Ar << (UObject*&)Res; \
	} \
	friend void operator<<(FStructuredArchive::FSlot InSlot, UHH*& Res) \
	{ \
		InSlot << (UObject*&)Res; \
	}

最后是 CCReflection_Source_CCReflection_HH_h_15_ENHANCED_CONSTRUCTORS

#define CCReflection_Source_CCReflection_HH_h_15_ENHANCED_CONSTRUCTORS \	
/** Standard constructor, called after all reflected properties have been initialized */ \
	NO_API UHH(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \
private: \
	/** Private move- and copy-constructors, should never be used */ \
	NO_API UHH(UHH&&); \
	NO_API UHH(const UHH&); \
public: \
	DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UHH); \
DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UHH); \
	DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UHH)

-> 
    NO_API UHH(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \
private: \
	/** Private move- and copy-constructors, should never be used */ \
	NO_API UHH(UHH&&); \
	NO_API UHH(const UHH&); \
public: \
	NO_API UHH(FVTableHelper& Helper);
	static UObject* __VTableCtorCaller(FVTableHelper& Helper) \
	{ \
		return new (EC_InternalUseOnlyConstructor, (UObject*)GetTransientPackage(), NAME_None, RF_NeedLoad | RF_ClassDefaultObject | RF_TagGarbageTemp) UHH(Helper); \
	}
	static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())UHH(X); }

将这些部分进行合并,得到将 GENERATED_BODY() 宏完全展开的 HH.h 文件如下。

UCLASS()
class CCREFLECTION_API UHH : public UObject
{
	PRAGMA_DISABLE_DEPRECATION_WARNINGS
public:
	static void execHHFunc( UObject* Context, FFrame& Stack, void *const Z_Param__Result);
	static void execHHFunc( UObject* Context, FFrame& Stack, void *const Z_Param__Result);
private:
	PRAGMA_ENABLE_DEPRECATION_WARNINGS

private:
	static void StaticRegisterNativesUHH();
	friend struct Z_Construct_UClass_UHH_Statics;
public:
	private:
    UHH& operator=(UHH&&); 
    UHH& operator=(const UHH&); 
	NO_API static UClass* GetPrivateStaticClass(); 
public:  
	/** Bitwise union of #EClassFlags pertaining to this class.*/  
	enum {StaticClassFlags=COMPILED_IN_FLAGS(0)};  
	/** Typedef for the base class () */  
	typedef UObject Super; 
	/** Typedef for . */  
	typedef UHH ThisClass; 
	/** Returns a UClass object representing this class at runtime */  
	inline static UClass* StaticClass()  
	{  
		return GetPrivateStaticClass();  
	}  
	/** Returns the package this class belongs in */  
	inline static const TCHAR* StaticPackage()  
	{  
		return TEXT("/Script/CCReflection");  
	}  
	/** Returns the static cast flags for this class */  
	inline static EClassCastFlags StaticClassCastFlags()  
	{  
		return CASTCLASS_None;  
	}  
	/** For internal use only; use StaticConstructObject() to create new objects. */  
	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);  
	}  
	/** For internal use only; use StaticConstructObject() to create new objects. */  
	inline void* operator new( const size_t InSize, EInternal* InMem )  
	{  
		return (void*)InMem;  
	}

	friend FArchive &operator<<( FArchive& Ar, UHH*& Res ) \
	{ \
		return Ar << (UObject*&)Res; \
	} \
	friend void operator<<(FStructuredArchive::FSlot InSlot, UHH*& Res) \
	{ \
		InSlot << (UObject*&)Res; \
	}
	
	NO_API UHH(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \
private: \
	/** Private move- and copy-constructors, should never be used */ \
	NO_API UHH(UHH&&); \
	NO_API UHH(const UHH&); \
public: \
	NO_API UHH(FVTableHelper& Helper);
	static UObject* __VTableCtorCaller(FVTableHelper& Helper) \
	{ \
		return new (EC_InternalUseOnlyConstructor, (UObject*)GetTransientPackage(), NAME_None, RF_NeedLoad | RF_ClassDefaultObject | RF_TagGarbageTemp) UHH(Helper); \
	}
	static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())UHH(X); }

public:
	UFUNCTION(BlueprintCallable)
	int HHFunc(int a);

	UPROPERTY()
	int HHID;
};

HH.gen.cpp

接下来分析HH.gen.cpp。

HH.gen.cpp

#include "UObject/GeneratedCppIncludes.h"
#include "CCReflection/HH.h"
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable : 4883)
#endif
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCodeHH() {}
// Cross Module References
	CCREFLECTION_API UClass* Z_Construct_UClass_UHH_NoRegister();
	CCREFLECTION_API UClass* Z_Construct_UClass_UHH();
	COREUOBJECT_API UClass* Z_Construct_UClass_UObject();
	UPackage* Z_Construct_UPackage__Script_CCReflection();
// End Cross Module References
	DEFINE_FUNCTION(UHH::execHHFunc)
	{
		P_GET_PROPERTY(FIntProperty,Z_Param_a);
		P_FINISH;
		P_NATIVE_BEGIN;
		*(int32*)Z_Param__Result=P_THIS->HHFunc(Z_Param_a);
		P_NATIVE_END;
	}
	void UHH::StaticRegisterNativesUHH()
	{
		UClass* Class = UHH::StaticClass();
		static const FNameNativePtrPair Funcs[] = {
			{ "HHFunc", &UHH::execHHFunc },
		};
		FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, UE_ARRAY_COUNT(Funcs));
	}
	struct Z_Construct_UFunction_UHH_HHFunc_Statics
	{
		struct HH_eventHHFunc_Parms
		{
			int32 a;
			int32 ReturnValue;
		};
		static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_a;
		static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_ReturnValue;
		static const UE4CodeGen_Private::FPropertyParamsBase* const PropPointers[];
#if WITH_METADATA
		static const UE4CodeGen_Private::FMetaDataPairParam Function_MetaDataParams[];
#endif
		static const UE4CodeGen_Private::FFunctionParams FuncParams;
	};
	const UE4CodeGen_Private::FUnsizedIntPropertyParams Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_a = { "a", nullptr, (EPropertyFlags)0x0010000000000080, UE4CodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, 1, STRUCT_OFFSET(HH_eventHHFunc_Parms, a), METADATA_PARAMS(nullptr, 0) };
	const UE4CodeGen_Private::FUnsizedIntPropertyParams Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_ReturnValue = { "ReturnValue", nullptr, (EPropertyFlags)0x0010000000000580, UE4CodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, 1, STRUCT_OFFSET(HH_eventHHFunc_Parms, ReturnValue), METADATA_PARAMS(nullptr, 0) };
	const UE4CodeGen_Private::FPropertyParamsBase* const Z_Construct_UFunction_UHH_HHFunc_Statics::PropPointers[] = {
		(const UE4CodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_a,
		(const UE4CodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_ReturnValue,
	};
#if WITH_METADATA
	const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UFunction_UHH_HHFunc_Statics::Function_MetaDataParams[] = {
		{ "ModuleRelativePath", "HH.h" },
	};
#endif
	const UE4CodeGen_Private::FFunctionParams Z_Construct_UFunction_UHH_HHFunc_Statics::FuncParams = { (UObject*(*)())Z_Construct_UClass_UHH, nullptr, "HHFunc", nullptr, nullptr, sizeof(HH_eventHHFunc_Parms), Z_Construct_UFunction_UHH_HHFunc_Statics::PropPointers, UE_ARRAY_COUNT(Z_Construct_UFunction_UHH_HHFunc_Statics::PropPointers), RF_Public|RF_Transient|RF_MarkAsNative, (EFunctionFlags)0x04020401, 0, 0, METADATA_PARAMS(Z_Construct_UFunction_UHH_HHFunc_Statics::Function_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UFunction_UHH_HHFunc_Statics::Function_MetaDataParams)) };
	UFunction* Z_Construct_UFunction_UHH_HHFunc()
	{
		static UFunction* ReturnFunction = nullptr;
		if (!ReturnFunction)
		{
			UE4CodeGen_Private::ConstructUFunction(ReturnFunction, Z_Construct_UFunction_UHH_HHFunc_Statics::FuncParams);
		}
		return ReturnFunction;
	}
	UClass* Z_Construct_UClass_UHH_NoRegister()
	{
		return UHH::StaticClass();
	}
	struct Z_Construct_UClass_UHH_Statics
	{
		static UObject* (*const DependentSingletons[])();
		static const FClassFunctionLinkInfo FuncInfo[];
#if WITH_METADATA
		static const UE4CodeGen_Private::FMetaDataPairParam Class_MetaDataParams[];
#endif
#if WITH_METADATA
		static const UE4CodeGen_Private::FMetaDataPairParam NewProp_HHID_MetaData[];
#endif
		static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_HHID;
		static const UE4CodeGen_Private::FPropertyParamsBase* const PropPointers[];
		static const FCppClassTypeInfoStatic StaticCppClassTypeInfo;
		static const UE4CodeGen_Private::FClassParams ClassParams;
	};
	UObject* (*const Z_Construct_UClass_UHH_Statics::DependentSingletons[])() = {
		(UObject* (*)())Z_Construct_UClass_UObject,
		(UObject* (*)())Z_Construct_UPackage__Script_CCReflection,
	};
	const FClassFunctionLinkInfo Z_Construct_UClass_UHH_Statics::FuncInfo[] = {
		{ &Z_Construct_UFunction_UHH_HHFunc, "HHFunc" }, // 501624126
	};
#if WITH_METADATA
	const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UClass_UHH_Statics::Class_MetaDataParams[] = {
		{ "Comment", "/**\n * \n */" },
		{ "IncludePath", "HH.h" },
		{ "ModuleRelativePath", "HH.h" },
	};
#endif
#if WITH_METADATA
	const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData[] = {
		{ "ModuleRelativePath", "HH.h" },
	};
#endif
	const UE4CodeGen_Private::FUnsizedIntPropertyParams Z_Construct_UClass_UHH_Statics::NewProp_HHID = { "HHID", nullptr, (EPropertyFlags)0x0010000000000000, UE4CodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, 1, STRUCT_OFFSET(UHH, HHID), METADATA_PARAMS(Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData, UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData)) };
	const UE4CodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_UHH_Statics::PropPointers[] = {
		(const UE4CodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_UHH_Statics::NewProp_HHID,
	};
	const FCppClassTypeInfoStatic Z_Construct_UClass_UHH_Statics::StaticCppClassTypeInfo = {
		TCppClassTypeTraits<UHH>::IsAbstract,
	};
	const UE4CodeGen_Private::FClassParams Z_Construct_UClass_UHH_Statics::ClassParams = {
		&UHH::StaticClass,
		nullptr,
		&StaticCppClassTypeInfo,
		DependentSingletons,
		FuncInfo,
		Z_Construct_UClass_UHH_Statics::PropPointers,
		nullptr,
		UE_ARRAY_COUNT(DependentSingletons),
		UE_ARRAY_COUNT(FuncInfo),
		UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::PropPointers),
		0,
		0x001000A0u,
		METADATA_PARAMS(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams))
	};
	UClass* Z_Construct_UClass_UHH()
	{
		static UClass* OuterClass = nullptr;
		if (!OuterClass)
		{
			UE4CodeGen_Private::ConstructUClass(OuterClass, Z_Construct_UClass_UHH_Statics::ClassParams);
		}
		return OuterClass;
	}
	IMPLEMENT_CLASS(UHH, 1368286490);
	template<> CCREFLECTION_API UClass* StaticClass<UHH>()
	{
		return UHH::StaticClass();
	}
	static FCompiledInDefer Z_CompiledInDefer_UClass_UHH(Z_Construct_UClass_UHH, &UHH::StaticClass, TEXT("/Script/CCReflection"), TEXT("UHH"), false, nullptr, nullptr, nullptr);
	DEFINE_VTABLE_PTR_HELPER_CTOR(UHH);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
#ifdef _MSC_VER
#pragma warning (pop)
#endif

看上去很复杂,从上往下,一步步展开宏。

首先是 DEFINE_FUNCTION(UHH::execHHFunc)

DEFINE_FUNCTION(UHH::execHHFunc)
{
    P_GET_PROPERTY(FIntProperty,Z_Param_a);
    P_FINISH;
    P_NATIVE_BEGIN;
    *(int32*)Z_Param__Result=P_THIS->HHFunc(Z_Param_a);
    P_NATIVE_END;
}
-> 
static void execHHFunc( UObject* Context, FFrame& Stack, void *const Z_Param__Result) 
{
    FIntProperty::TCppType Z_Param_a = FIntProperty::GetDefaultPropertyValue();
    Stack.StepCompiledIn<FIntProperty>(&Z_Param_a);
    
    Stack.Code += !!Stack.Code;
    { 
        SCOPED_SCRIPT_NATIVE_TIMER(ScopedNativeCallTimer);
        *(int32*)Z_Param__Result = (ThisClass *) Context->HHFunc(Z_Param_a);
    }
}

其中 ThisClass 前面展开的 HH.generated.h 中已经设置为 UHH 的别名了。

DEFINE_FUNCTION(UHH::execHHFunc)
{
    P_GET_PROPERTY(FIntProperty,Z_Param_a);
    P_FINISH;
    P_NATIVE_BEGIN;
    *(int32*)Z_Param__Result=P_THIS->HHFunc(Z_Param_a);
    P_NATIVE_END;
}
-> 
static void execHHFunc( UObject* Context, FFrame& Stack, void *const Z_Param__Result) 
{
    FIntProperty::TCppType Z_Param_a = FIntProperty::GetDefaultPropertyValue();
    Stack.StepCompiledIn<FIntProperty>(&Z_Param_a);
    
    Stack.Code += !!Stack.Code;
    { 
        SCOPED_SCRIPT_NATIVE_TIMER(ScopedNativeCallTimer);
        *(int32*)Z_Param__Result = (UHH *) Context->HHFunc(Z_Param_a);
    }
}

接下来的宏就是 IMPLEMENT_CLASS(UHH, 1368286490);

展开过程:

IMPLEMENT_CLASS(UHH, 1368286490);

-> 

static UHHCompiledInDefer<UHH> AutoInitialize##UHH(TEXT(#UHH), sizeof(UHH), 1368286490); \
UClass* UHH::GetPrivateStaticClass() \
{ \
	static UClass* PrivateStaticClass = NULL; \
	if (!PrivateStaticClass) \
	{ \
		/* this could be handled with templates, but we want it external to avoid code bloat */ \
		GetPrivateStaticClassBody( \
			StaticPackage(), \
			(TCHAR*)TEXT(#UHH) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), \
			PrivateStaticClass, \
			StaticRegisterNatives##UHH, \
			sizeof(UHH), \
			alignof(UHH), \
			(EClassFlags)UHH::StaticClassFlags, \
			UHH::StaticClassCastFlags(), \
			UHH::StaticConfigName(), \
			(UClass::ClassConstructorType)InternalConstructor<UHH>, \
			(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<UHH>, \
			&UHH::AddReferencedObjects, \
			&UHH::Super::StaticClass, \
			&UHH::WithinClass::StaticClass \
		); \
	} \
	return PrivateStaticClass; \
}

-> 

static UHHCompiledInDefer<UHH> AutoInitializeUHH(TEXT("UHH"), sizeof(UHH), 1368286490); 
UClass* UHH::GetPrivateStaticClass() 
{ 
	static UClass* PrivateStaticClass = NULL; 
	if (!PrivateStaticClass) 
	{ 
		/* this could be handled with templates, but we want it external to avoid code bloat */ 
		GetPrivateStaticClassBody( 
			StaticPackage(), 
			(TCHAR*)TEXT("UHH") + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), 
			PrivateStaticClass, 
			StaticRegisterNativesUHH, 
			sizeof(UHH), 
			alignof(UHH), 
			(EClassFlags)UHH::StaticClassFlags, 
			UHH::StaticClassCastFlags(), 
			UHH::StaticConfigName(), 
			(UClass::ClassConstructorType)InternalConstructor<UHH>, 
			(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<UHH>, 
			&UHH::AddReferencedObjects, 
			&UHH::Super::StaticClass, 
			&UHH::WithinClass::StaticClass 
		); 
	} 
	return PrivateStaticClass; 
}

最后剩下 DEFINE_VTABLE_PTR_HELPER_CTOR(UHH);

DEFINE_VTABLE_PTR_HELPER_CTOR(UHH);
-> 
UHH::UHH(FVTableHelper& Helper) : Super(Helper) {};

这里有两个别名定义,其中 Super 就是 UObject,而 ThisClass 就是 UHH

1613034703155

这样HH.gen.cpp的宏就全部展开了。

得到完整文件如下:

#include "UObject/GeneratedCppIncludes.h"
#include "CCReflection/HH.h"
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable : 4883)
#endif
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCodeHH() {}
// Cross Module References
	CCREFLECTION_API UClass* Z_Construct_UClass_UHH_NoRegister();
	CCREFLECTION_API UClass* Z_Construct_UClass_UHH();
	COREUOBJECT_API UClass* Z_Construct_UClass_UObject();
	UPackage* Z_Construct_UPackage__Script_CCReflection();
// End Cross Module References

static void execHHFunc( UObject* Context, FFrame& Stack, void *const Z_Param__Result) 
{
    FIntProperty::TCppType Z_Param_a = FIntProperty::GetDefaultPropertyValue();
    Stack.StepCompiledIn<FIntProperty>(&Z_Param_a);
    
    Stack.Code += !!Stack.Code;
    { 
        SCOPED_SCRIPT_NATIVE_TIMER(ScopedNativeCallTimer);
        *(int32*)Z_Param__Result = (UHH *) Context->HHFunc(Z_Param_a);
    }
}

void UHH::StaticRegisterNativesUHH()
{
	UClass* Class = UHH::StaticClass();
	static const FNameNativePtrPair Funcs[] = {
		{ "HHFunc", &UHH::execHHFunc },
	};
	FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, UE_ARRAY_COUNT(Funcs));
}
struct Z_Construct_UFunction_UHH_HHFunc_Statics
{
	struct HH_eventHHFunc_Parms
	{
		int32 a;
		int32 ReturnValue;
	};
	static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_a;
	static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_ReturnValue;
	static const UE4CodeGen_Private::FPropertyParamsBase* const PropPointers[];
#if WITH_METADATA
	static const UE4CodeGen_Private::FMetaDataPairParam Function_MetaDataParams[];
#endif
	static const UE4CodeGen_Private::FFunctionParams FuncParams;
};
const UE4CodeGen_Private::FUnsizedIntPropertyParams Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_a = { "a", nullptr, (EPropertyFlags)0x0010000000000080, UE4CodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, 1, STRUCT_OFFSET(HH_eventHHFunc_Parms, a), METADATA_PARAMS(nullptr, 0) };
const UE4CodeGen_Private::FUnsizedIntPropertyParams Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_ReturnValue = { "ReturnValue", nullptr, (EPropertyFlags)0x0010000000000580, UE4CodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, 1, STRUCT_OFFSET(HH_eventHHFunc_Parms, ReturnValue), METADATA_PARAMS(nullptr, 0) };
const UE4CodeGen_Private::FPropertyParamsBase* const Z_Construct_UFunction_UHH_HHFunc_Statics::PropPointers[] = {
	(const UE4CodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_a,
	(const UE4CodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UHH_HHFunc_Statics::NewProp_ReturnValue,
};
#if WITH_METADATA
const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UFunction_UHH_HHFunc_Statics::Function_MetaDataParams[] = {
	{ "ModuleRelativePath", "HH.h" },
};
#endif
const UE4CodeGen_Private::FFunctionParams Z_Construct_UFunction_UHH_HHFunc_Statics::FuncParams = { (UObject*(*)())Z_Construct_UClass_UHH, nullptr, "HHFunc", nullptr, nullptr, sizeof(HH_eventHHFunc_Parms), Z_Construct_UFunction_UHH_HHFunc_Statics::PropPointers, UE_ARRAY_COUNT(Z_Construct_UFunction_UHH_HHFunc_Statics::PropPointers), RF_Public|RF_Transient|RF_MarkAsNative, (EFunctionFlags)0x04020401, 0, 0, METADATA_PARAMS(Z_Construct_UFunction_UHH_HHFunc_Statics::Function_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UFunction_UHH_HHFunc_Statics::Function_MetaDataParams)) };
UFunction* Z_Construct_UFunction_UHH_HHFunc()
{
	static UFunction* ReturnFunction = nullptr;
	if (!ReturnFunction)
	{
		UE4CodeGen_Private::ConstructUFunction(ReturnFunction, Z_Construct_UFunction_UHH_HHFunc_Statics::FuncParams);
	}
	return ReturnFunction;
}
UClass* Z_Construct_UClass_UHH_NoRegister()
{
	return UHH::StaticClass();
}
struct Z_Construct_UClass_UHH_Statics
{
	static UObject* (*const DependentSingletons[])();
	static const FClassFunctionLinkInfo FuncInfo[];
#if WITH_METADATA
	static const UE4CodeGen_Private::FMetaDataPairParam Class_MetaDataParams[];
#endif
#if WITH_METADATA
	static const UE4CodeGen_Private::FMetaDataPairParam NewProp_HHID_MetaData[];
#endif
	static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_HHID;
	static const UE4CodeGen_Private::FPropertyParamsBase* const PropPointers[];
	static const FCppClassTypeInfoStatic StaticCppClassTypeInfo;
	static const UE4CodeGen_Private::FClassParams ClassParams;
};
UObject* (*const Z_Construct_UClass_UHH_Statics::DependentSingletons[])() = {
	(UObject* (*)())Z_Construct_UClass_UObject,
	(UObject* (*)())Z_Construct_UPackage__Script_CCReflection,
};
const FClassFunctionLinkInfo Z_Construct_UClass_UHH_Statics::FuncInfo[] = {
	{ &Z_Construct_UFunction_UHH_HHFunc, "HHFunc" }, // 501624126
};
#if WITH_METADATA
const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UClass_UHH_Statics::Class_MetaDataParams[] = {
	{ "Comment", "/**\n * \n */" },
	{ "IncludePath", "HH.h" },
	{ "ModuleRelativePath", "HH.h" },
};
#endif
#if WITH_METADATA
const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData[] = {
	{ "ModuleRelativePath", "HH.h" },
};
#endif
const UE4CodeGen_Private::FUnsizedIntPropertyParams Z_Construct_UClass_UHH_Statics::NewProp_HHID = { "HHID", nullptr, (EPropertyFlags)0x0010000000000000, UE4CodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, 1, STRUCT_OFFSET(UHH, HHID), METADATA_PARAMS(Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData, UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData)) };
const UE4CodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_UHH_Statics::PropPointers[] = {
	(const UE4CodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_UHH_Statics::NewProp_HHID,
};
const FCppClassTypeInfoStatic Z_Construct_UClass_UHH_Statics::StaticCppClassTypeInfo = {
	TCppClassTypeTraits<UHH>::IsAbstract,
};
const UE4CodeGen_Private::FClassParams Z_Construct_UClass_UHH_Statics::ClassParams = {
	&UHH::StaticClass,
	nullptr,
	&StaticCppClassTypeInfo,
	DependentSingletons,
	FuncInfo,
	Z_Construct_UClass_UHH_Statics::PropPointers,
	nullptr,
	UE_ARRAY_COUNT(DependentSingletons),
	UE_ARRAY_COUNT(FuncInfo),
	UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::PropPointers),
	0,
	0x001000A0u,
	METADATA_PARAMS(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams))
};
UClass* Z_Construct_UClass_UHH()
{
	static UClass* OuterClass = nullptr;
	if (!OuterClass)
	{
		UE4CodeGen_Private::ConstructUClass(OuterClass, Z_Construct_UClass_UHH_Statics::ClassParams);
	}
	return OuterClass;
}

static UHHCompiledInDefer<UHH> AutoInitializeUHH(TEXT("UHH"), sizeof(UHH), 1368286490); 
UClass* UHH::GetPrivateStaticClass() 
{ 
	static UClass* PrivateStaticClass = NULL; 
	if (!PrivateStaticClass) 
	{ 
		/* this could be handled with templates, but we want it external to avoid code bloat */ 
		GetPrivateStaticClassBody( 
			StaticPackage(), 
			(TCHAR*)TEXT("UHH") + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), 
			PrivateStaticClass, 
			StaticRegisterNativesUHH, 
			sizeof(UHH), 
			alignof(UHH), 
			(EClassFlags)UHH::StaticClassFlags, 
			UHH::StaticClassCastFlags(), 
			UHH::StaticConfigName(), 
			(UClass::ClassConstructorType)InternalConstructor<UHH>, 
			(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<UHH>, 
			&UHH::AddReferencedObjects, 
			&UHH::Super::StaticClass, 
			&UHH::WithinClass::StaticClass 
		); 
	} 
	return PrivateStaticClass; 
}

template<> CCREFLECTION_API UClass* StaticClass<UHH>()
{
	return UHH::StaticClass();
}
static FCompiledInDefer Z_CompiledInDefer_UClass_UHH(Z_Construct_UClass_UHH, &UHH::StaticClass, TEXT("/Script/CCReflection"), TEXT("UHH"), false, nullptr, nullptr, nullptr);

UHH::UHH(FVTableHelper& Helper) : Super(Helper) {};

PRAGMA_ENABLE_DEPRECATION_WARNINGS
#ifdef _MSC_VER
#pragma warning (pop)
#endif

可能会有漏的,但是重要的部分应该是不会错的。

这样生成文件就全部展开完了。

生成文件解析

接下来对生成的部分进行一一的解析,需要将头文件和源文件联系起来。

将反射的整个注册过程按照数据的走向进行分解,希望尽量把这个过程讲明白,由于篇幅和精力受限,就不对各个类型进行详细举例了,读者可以按照同样的套路进行尝试,其他的类型也都是大同小异的。

属性 / UPROPERTY

之前在HH.h中定义了一个属性 HHID,同样可以在生成文件中找到,并以此为线索,找到通过 HHID 生成的NewProp_HHID

1613036829812

贴出完整代码:

const UE4CodeGen_Private::FUnsizedIntPropertyParams Z_Construct_UClass_UHH_Statics::NewProp_HHID = { "HHID", nullptr, (EPropertyFlags)0x0010000000000000, UE4CodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, 1, STRUCT_OFFSET(UHH, HHID), METADATA_PARAMS(Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData, UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::NewProp_HHID_MetaData)) };
const UE4CodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_UHH_Statics::PropPointers[] = {
	(const UE4CodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_UHH_Statics::NewProp_HHID,
};

定义了一个 UE4CodeGen_Private::FUnsizedIntPropertyParams 类型的 NewProp_HHID ,随后又添加到了 Z_Construct_UClass_UHH_Statics::PropPointers 指针数组中。

1613037155754

Z_Construct_UClass_UHH_Statics::PropPointers 则作为参数传入,创建了 Z_Construct_UClass_UHH_Statics::ClassParams

此时肯定注意到了 Z_Construct_UClass_UHH_Statics 结构体,ClassParams 正是该结构体中的一个静态成员:

1613037320097

也就是说,属性最终会注册到 Z_Construct_UClass_UHH_Statics::ClassParams 中,关于结构体Z_Construct_UClass_UHH_Statics,先挖坑,后面和函数注册信息放一起接着讲。

成员函数 / UFUNCTION

函数 HHFunc 声明如下。

1613037582722

函数的注册是分两部分完成的,一个是注册函数名到函数指针的映射,另外就是函数签名信息的记录。

首先可以看到,UHT已经生成了一个前缀为 exec 的函数:

1613037702888

很显然,这是为了统一函数签名,并将不同函数签名的处理则封装在内部。

execHHFunc 注册的逻辑写在 StaticRegisterNativesUHH 中。

void UHH::StaticRegisterNativesUHH()
{
	UClass* Class = UHH::StaticClass();
	static const FNameNativePtrPair Funcs[] = {
		{ "HHFunc", &UHH::execHHFunc },
	};
	FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, UE_ARRAY_COUNT(Funcs));
}

目前来看,可以猜测到是一个映射,即 function name -> function pointer

在引擎代码中,一步步跳转,寻找映射最终存储的位置:

1613204948833

1613204982466

会 new 出一个 FNativeFunctionLookup 类型的 struct 实体,也就是将该实体添加到一个数组中。

/** This class's native functions. */
TArray<FNativeFunctionLookup> NativeFunctionLookupTable;

这里注释里一直提示是map,但实际存储是数组。。。有点懵,不过以我浅显的理解,一个类的函数其实不会太多,数组存储可能更省内存,用map性能提升也不大。。。该过程先折腾到这。

/** A struct that maps a string name to a native function */
struct FNativeFunctionLookup
{
	FName Name;
	FNativeFuncPtr Pointer;

	FNativeFunctionLookup(FName InName, FNativeFuncPtr InPointer)
		:	Name(InName)
		,	Pointer(InPointer)
	{}
};

接上面 UHH::StaticRegisterNativesUHH() 的函数讲。

UHH::StaticRegisterNativesUHH() 的函数指针会传给 UHH::GetPrivateStaticClass(),在GetPrivateStaticClassBody() 函数中调用。

void GetPrivateStaticClassBody(
	const TCHAR* PackageName,
	const TCHAR* Name,
	UClass*& ReturnClass,
	void(*RegisterNativeFunc)(),
	uint32 InSize,
	uint32 InAlignment,
	EClassFlags InClassFlags,
	EClassCastFlags InClassCastFlags,
	const TCHAR* InConfigName,
	UClass::ClassConstructorType InClassConstructor,
	UClass::ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,
	UClass::ClassAddReferencedObjectsType InClassAddReferencedObjects,
	UClass::StaticClassFunctionType InSuperClassFn,
	UClass::StaticClassFunctionType InWithinClassFn,
	bool bIsDynamic /*= false*/,
	UDynamicClass::DynamicClassInitializerType InDynamicClassInitializerFn /*= nullptr*/
	)
{
	...
	InitializePrivateStaticClass(
		InSuperClassFn(),
		ReturnClass,
		InWithinClassFn(),
		PackageName,
		Name
		);

	// Register the class's native functions.
	RegisterNativeFunc();
}

也就是说,在第一次调用 UHH::GetPrivateStaticClass() 的时候会注册函数,而UHH::GetPrivateStaticClass() 则是可以在 StaticClass() 函数中调用。

inline static UClass* StaticClass()  
{  
    return GetPrivateStaticClass();  
}  

这时候就会引出疑问,第一次调用StaticClass() 是在什么时候?这里再留下一个坑,后面文章一起讲。

接下来就是函数签名信息的收集,很明显能看到结构体 Z_Construct_UFunction_UHH_HHFunc_Statics

struct Z_Construct_UFunction_UHH_HHFunc_Statics
{
	struct HH_eventHHFunc_Parms
	{
		int32 a;
		int32 ReturnValue;
	};
	static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_a;
	static const UE4CodeGen_Private::FUnsizedIntPropertyParams NewProp_ReturnValue;
	static const UE4CodeGen_Private::FPropertyParamsBase* const PropPointers[];
#if WITH_METADATA
	static const UE4CodeGen_Private::FMetaDataPairParam Function_MetaDataParams[];
#endif
	static const UE4CodeGen_Private::FFunctionParams FuncParams;
};

该结构体存储了若干静态成员,形式与 Z_Construct_UClass_UHH_Statics 是一样的。同样观察参数及返回值信息的收集(代码太长,我就贴了截图,与上面完全展开的 HH.gen.cpp 的52-63行对应):

1613130799519

同样会将参数和返回值信息,存储到 Z_Construct_UFunction_UHH_HHFunc_Statics::PropPointers 指针数组中,最终还是会将所有信息的关联到 Z_Construct_UFunction_UHH_HHFunc_Statics::FuncParams 中,与之前属性信息收集保持一致。

函数 Z_Construct_UFunction_UHH_HHFunc() 中使用lazy静态创建(这种方式很常见)对象,Z_Construct_UFunction_UHH_HHFunc_Statics::FuncParams 则用于创建 UFUNCTION 对象。

UFunction* Z_Construct_UFunction_UHH_HHFunc()
{
	static UFunction* ReturnFunction = nullptr;
	if (!ReturnFunction)
	{
		UE4CodeGen_Private::ConstructUFunction(ReturnFunction, Z_Construct_UFunction_UHH_HHFunc_Statics::FuncParams);
	}
	return ReturnFunction;
}

函数 Z_Construct_UFunction_UHH_HHFunc() 的地址将会传入给 Z_Construct_UClass_UHH_Statics::FuncInfo 数组中(又见 Z_Construct_UClass_UHH_Statics 结构体):

const FClassFunctionLinkInfo Z_Construct_UClass_UHH_Statics::FuncInfo[] = {
	{ &Z_Construct_UFunction_UHH_HHFunc, "HHFunc" }, // 501624126
};

FuncInfo 则作为参数创建 Z_Construct_UClass_UHH_Statics::ClassParams

const UE4CodeGen_Private::FClassParams Z_Construct_UClass_UHH_Statics::ClassParams = {
	&UHH::StaticClass,
	nullptr,
	&StaticCppClassTypeInfo,
	DependentSingletons,
	FuncInfo,
	Z_Construct_UClass_UHH_Statics::PropPointers,
	nullptr,
	UE_ARRAY_COUNT(DependentSingletons),
	UE_ARRAY_COUNT(FuncInfo),
	UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::PropPointers),
	0,
	0x001000A0u,
	METADATA_PARAMS(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams))
};

到这里,读者肯定也注意到了,目前函数指针映射的收集和Z_Construct_UClass_UHH_Statics::ClassParams 没什么关系,而属性、函数参数及返回值信息的收集则会直接关联到 ClassParams 中。

于是就能确定,Z_Construct_UClass_UHH_Statics 结构体的信息会被注册到ClassParams 静态成员中,ClassParams 的处理就决定了信息收集的下一步走向。。。也算填了前面挖的坑。

静态成员 ClassParams

经过前面对属性以及成员函数的分析,不难看出,静态成员 ClassParams 非常关键,分析一下其结构体。

struct FClassParams
{
    UClass*                                   (*ClassNoRegisterFunc)();
    const char*                                 ClassConfigNameUTF8;
    const FCppClassTypeInfoStatic*              CppClassInfo;
    UObject*                           (*const *DependencySingletonFuncArray)();
    const FClassFunctionLinkInfo*               FunctionLinkArray;
    const FPropertyParamsBase* const*           PropertyArray;
    const FImplementedInterfaceParams*          ImplementedInterfaceArray;
    int32                                       NumDependencySingletons;
    int32                                       NumFunctions;
    int32                                       NumProperties;
    int32                                       NumImplementedInterfaces;
    uint32                                      ClassFlags; // EClassFlags
    #if WITH_METADATA
    const FMetaDataPairParam*                   MetaDataArray;
    int32                                       NumMetaData;
    #endif
};

再回忆下前面如何构造 ClassParams 对象的:

const UE4CodeGen_Private::FClassParams Z_Construct_UClass_UHH_Statics::ClassParams = {
	&UHH::StaticClass,
	nullptr,
	&StaticCppClassTypeInfo,
	DependentSingletons,
	FuncInfo,
	Z_Construct_UClass_UHH_Statics::PropPointers,
	nullptr,
	UE_ARRAY_COUNT(DependentSingletons),
	UE_ARRAY_COUNT(FuncInfo),
	UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::PropPointers),
	0,
	0x001000A0u,
	METADATA_PARAMS(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UClass_UHH_Statics::Class_MetaDataParams))
};

进行一一对应,目前关注的是:

  • 函数 UHH::StaticClass() 函数地址传给了 ClassNoRegisterFunc 指针
  • 函数签名信息数组 FuncInfo 传给了 FunctionLinkArray
  • 属性类型信息 Z_Construct_UClass_UHH_Statics::PropPointers 传给了 PropertyArray

其中 ClassNoRegisterFunc 函数指针,在后续分析中仍然会用到,不要忘记!

除了结构体内部对齐等细节问题,目前还剩下三个疑问:

  1. ` ClassParams 最终用于生成 UClass 对象吗?是的话,什么时候生成,在哪里生成?与调用 StaticClass() 返回 UClass` 对象是什么关系?
  2. 函数指针的收集是如何完成的?
  3. 如何利用两个全局静态变量的构造函数?

两个静态的全局变量直接在 HH.gen.cpp 定义。

static TClassCompiledInDefer<UHH> AutoInitializeUHH(TEXT("UHH"), sizeof(UHH), 1368286490); 

static FCompiledInDefer Z_CompiledInDefer_UClass_UHH(Z_Construct_UClass_UHH, &UHH::StaticClass, TEXT("/Script/CCReflection"), TEXT("UHH"), false, nullptr, nullptr, nullptr);

这个下篇再解释。

其他

1. 关于#if WITH_METADATA 宏?

HH.gen.cpp 中使用的 #if WITH_METADATA 宏判断后要执行的逻辑,均是用于在编辑器中显示,实际游戏发布不会有这些东西的。

1613136806140

1613137157396

2. 为什么存在__DefaultConstructor() 函数?

这是因为通过名字动态生成对象,而构造函数无法使用函数指针来直接指向,因此这里就用一个static函数包装一下,变成一个”平凡”的函数指针,而且所有类的签名一致,就可以在UClass里用一个函数指针里保存起来。

static void __DefaultConstructor(const FObjectInitializer& X) 
{
    new((EInternal*)X.GetObj())UHH(X); 
}

这是C++的placement new的使用。

同时引擎里 Class.h 也有对应的声明:

1613138715077

也就是定义了一个函数指针,用于指向__DefaultConstructor()

3. 函数 Z_Construct_UPackage__Script_CCReflection() 的实现在哪,和UPackage的关系?

其实生成文件除了 *.generated.h 和 *.gen.cpp 以外,每个Package还有一个 *.init.gen.cpp 文件。

1613197909002

于是可以得到函数 Z_Construct_UPackage__Script_CCReflection() 的实现:

UPackage* Z_Construct_UPackage__Script_CCReflection()
{
    static UPackage* ReturnPackage = nullptr;
    if (!ReturnPackage)
    {
        static const UE4CodeGen_Private::FPackageParams PackageParams = {
            "/Script/CCReflection",
            nullptr,
            0,
            PKG_CompiledIn | 0x00000000,
            0x14DC9842,
            0x0F2270C8,
            METADATA_PARAMS(nullptr, 0)
        };
        UE4CodeGen_Private::ConstructUPackage(ReturnPackage, PackageParams);
    }
    return ReturnPackage;
}

很显然这个函数就是生成一个 UPackage 对象。

而函数 Z_Construct_UPackage__Script_CCReflection() 最终也会被函数指针指向,并通过 ClassParams 对象被收集。读者按照上述的规律,就能发现这个过程。

void GetPrivateStaticClassBody(
	const TCHAR* PackageName,
	const TCHAR* Name,
	UClass*& ReturnClass,
	void(*RegisterNativeFunc)(),
	uint32 InSize,
	uint32 InAlignment,
	EClassFlags InClassFlags,
	EClassCastFlags InClassCastFlags,
	const TCHAR* InConfigName,
	UClass::ClassConstructorType InClassConstructor,
	UClass::ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,
	UClass::ClassAddReferencedObjectsType InClassAddReferencedObjects,
	UClass::StaticClassFunctionType InSuperClassFn,
	UClass::StaticClassFunctionType InWithinClassFn,
	bool bIsDynamic /*= false*/,
	UDynamicClass::DynamicClassInitializerType InDynamicClassInitializerFn /*= nullptr*/
	)
{}

而 Package 的名字,通过 UHH::StaticPackage()传入到 GetPrivateStaticClassBody() 中用于生成 UClass 对象。