本文以 UE5.4 为基准,剖析反射代码的生成内容和注册流程。
简介 UE5 的 C++ 需要各种宏来辅助开发,在编译时使用 UHT
工具扫描这些宏来生成 XXX.generated.h
和 XXX.gen.cpp
两个文件,接下来将分析UHT生成的文件,来学习反射具体做了什么。代码将会删减掉热更相关的内容,只关注核心逻辑。
反射代码 Enum 枚举的声明在C++中有三种方式,C风格、namespace、enum class。
1 2 3 4 5 6 enum class ECppForm { Regular, Namespaced, EnumClass };
为了减小本文篇幅,此处只看 enum class。在一个新文件中定义完该 enum class 后,进行构建。
1 2 3 4 5 6 UENUM (BlueprintType)enum class EMyEnumClass :uint8{ Enum1 UMETA (DisplayName = "DisplayInBlueprint" ) , Enum2, } ;
最终会生成 generated.h
和 gen.cpp
两个文件。
generated.h
的内容如下,仅仅只是一些模板全特化,便于开发。
1 2 3 4 5 6 7 #define FOREACH_ENUM_EMYENUMCLASS(op) \ op(EMyEnumClass::Enum1) \ op(EMyEnumClass::Enum2) enum class EMyEnumClass : uint8;template <> struct TIsUEnumClass <EMyEnumClass> { enum { Value = true }; };template <> REFLECTION_API UEnum* StaticEnum <EMyEnumClass>();
gen.cpp
的内容偏多,将从上往下进行注释讲解。
1 2 void EmptyLinkFunctionForGeneratedCodeMyEnumClass () {}
前置声明,内部构建 UEnum 和 UPackage。 UPackage 是个代码包,会将同一模块内的所有反射类组织到一起 。反射的代码都是以 Z_
开头,因为 Z
是字母最后一位,避免代码提示里提示过靠前。
1 2 3 4 REFLECTION_API UEnum* Z_Construct_UEnum_Reflection_EMyEnumClass () ;UPackage* Z_Construct_UPackage__Script_Reflection () ;
此处才是真正对外构建 UEnum 的接口,其内部最终会调用到 Z_Construct_UEnum_Reflection_EMyEnumClass
,但此时还没看到该函数的定义先略过。还有一点需要注意 调用 GetStaticEnum
时,已经显式的调用 Z_Construct_UPackage__Script_Reflection()
来确保 UPackage 一定存在了。
剧透一下 GetStaticEnum
实际上就是执行第一个参数的函数,用内部函数构建出 UEnum
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static FEnumRegistrationInfo Z_Registration_Info_UEnum_EMyEnumClass;static UEnum* EMyEnumClass_StaticEnum () { if (!Z_Registration_Info_UEnum_EMyEnumClass.OuterSingleton) { Z_Registration_Info_UEnum_EMyEnumClass.OuterSingleton = GetStaticEnum ( Z_Construct_UEnum_Reflection_EMyEnumClass, (UObject*)Z_Construct_UPackage__Script_Reflection (), TEXT ("EMyEnumClass" ) ); } return Z_Registration_Info_UEnum_EMyEnumClass.OuterSingleton; } template <> REFLECTION_API UEnum* StaticEnum <EMyEnumClass>(){ return EMyEnumClass_StaticEnum (); }
此处是一些元数据, FEnumParams
就是后面用来构建 UEnum 的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct Z_Construct_UEnum_Reflection_EMyEnumClass_Statics { #if WITH_METADATA static constexpr UECodeGen_Private::FMetaDataPairParam Enum_MetaDataParams[] = { { "BlueprintType" , "true" }, #if !UE_BUILD_SHIPPING { "Comment" , "/**\n * \n */" }, #endif { "Enum1.Comment" , "/**\n * \n */" }, { "Enum1.DisplayName" , "DisplayInBlueprint" }, { "Enum1.Name" , "EMyEnumClass::Enum1" }, { "Enum2.Comment" , "/**\n * \n */" }, { "Enum2.Name" , "EMyEnumClass::Enum2" }, { "ModuleRelativePath" , "Public/Enum/MyEnumClass.h" }, }; #endif static constexpr UECodeGen_Private::FEnumeratorParam Enumerators[] = { { "EMyEnumClass::Enum1" , (int64)EMyEnumClass::Enum1 }, { "EMyEnumClass::Enum2" , (int64)EMyEnumClass::Enum2 }, }; static const UECodeGen_Private::FEnumParams EnumParams; };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const UECodeGen_Private::FEnumParams Z_Construct_UEnum_Reflection_EMyEnumClass_Statics::EnumParams = { (UObject*(*)())Z_Construct_UPackage__Script_Reflection, nullptr , "EMyEnumClass" , "EMyEnumClass" , Z_Construct_UEnum_Reflection_EMyEnumClass_Statics::Enumerators, RF_Public|RF_Transient|RF_MarkAsNative, UE_ARRAY_COUNT (Z_Construct_UEnum_Reflection_EMyEnumClass_Statics::Enumerators), EEnumFlags::None, (uint8)UEnum::ECppForm::EnumClass, METADATA_PARAMS (UE_ARRAY_COUNT (Z_Construct_UEnum_Reflection_EMyEnumClass_Statics::Enum_MetaDataParams), Z_Construct_UEnum_Reflection_EMyEnumClass_Statics::Enum_MetaDataParams) }; struct FEnumParams { UObject* (*OuterFunc)(); FText (*DisplayNameFunc)(int32); const char * NameUTF8; const char * CppTypeUTF8; const FEnumeratorParam* EnumeratorParams; EObjectFlags ObjectFlags; int16 NumEnumerators; EEnumFlags EnumFlags; uint8 CppForm; #if WITH_METADATA uint16 NumMetaData; const FMetaDataPairParam* MetaDataArray; #endif };
内部真正构造 UEnum 的函数,Outer 最终就是调用该函数 完成 Inner 的构建。
1 2 3 4 5 6 7 8 UEnum* Z_Construct_UEnum_Reflection_EMyEnumClass () { if (!Z_Registration_Info_UEnum_EMyEnumClass.InnerSingleton) { UECodeGen_Private::ConstructUEnum (Z_Registration_Info_UEnum_EMyEnumClass.InnerSingleton, Z_Construct_UEnum_Reflection_EMyEnumClass_Statics::EnumParams); } return Z_Registration_Info_UEnum_EMyEnumClass.InnerSingleton; }
注册相关代码,可以看出它是以文件为单位,将整个文件的内容都放到一起,这个文件只有一个枚举,所以内容就比较少,如果还有 UStruct 的话 也会在此处被列出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 struct Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Enum_MyEnumClass_h_Statics { static constexpr FEnumRegisterCompiledInInfo EnumInfo[] = { { EMyEnumClass_StaticEnum, TEXT ("EMyEnumClass" ), &Z_Registration_Info_UEnum_EMyEnumClass, CONSTRUCT_RELOAD_VERSION_INFO (FEnumReloadVersionInfo, 4010083278U ) }, }; }; static FRegisterCompiledInInfo Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Enum_MyEnumClass_h_2660371430 ( TEXT("/Script/Reflection" ), nullptr , 0 , nullptr , 0 , Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Enum_MyEnumClass_h_Statics::EnumInfo, UE_ARRAY_COUNT(Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Enum_MyEnumClass_h_Statics::EnumInfo) ) ;struct FEnumRegisterCompiledInInfo { class UEnum * (*OuterRegister)(); const TCHAR* Name; FEnumRegistrationInfo* Info; FEnumReloadVersionInfo VersionInfo; };
Struct 为了本文主体逻辑能够简单理解,只声明定义一个属性。
1 2 3 4 5 6 7 8 USTRUCT (BlueprintType)struct FMyStruct { GENERATED_BODY () UPROPERTY () int32 MyInt32 = 0 ; };
GENERATED_BODY
本质就是将其替换为 文件名_行号_GENERATED_BODY
。
1 2 3 #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);
最后会被替换 FID_Project_Source_Reflection_Public_Struct_MyStruct_h_13_GENERATED_BODY
再看 generated.h
的内容
1 2 3 4 5 #define FID_Project_Source_Reflection_Public_Struct_MyStruct_h_13_GENERATED_BODY \ friend struct Z_Construct_UScriptStruct_FMyStruct_Statics; \ REFLECTION_API static class UScriptStruct* StaticStruct(); template <> REFLECTION_API UScriptStruct* StaticStruct <struct FMyStruct >();
宏展开之后得到
1 2 3 4 5 6 7 8 9 10 11 template <> REFLECTION_API UScriptStruct* StaticStruct <struct FMyStruct >();USTRUCT (BlueprintType)struct FMyStruct { friend struct Z_Construct_UScriptStruct_FMyStruct_Statics ; REFLECTION_API static class UScriptStruct* StaticStruct () ; UPROPERTY () int32 MyInt32 = 0 ; };
gen.cpp
内容如下,但不会再次解释了,很多都在 Enum 那解释过了。
1 2 3 4 void EmptyLinkFunctionForGeneratedCodeMyStruct () {}REFLECTION_API UScriptStruct* Z_Construct_UScriptStruct_FMyStruct () ;UPackage* Z_Construct_UPackage__Script_Reflection () ;
对外的构造 Struct 接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 static FStructRegistrationInfo Z_Registration_Info_UScriptStruct_MyStruct;class UScriptStruct* FMyStruct::StaticStruct () { if (!Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton) { Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton = GetStaticStruct ( Z_Construct_UScriptStruct_FMyStruct, (UObject*)Z_Construct_UPackage__Script_Reflection (), TEXT ("MyStruct" ) ); } return Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton; } template <> REFLECTION_API UScriptStruct* StaticStruct <FMyStruct>(){ return FMyStruct::StaticStruct (); }
反射元数据,其中 NewStructOps
提供了结构体反射、序列化、复制比较功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 struct Z_Construct_UScriptStruct_FMyStruct_Statics { #if WITH_METADATA static constexpr UECodeGen_Private::FMetaDataPairParam Struct_MetaDataParams[] = { { "BlueprintType" , "true" }, #if !UE_BUILD_SHIPPING { "Comment" , "/**\n * \n */" }, #endif { "ModuleRelativePath" , "Public/Struct/MyStruct.h" }, }; static constexpr UECodeGen_Private::FMetaDataPairParam NewProp_MyInt32_MetaData[] = { { "ModuleRelativePath" , "Public/Struct/MyStruct.h" }, }; #endif static const UECodeGen_Private::FIntPropertyParams NewProp_MyInt32; static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[]; static void * NewStructOps () { return (UScriptStruct::ICppStructOps*)new UScriptStruct::TCppStructOps <FMyStruct>(); } static const UECodeGen_Private::FStructParams StructParams; };
属性,我们只有一个属性,可以看到会在这记录该属性在 Struct 中的偏移量,同时 属性个数不得超过 2048个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const UECodeGen_Private::FIntPropertyParams Z_Construct_UScriptStruct_FMyStruct_Statics::NewProp_MyInt32 = { "MyInt32" , nullptr , (EPropertyFlags)0x0010000000000000 , UECodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, nullptr , nullptr , 1 , STRUCT_OFFSET (FMyStruct, MyInt32), METADATA_PARAMS (UE_ARRAY_COUNT (NewProp_MyInt32_MetaData), NewProp_MyInt32_MetaData) }; const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UScriptStruct_FMyStruct_Statics::PropPointers[] = { (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UScriptStruct_FMyStruct_Statics::NewProp_MyInt32, }; static_assert (UE_ARRAY_COUNT (Z_Construct_UScriptStruct_FMyStruct_Statics::PropPointers) < 2048 );
构造 Struct 的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 const UECodeGen_Private::FStructParams Z_Construct_UScriptStruct_FMyStruct_Statics::StructParams = { (UObject* (*)())Z_Construct_UPackage__Script_Reflection, nullptr , &NewStructOps, "MyStruct" , Z_Construct_UScriptStruct_FMyStruct_Statics::PropPointers, UE_ARRAY_COUNT (Z_Construct_UScriptStruct_FMyStruct_Statics::PropPointers), sizeof (FMyStruct), alignof (FMyStruct), RF_Public|RF_Transient|RF_MarkAsNative, EStructFlags (0x00000001 ), METADATA_PARAMS (UE_ARRAY_COUNT (Z_Construct_UScriptStruct_FMyStruct_Statics::Struct_MetaDataParams), Z_Construct_UScriptStruct_FMyStruct_Statics::Struct_MetaDataParams) }; struct FStructParams { UObject* (*OuterFunc)(); UScriptStruct* (*SuperFunc)(); void * (*StructOpsFunc)(); const char * NameUTF8; const FPropertyParamsBase* const * PropertyArray; uint16 NumProperties; uint16 SizeOf; uint8 AlignOf; EObjectFlags ObjectFlags; uint32 StructFlags; #if WITH_METADATA uint16 NumMetaData; const FMetaDataPairParam* MetaDataArray; #endif };
同个文件内的反射内容都会注册到这,这个文件只有 Struct。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Struct_MyStruct_h_Statics { static constexpr FStructRegisterCompiledInInfo ScriptStructInfo[] = { { FMyStruct::StaticStruct, Z_Construct_UScriptStruct_FMyStruct_Statics::NewStructOps, TEXT ("MyStruct" ), &Z_Registration_Info_UScriptStruct_MyStruct, CONSTRUCT_RELOAD_VERSION_INFO (FStructReloadVersionInfo, sizeof (FMyStruct), 221546749U ) }, }; }; struct FStructRegisterCompiledInInfo { class UScriptStruct * (*OuterRegister)(); void * (*CreateCppStructOps)(); const TCHAR* Name; FStructRegistrationInfo* Info; FStructReloadVersionInfo VersionInfo; };
注册参数。
1 2 3 4 5 6 7 8 9 static FRegisterCompiledInInfo Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Struct_MyStruct_h_1968461662 ( TEXT("/Script/Reflection" ), nullptr , 0 , Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Struct_MyStruct_h_Statics::ScriptStructInfo, UE_ARRAY_COUNT(Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Struct_MyStruct_h_Statics::ScriptStructInfo), nullptr , 0 ) ;
Class Class 和 Struct 其实差不太多,但它支持成员方法,同时成员方法还支持给蓝图调用。下面只定义一个成员方法,但它支持参数和返回值。
1 2 3 4 5 6 7 8 9 10 11 UCLASS ()class REFLECTION_API UMyObject : public UObject{ GENERATED_BODY () public : UFUNCTION () int32 MyFunc (int32 i) { return i++; } private : UPROPERTY () int32 MyInt32 = 0 ; };
GENERATED_BODY()
生成出以下内容
1 2 3 4 5 6 #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_GENERATED_BODY \ public: \ FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_RPC_WRAPPERS_NO_PURE_DECLS \ FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_INCLASS_NO_PURE_DECLS \ FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_ENHANCED_CONSTRUCTORS \ private:
RPC_WRAPPERS_NO_PURE_DECLS
会生成 UFunction 方法的包装,为了让蓝图也能调用,其实就将参数和返回值改放到 FFrame
栈中。
1 2 3 4 5 6 7 #define DECLARE_FUNCTION(func) static void func( UObject* Context, FFrame& Stack, RESULT_DECL ) #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_RPC_WRAPPERS_NO_PURE_DECLS \ DECLARE_FUNCTION(execMyFunc); #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_RPC_WRAPPERS_NO_PURE_DECLS \ static void execMyFunc( UObject* Context, FFrame& Stack, RESULT_DECL );
INCLASS_NO_PURE_DECLS
声明一些类的基础别名、序列化等。比如 Super
就是在这被设置为父类别名的。
1 2 3 4 5 6 7 #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_INCLASS_NO_PURE_DECLS \ private: \ static void StaticRegisterNativesUMyObject(); \ friend struct Z_Construct_UClass_UMyObject_Statics; \ public: \ DECLARE_CLASS(UMyObject, UObject, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/Reflection" ), NO_API) \ DECLARE_SERIALIZER(UMyObject)
ENHANCED_CONSTRUCTORS
从名字也能看出是提供多一些构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_14_ENHANCED_CONSTRUCTORS \ \ NO_API UMyObject(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \ private: \ \ UMyObject(UMyObject&&); \ UMyObject(const UMyObject&); \ public: \ DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UMyObject); \ DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UMyObject); \ DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UMyObject) \ NO_API virtual ~UMyObject();
GENERATED_BODY()
将宏完整展开生成代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 UCLASS ()class REFLECTION_API UMyObject : public UObject{ public : static void execMyFunc ( UObject* Context, FFrame& Stack, RESULT_DECL ) ; private : static void StaticRegisterNativesUMyObject () ; friend struct Z_Construct_UClass_UMyObject_Statics ; public : static constexpr EClassFlags StaticClassFlags = EClassFlags ((0 | CLASS_Intrinsic)); typedef UObject Super; typedef UMyObject ThisClass; inline static UClass* StaticClass () { return GetPrivateStaticClass (); } inline static const TCHAR* StaticPackage () { return L"/ Script/ Reflection" ; } inline static EClassCastFlags StaticClassCastFlags () { return CASTCLASS_None; } 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); } inline void * operator new (const size_t InSize, EInternal* InMem) { return (void *)InMem; } inline void operator delete (void * InMem) { ::operator delete (InMem) ; } friend FArchive& operator <<(FArchive& Ar, UMyObject*& Res) { return Ar << (UObject*&)Res; } friend void operator <<(FStructuredArchive::FSlot InSlot, UMyObject*& Res) { InSlot << (UObject*&)Res; } NO_API UMyObject (const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) ; private : UMyObject (UMyObject&&); UMyObject (const UMyObject&); public : DECLARE_VTABLE_PTR_HELPER_CTOR (NO_API, UMyObject); DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER (UMyObject); static void __DefaultConstructor(const FObjectInitializer& X) { new ((EInternal*)X.GetObj ())UMyObject (X); } NO_API virtual ~UMyObject (); public : int32 MyFunc (int32 i) { return i++; } private : int32 MyInt32 = 0 ; };
gen.cpp
前置声明。
1 2 3 4 5 6 void EmptyLinkFunctionForGeneratedCodeMyObject () {}COREUOBJECT_API UClass* Z_Construct_UClass_UObject () ;REFLECTION_API UClass* Z_Construct_UClass_UMyObject () ;REFLECTION_API UClass* Z_Construct_UClass_UMyObject_NoRegister () ;UPackage* Z_Construct_UPackage__Script_Reflection () ;
成员函数反射信息,为返回值和参数都构造属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 struct Z_Construct_UFunction_UMyObject_MyFunc_Statics { struct MyObject_eventMyFunc_Parms { int32 i; int32 ReturnValue; }; #if WITH_METADATA static constexpr UECodeGen_Private::FMetaDataPairParam Function_MetaDataParams[] = { { "ModuleRelativePath" , "Public/Object/MyObject.h" }, }; #endif static const UECodeGen_Private::FIntPropertyParams NewProp_i; static const UECodeGen_Private::FIntPropertyParams NewProp_ReturnValue; static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[]; static const UECodeGen_Private::FFunctionParams FuncParams; }; const UECodeGen_Private::FIntPropertyParams Z_Construct_UFunction_UMyObject_MyFunc_Statics::NewProp_i = { "i" , nullptr , (EPropertyFlags)0x0010000000000080 , UECodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, nullptr , nullptr , 1 , STRUCT_OFFSET (MyObject_eventMyFunc_Parms, i), METADATA_PARAMS (0 , nullptr ) };const UECodeGen_Private::FIntPropertyParams Z_Construct_UFunction_UMyObject_MyFunc_Statics::NewProp_ReturnValue = { "ReturnValue" , nullptr , (EPropertyFlags)0x0010000000000580 , UECodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, nullptr , nullptr , 1 , STRUCT_OFFSET (MyObject_eventMyFunc_Parms, ReturnValue), METADATA_PARAMS (0 , nullptr ) };const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UFunction_UMyObject_MyFunc_Statics::PropPointers[] = { (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UMyObject_MyFunc_Statics::NewProp_i, (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_UMyObject_MyFunc_Statics::NewProp_ReturnValue, }; static_assert (UE_ARRAY_COUNT (Z_Construct_UFunction_UMyObject_MyFunc_Statics::PropPointers) < 2048 );const UECodeGen_Private::FFunctionParams Z_Construct_UFunction_UMyObject_MyFunc_Statics::FuncParams = { (UObject*(*)())Z_Construct_UClass_UMyObject, nullptr , "MyFunc" , nullptr , nullptr , Z_Construct_UFunction_UMyObject_MyFunc_Statics::PropPointers, UE_ARRAY_COUNT (Z_Construct_UFunction_UMyObject_MyFunc_Statics::PropPointers), sizeof (Z_Construct_UFunction_UMyObject_MyFunc_Statics::MyObject_eventMyFunc_Parms), RF_Public|RF_Transient|RF_MarkAsNative, (EFunctionFlags)0x00020401 , 0 , 0 , METADATA_PARAMS (UE_ARRAY_COUNT (Z_Construct_UFunction_UMyObject_MyFunc_Statics::Function_MetaDataParams), Z_Construct_UFunction_UMyObject_MyFunc_Statics::Function_MetaDataParams) };static_assert (sizeof (Z_Construct_UFunction_UMyObject_MyFunc_Statics::MyObject_eventMyFunc_Parms) < MAX_uint16);
成员函数的构造方法
1 2 3 4 5 6 7 8 9 UFunction* Z_Construct_UFunction_UMyObject_MyFunc () { static UFunction* ReturnFunction = nullptr ; if (!ReturnFunction) { UECodeGen_Private::ConstructUFunction (&ReturnFunction, Z_Construct_UFunction_UMyObject_MyFunc_Statics::FuncParams); } return ReturnFunction; }
成员函数的 thunk 函数定义,里面 P 开头的是虚拟机的辅助宏。
1 2 3 4 5 6 7 8 9 10 #define RESULT_PARAM Z_Param__Result #define RESULT_DECL void*const RESULT_PARAM void UMyObject::execMyFunc ( UObject* Context, FFrame& Stack, RESULT_DECL ) { P_GET_PROPERTY (FIntProperty,Z_Param_i); P_FINISH; P_NATIVE_BEGIN; *(int32*)Z_Param__Result=P_THIS->MyFunc (Z_Param_i); P_NATIVE_END; }
注册成员函数和对应的 thunk 函数的绑定。
1 2 3 4 5 6 7 8 void UMyObject::StaticRegisterNativesUMyObject () { UClass* Class = UMyObject::StaticClass (); static const FNameNativePtrPair Funcs[] = { { "MyFunc" , &UMyObject::execMyFunc }, }; FNativeFunctionRegistrar::RegisterFunctions (Class, Funcs, UE_ARRAY_COUNT (Funcs)); }
GetPrivateStaticClass
就是 StaticClass
也是 InnerRegister
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 UClass* UMyObject::GetPrivateStaticClass () { if (!Z_Registration_Info_UClass_UMyObject.InnerSingleton) { GetPrivateStaticClassBody ( StaticPackage (), (TCHAR*)TEXT ("UMyObject" ) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0 ), Z_Registration_Info_UClass_UMyObject.InnerSingleton, StaticRegisterNativesUMyObject, sizeof (UMyObject), alignof (UMyObject), UMyObject::StaticClassFlags, UMyObject::StaticClassCastFlags (), UMyObject::StaticConfigName (), (UClass::ClassConstructorType)InternalConstructor<UMyObject>, (UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<UMyObject>, UOBJECT_CPPCLASS_STATICFUNCTIONS_FORCLASS (UMyObject), &UMyObject::Super::StaticClass, &UMyObject::WithinClass::StaticClass ); } return Z_Registration_Info_UClass_UMyObject.InnerSingleton; }
1 2 3 4 UClass* Z_Construct_UClass_UMyObject_NoRegister () { return UMyObject::StaticClass (); }
类的反射信息,包含成员变量和成员方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 struct Z_Construct_UClass_UMyObject_Statics { #if WITH_METADATA static constexpr UECodeGen_Private::FMetaDataPairParam Class_MetaDataParams[] = { #if !UE_BUILD_SHIPPING { "Comment" , "/**\n * \n */" }, #endif { "IncludePath" , "Object/MyObject.h" }, { "ModuleRelativePath" , "Public/Object/MyObject.h" }, }; static constexpr UECodeGen_Private::FMetaDataPairParam NewProp_MyInt32_MetaData[] = { { "ModuleRelativePath" , "Public/Object/MyObject.h" }, }; #endif static const UECodeGen_Private::FIntPropertyParams NewProp_MyInt32; static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[]; static UObject* (*const DependentSingletons[])(); static constexpr FClassFunctionLinkInfo FuncInfo[] = { { &Z_Construct_UFunction_UMyObject_MyFunc, "MyFunc" }, }; static_assert (UE_ARRAY_COUNT (FuncInfo) < 2048 ); static constexpr FCppClassTypeInfoStatic StaticCppClassTypeInfo = { TCppClassTypeTraits<UMyObject>::IsAbstract, }; static const UECodeGen_Private::FClassParams ClassParams; };
成员变量反射信息
1 2 3 4 5 const UECodeGen_Private::FIntPropertyParams Z_Construct_UClass_UMyObject_Statics::NewProp_MyInt32 = { "MyInt32" , nullptr , (EPropertyFlags)0x0040000000000000 , UECodeGen_Private::EPropertyGenFlags::Int, RF_Public|RF_Transient|RF_MarkAsNative, nullptr , nullptr , 1 , STRUCT_OFFSET (UMyObject, MyInt32), METADATA_PARAMS (UE_ARRAY_COUNT (NewProp_MyInt32_MetaData), NewProp_MyInt32_MetaData) };const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_UMyObject_Statics::PropPointers[] = { (const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_UMyObject_Statics::NewProp_MyInt32, }; static_assert (UE_ARRAY_COUNT (Z_Construct_UClass_UMyObject_Statics::PropPointers) < 2048 );
构造该 Class 的依赖项,至少要构造 UObject 因为是它子类,其次是 UPackage。
1 2 3 4 5 UObject* (*const Z_Construct_UClass_UMyObject_Statics::DependentSingletons[])() = { (UObject* (*)())Z_Construct_UClass_UObject, (UObject* (*)())Z_Construct_UPackage__Script_Reflection, }; static_assert (UE_ARRAY_COUNT (Z_Construct_UClass_UMyObject_Statics::DependentSingletons) < 16 );
类的构造参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 const UECodeGen_Private::FClassParams Z_Construct_UClass_UMyObject_Statics::ClassParams = { &UMyObject::StaticClass, nullptr , &StaticCppClassTypeInfo, DependentSingletons, FuncInfo, Z_Construct_UClass_UMyObject_Statics::PropPointers, nullptr , UE_ARRAY_COUNT (DependentSingletons), UE_ARRAY_COUNT (FuncInfo), UE_ARRAY_COUNT (Z_Construct_UClass_UMyObject_Statics::PropPointers), 0 , 0x001000A0u , METADATA_PARAMS (UE_ARRAY_COUNT (Z_Construct_UClass_UMyObject_Statics::Class_MetaDataParams), Z_Construct_UClass_UMyObject_Statics::Class_MetaDataParams) }; struct FClassParams { UClass* (*ClassNoRegisterFunc)(); const char * ClassConfigNameUTF8; const FCppClassTypeInfoStatic* CppClassInfo; UObject* (*const *DependencySingletonFuncArray)(); const FClassFunctionLinkInfo* FunctionLinkArray; const FPropertyParamsBase* const * PropertyArray; const FImplementedInterfaceParams* ImplementedInterfaceArray; uint32 NumDependencySingletons : 4 ; uint32 NumFunctions : 11 ; uint32 NumProperties : 11 ; uint32 NumImplementedInterfaces : 6 ; uint32 ClassFlags; #if WITH_METADATA uint16 NumMetaData; const FMetaDataPairParam* MetaDataArray; #endif };
构造函数定义。
1 2 3 UMyObject::UMyObject (const FObjectInitializer& ObjectInitializer) : Super (ObjectInitializer) {} DEFINE_VTABLE_PTR_HELPER_CTOR (UMyObject);UMyObject::~UMyObject () {}
真正构造该 Class 的地方。
1 2 3 4 5 6 7 8 9 10 11 12 UClass* Z_Construct_UClass_UMyObject () { if (!Z_Registration_Info_UClass_UMyObject.OuterSingleton) { UECodeGen_Private::ConstructUClass (Z_Registration_Info_UClass_UMyObject.OuterSingleton, Z_Construct_UClass_UMyObject_Statics::ClassParams); } return Z_Registration_Info_UClass_UMyObject.OuterSingleton; } template <> REFLECTION_API UClass* StaticClass <UMyObject>(){ return UMyObject::StaticClass (); }
一样的,同一个文件的所有反射都会记录在这,这个文件只有一个类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 struct Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_Statics { static constexpr FClassRegisterCompiledInInfo ClassInfo[] = { { Z_Construct_UClass_UMyObject, UMyObject::StaticClass, TEXT ("UMyObject" ), &Z_Registration_Info_UClass_UMyObject, CONSTRUCT_RELOAD_VERSION_INFO (FClassReloadVersionInfo, sizeof (UMyObject), 1556497845U )}, }; }; struct FClassRegisterCompiledInInfo { class UClass * (*OuterRegister)(); class UClass * (*InnerRegister)(); const TCHAR* Name; FClassRegistrationInfo* Info; FClassReloadVersionInfo VersionInfo; };
最终注册。
1 2 3 4 5 6 7 8 9 static FRegisterCompiledInInfo Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_1505249514 ( TEXT("/Script/Reflection" ), Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_Statics::ClassInfo, UE_ARRAY_COUNT(Z_CompiledInDeferFile_FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Object_MyObject_h_Statics::ClassInfo), nullptr , 0 , nullptr , 0 ) ;
Interface 先创建一个 Interface,并声明两个成员方法,两个方法皆能被蓝图和C++所调用,但其中一个只能被蓝图实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 UINTERFACE (MinimalAPI)class UMyInterface : public UInterface{ GENERATED_BODY () }; class REFLECTION_API IMyInterface{ GENERATED_BODY () public : UFUNCTION (BlueprintCallable, BlueprintImplementableEvent ) void IBlueprintImplementableEvent () ; UFUNCTION (BlueprintCallable, BlueprintNativeEvent) void IBlueprintNativeEvent () ; };
随后创建一个 Class 实现 该 Interface。
1 2 3 4 5 6 7 UCLASS ()class REFLECTION_API UMyInterfaceObj : public UObject, public IMyInterface{ GENERATED_BODY () public : void IBlueprintNativeEvent_Implementation () override {} };
UMyInterface
这个 UE 自动帮我们生成的 Class 可以跳过,因为和上面讲过得 Class 一样的逻辑。
而 IMyInterface
的 GENERATED_BODY()
最终会生成如下代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_13_RPC_WRAPPERS_NO_PURE_DECLS \ virtual void IBlueprintNativeEvent_Implementation() {}; \ DECLARE_FUNCTION(execIBlueprintNativeEvent); #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_13_CALLBACK_WRAPPERS #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_13_INCLASS_IINTERFACE_NO_PURE_DECLS \ protected: \ virtual ~IMyInterface() {} \ public: \ typedef UMyInterface UClassType; \ typedef IMyInterface ThisClass; \ static void Execute_IBlueprintImplementableEvent(UObject* O); \ static void Execute_IBlueprintNativeEvent(UObject* O); \ virtual UObject* _getUObject() const { return nullptr; } #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_10_PROLOG #define FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_21_GENERATED_BODY \ public: \ FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_13_RPC_WRAPPERS_NO_PURE_DECLS \ FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_13_CALLBACK_WRAPPERS \ FID_Users_yuerer_Desktop_reflection_Source_Reflection_Public_Interface_MyInterface_h_13_INCLASS_IINTERFACE_NO_PURE_DECLS \ private:
将其展开后得到:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class REFLECTION_API IMyInterface{ public : virtual void IBlueprintNativeEvent_Implementation () {}; static void execIBlueprintNativeEvent ( UObject* Context, FFrame& Stack, RESULT_DECL ) ; protected : virtual ~IMyInterface () {} public : typedef UMyInterface UClassType; typedef IMyInterface ThisClass; static void Execute_IBlueprintImplementableEvent (UObject* O) ; static void Execute_IBlueprintNativeEvent (UObject* O) ; virtual UObject* _getUObject() const { return nullptr ; } public : void IBlueprintImplementableEvent () ; void IBlueprintNativeEvent () ; };
gen.cpp
中的内容如下:
先是 IBlueprintImplementableEvent
相关的反射内容。
BlueprintImplement
的接口 默认生成一个检测函数,避免C++直接调用原来的函数,因为无论是C++还是蓝图调用的接口都是被改名过的 thunk 函数。
1 2 3 4 void IMyInterface::IBlueprintImplementableEvent () { check (0 && "Do not directly call Event functions in Interfaces. Call Execute_IBlueprintImplementableEvent instead." ); }
但需要让C++能够调用到蓝图实现的接口。
1 2 3 4 5 6 7 8 9 10 11 static FName NAME_UMyInterface_IBlueprintImplementableEvent = FName (TEXT ("IBlueprintImplementableEvent" ));void IMyInterface::Execute_IBlueprintImplementableEvent (UObject* O) { check (O != NULL ); check (O->GetClass ()->ImplementsInterface (UMyInterface::StaticClass ())); UFunction* const Func = O->FindFunction (NAME_UMyInterface_IBlueprintImplementableEvent); if (Func) { O->ProcessEvent (Func, NULL ); } }
构造 IBlueprintImplementableEvent
这个 UFunction 。
1 2 3 4 5 6 7 8 9 10 const UECodeGen_Private::FFunctionParams Z_Construct_UFunction_UMyInterface_IBlueprintImplementableEvent_Statics::FuncParams = { (UObject*(*)())Z_Construct_UClass_UMyInterface, nullptr , "IBlueprintImplementableEvent" , nullptr , nullptr , nullptr , 0 , 0 , RF_Public|RF_Transient|RF_MarkAsNative, (EFunctionFlags)0x0C020800 , 0 , 0 , METADATA_PARAMS (UE_ARRAY_COUNT (Z_Construct_UFunction_UMyInterface_IBlueprintImplementableEvent_Statics::Function_MetaDataParams), Z_Construct_UFunction_UMyInterface_IBlueprintImplementableEvent_Statics::Function_MetaDataParams) };UFunction* Z_Construct_UFunction_UMyInterface_IBlueprintImplementableEvent () { static UFunction* ReturnFunction = nullptr ; if (!ReturnFunction) { UECodeGen_Private::ConstructUFunction (&ReturnFunction, Z_Construct_UFunction_UMyInterface_IBlueprintImplementableEvent_Statics::FuncParams); } return ReturnFunction; }
另一个接口 IBlueprintNativeEvent
,同样需要避免被直接调用。
1 2 3 4 void IMyInterface::IBlueprintNativeEvent () { check (0 && "Do not directly call Event functions in Interfaces. Call Execute_IBlueprintNativeEvent instead." ); }
既可以被蓝图实现,也能被C++实现,所以都要判断一下,不过可以看出如果蓝图有实现,优先用蓝图的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static FName NAME_UMyInterface_IBlueprintNativeEvent = FName (TEXT ("IBlueprintNativeEvent" ));void IMyInterface::Execute_IBlueprintNativeEvent (UObject* O) { check (O != NULL ); check (O->GetClass ()->ImplementsInterface (UMyInterface::StaticClass ())); UFunction* const Func = O->FindFunction (NAME_UMyInterface_IBlueprintNativeEvent); if (Func) { O->ProcessEvent (Func, NULL ); } else if (auto I = (IMyInterface*)(O->GetNativeInterfaceAddress (UMyInterface::StaticClass ()))) { I->IBlueprintNativeEvent_Implementation (); } }
构造该 UFunction 的辅助函数。
1 2 3 4 5 6 7 8 9 UFunction* Z_Construct_UFunction_UMyInterface_IBlueprintNativeEvent () { static UFunction* ReturnFunction = nullptr ; if (!ReturnFunction) { UECodeGen_Private::ConstructUFunction (&ReturnFunction, Z_Construct_UFunction_UMyInterface_IBlueprintNativeEvent_Statics::FuncParams); } return ReturnFunction; }
最后由于这个接口可以被蓝图调用,需要提供一个蓝图调用接口。
1 2 3 4 5 6 7 void IMyInterface::execInterfaceBlueprintNativeEvent ( UObject* Context, FFrame& Stack, RESULT_DECL ) { P_FINISH; P_NATIVE_BEGIN; P_THIS->IBlueprintNativeEvent_Implementation (); P_NATIVE_END; }
最后则是将C++可实现的接口注册到 UMyInterface
这个UE自动帮我们生成的 Object 中,这也就解释了为什么 Interface 需要生成一个 Object。
反射代码注册 在每个 gen.cpp
文件下都使用了一个 FRegisterCompiledInInfo
struct,反射代码的注册都是通过这个结构体的构造函数进行。
1 2 3 4 5 6 7 8 struct FRegisterCompiledInInfo { template <typename ... Args> FRegisterCompiledInInfo (Args&& ... args) { RegisterCompiledInInfo (std::forward<Args>(args)...); } };
每个文件最终都会进入这一统一的注册入口,然后将文件中的 Class
Stuct
Enum
分别注册进去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void RegisterCompiledInInfo (const TCHAR* PackageName, const FClassRegisterCompiledInInfo* ClassInfo, size_t NumClassInfo, const FStructRegisterCompiledInInfo* StructInfo, size_t NumStructInfo, const FEnumRegisterCompiledInInfo* EnumInfo, size_t NumEnumInfo) { for (size_t Index = 0 ; Index < NumClassInfo; ++Index) { const FClassRegisterCompiledInInfo& Info = ClassInfo[Index]; RegisterCompiledInInfo (Info.OuterRegister, Info.InnerRegister, PackageName, Info.Name, *Info.Info, Info.VersionInfo); } for (size_t Index = 0 ; Index < NumStructInfo; ++Index) { const FStructRegisterCompiledInInfo& Info = StructInfo[Index]; RegisterCompiledInInfo (Info.OuterRegister, PackageName, Info.Name, *Info.Info, Info.VersionInfo); if (Info.CreateCppStructOps != nullptr ) { UScriptStruct::DeferCppStructOps (FTopLevelAssetPath (FName (PackageName), FName (Info.Name)), (UScriptStruct::ICppStructOps*)Info.CreateCppStructOps ()); } } for (size_t Index = 0 ; Index < NumEnumInfo; ++Index) { const FEnumRegisterCompiledInInfo& Info = EnumInfo[Index]; RegisterCompiledInInfo (Info.OuterRegister, PackageName, Info.Name, *Info.Info, Info.VersionInfo); } }
Class
版本的 RegisterCompiledInInfo:
大致就是将其加入到 FClassDeferredRegistry
列表中,同时发起一个事件记录这个 Class 和 这个Class 的 CDO 已添加,后续用来检查有哪些数据是未完成注册用的,后面不再强调了。
1 2 3 4 5 6 7 8 void RegisterCompiledInInfo (class UClass* (*InOuterRegister)(), class UClass* (*InInnerRegister)(), const TCHAR* InPackageName, const TCHAR* InName, FClassRegistrationInfo& InInfo, const FClassReloadVersionInfo& InVersionInfo) { FClassDeferredRegistry::AddResult result = FClassDeferredRegistry::Get ().AddRegistration (InOuterRegister, InInnerRegister, InPackageName, InName, InInfo, InVersionInfo); FString NoPrefix (UObjectBase::RemoveClassPrefix(InName)) ; NotifyRegistrationEvent (InPackageName, *NoPrefix, ENotifyRegistrationType::NRT_Class, ENotifyRegistrationPhase::NRP_Added, (UObject * (*)())(InOuterRegister), false ); NotifyRegistrationEvent (InPackageName, *(FString (DEFAULT_OBJECT_PREFIX) + NoPrefix), ENotifyRegistrationType::NRT_ClassCDO, ENotifyRegistrationPhase::NRP_Added, (UObject * (*)())(InOuterRegister), false ); }
Struct
版本同理,记录到 FStructDeferredRegistry
中。
1 2 3 4 5 void RegisterCompiledInInfo (class UScriptStruct* (*InOuterRegister)(), const TCHAR* InPackageName, const TCHAR* InName, FStructRegistrationInfo& InInfo, const FStructReloadVersionInfo& InVersionInfo) { FStructDeferredRegistry::Get ().AddRegistration (InOuterRegister, nullptr , InPackageName, InName, InInfo, InVersionInfo); NotifyRegistrationEvent (InPackageName, InName, ENotifyRegistrationType::NRT_Struct, ENotifyRegistrationPhase::NRP_Added, (UObject * (*)())(InOuterRegister), false ); }
Enum
同理。
1 2 3 4 5 void RegisterCompiledInInfo (class UEnum* (*InOuterRegister)(), const TCHAR* InPackageName, const TCHAR* InName, FEnumRegistrationInfo& InInfo, const FEnumReloadVersionInfo& InVersionInfo) { FEnumDeferredRegistry::Get ().AddRegistration (InOuterRegister, nullptr , InPackageName, InName, InInfo, InVersionInfo); NotifyRegistrationEvent (InPackageName, InName, ENotifyRegistrationType::NRT_Enum, ENotifyRegistrationPhase::NRP_Added, (UObject * (*)())(InOuterRegister), false ); }
这些反射数据采集完成后,会在引擎初始化时,调用 ProcessNewlyLoadedUObjects
方法。
1 2 3 4 5 6 7 8 9 void ProcessNewlyLoadedUObjects (FName Package, bool bCanProcessNewlyLoadedObjects) { FPackageDeferredRegistry& PackageRegistry = FPackageDeferredRegistry::Get (); FClassDeferredRegistry& ClassRegistry = FClassDeferredRegistry::Get (); FStructDeferredRegistry& StructRegistry = FStructDeferredRegistry::Get (); FEnumDeferredRegistry& EnumRegistry = FEnumDeferredRegistry::Get (); UClassRegisterAllCompiledInClasses (); }
将所有的 Class 都进行注册,此处使用的 InnerRegister
。
1 2 3 4 5 6 7 8 void UClassRegisterAllCompiledInClasses () { FClassDeferredRegistry& Registry = FClassDeferredRegistry::Get (); for (const FClassDeferredRegistry::FRegistrant& Registrant : Registry.GetRegistrations ()) { UClass* RegisteredClass = FClassDeferredRegistry::InnerRegister (Registrant); } }
1 2 3 4 5 6 7 static constexpr FClassRegisterCompiledInInfo ClassInfo[] = { { Z_Construct_UClass_UMyObject, UMyObject::StaticClass, TEXT ("UMyObject" ), &Z_Registration_Info_UClass_UMyObject, CONSTRUCT_RELOAD_VERSION_INFO (FClassReloadVersionInfo, sizeof (UMyObject), 1556497845U )}, };
此时调用 InnerRegister
本质就是调用 UMyObject::StaticClass
,最终调用的GetPrivateStaticClass
。
使用 GUObjectAllocator
分配内存,并使用 placement new 构造出该 Class,并设置属性。
InitializePrivateStaticClass
会调用 Register
将 Class 注册到 GFirstPendingRegistrant
链表中,这主要是为了之后能够保证每个 Object
都能被加入到一张全局的 Globals Table,最后注册 thunk 函数。这就把 Class Object 给构造出来了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 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, FUObjectCppClassStaticFunctions&& InCppClassStaticFunctions, UClass::StaticClassFunctionType InSuperClassFn, UClass::StaticClassFunctionType InWithinClassFn ) { ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject (sizeof (UClass), alignof (UClass), true ); ReturnClass = ::new (ReturnClass) UClass ( EC_StaticConstructor, Name, InSize, InAlignment, InClassFlags, InClassCastFlags, InConfigName, EObjectFlags (RF_Public | RF_Standalone | RF_Transient | RF_MarkAsNative | RF_MarkAsRootSet), InClassConstructor, InClassVTableHelperCtorCaller, MoveTemp (InCppClassStaticFunctions) ); InitializePrivateStaticClass ( InSuperClassFn (), ReturnClass, InWithinClassFn (), PackageName, Name ); RegisterNativeFunc (); }
在本文中注册的是 MyFunc
,因为它需要被蓝图调用。
1 2 3 4 5 6 7 8 void UMyObject::StaticRegisterNativesUMyObject () { UClass* Class = UMyObject::StaticClass (); static const FNameNativePtrPair Funcs[] = { { "MyFunc" , &UMyObject::execMyFunc }, }; FNativeFunctionRegistrar::RegisterFunctions (Class, Funcs, UE_ARRAY_COUNT (Funcs)); }
回到 ProcessNewlyLoadedUObjects
中, UObjectProcessRegistrants
就是将之前放入链表的 Object
取出来并放入一张全局的 Objects Table,同时还会将该 Class
所属的 Package
提前创建好,但不初始化,这点尤为重要。这段逻辑在 UObjectBase::DeferredRegister
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void ProcessNewlyLoadedUObjects (FName Package, bool bCanProcessNewlyLoadedObjects) { UClassRegisterAllCompiledInClasses (); bool bNewUObjects = false ; TArray<UClass*> AllNewClasses; while (GFirstPendingRegistrant || ClassRegistry.HasPendingRegistrations () || StructRegistry.HasPendingRegistrations () || EnumRegistry.HasPendingRegistrations ()) { bNewUObjects = true ; UObjectProcessRegistrants (); UObjectLoadAllCompiledInStructs (); FCoreUObjectDelegates::CompiledInUObjectsRegisteredDelegate.Broadcast (Package); UObjectLoadAllCompiledInDefaultProperties (AllNewClasses); } }
DoPendingPackageRegistrations
其实就会提前创建好 Package,和 Class 一样,提前创建好,但不初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 static void UObjectLoadAllCompiledInStructs () { FEnumDeferredRegistry& EnumRegistry = FEnumDeferredRegistry::Get (); FStructDeferredRegistry& StructRegistry = FStructDeferredRegistry::Get (); { SCOPED_BOOT_TIMING ("UObjectLoadAllCompiledInStructs - CreatePackages (could be optimized!)" ); EnumRegistry.DoPendingPackageRegistrations (); StructRegistry.DoPendingPackageRegistrations (); } EnumRegistry.DoPendingOuterRegistrations (true ); StructRegistry.DoPendingOuterRegistrations (true ); }
最后调用 Enum
和 Struct
的 OuterRegister。
1 2 3 4 5 6 7 8 9 10 11 12 13 void DoPendingOuterRegistrations (bool UpdateCounter) { int32 Num = Registrations.Num (); for (int32 Index = ProcessedRegistrations; Index < Num; ++Index) { OuterRegister (Registrations[Index]); } if (UpdateCounter) { ProcessedRegistrations = Num; } }
在这把 OuterRegister 取出来,方便阅读,无论是调用 GetStaticEnum
还是 GetStaticStruct
最后都是调用 InnerRegister
,但此处需要注意在这我们将 UPackage
给初始化了, UPackage
一定是先创建好 但不初始化,等到此处才初始化 UPackage
然后调用内部的 InnerRegister
将其构造出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 static UEnum* EMyEnumClass_StaticEnum () { if (!Z_Registration_Info_UEnum_EMyEnumClass.OuterSingleton) { Z_Registration_Info_UEnum_EMyEnumClass.OuterSingleton = GetStaticEnum ( Z_Construct_UEnum_Reflection_EMyEnumClass, (UObject*)Z_Construct_UPackage__Script_Reflection (), TEXT ("EMyEnumClass" ) ); } return Z_Registration_Info_UEnum_EMyEnumClass.OuterSingleton; } class UScriptStruct* FMyStruct::StaticStruct () { if (!Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton) { Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton = GetStaticStruct ( Z_Construct_UScriptStruct_FMyStruct, (UObject*)Z_Construct_UPackage__Script_Reflection (), TEXT ("MyStruct" ) ); } return Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton; }
构造 UEnum
,调用 SetEnums
时会默认帮你加一个 _MAX
枚举项,同时将枚举注册到对应 PackageName
的 map 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void ConstructUEnum (UEnum*& OutEnum, const FEnumParams& Params) { UObject* (*OuterFunc)() = Params.OuterFunc; UObject* Outer = OuterFunc ? OuterFunc () : nullptr ; if (OutEnum) { return ; } UEnum* NewEnum = new (EC_InternalUseOnlyConstructor, Outer, UTF8_TO_TCHAR (Params.NameUTF8), Params.ObjectFlags) UEnum (FObjectInitializer ()); OutEnum = NewEnum; TArray<TPair<FName, int64>> EnumNames; EnumNames.Reserve (Params.NumEnumerators); for (const FEnumeratorParam* Enumerator = Params.EnumeratorParams, *EnumeratorEnd = Enumerator + Params.NumEnumerators; Enumerator != EnumeratorEnd; ++Enumerator) { EnumNames.Emplace (UTF8_TO_TCHAR (Enumerator->NameUTF8), Enumerator->Value); } const bool bAddMaxKeyIfMissing = true ; NewEnum->SetEnums (EnumNames, (UEnum::ECppForm)Params.CppForm, Params.EnumFlags, bAddMaxKeyIfMissing); NewEnum->CppType = UTF8_TO_TCHAR (Params.CppTypeUTF8); if (Params.DisplayNameFunc) { NewEnum->SetEnumDisplayNameFn (Params.DisplayNameFunc); } }
构造 Struct
, ConstructFProperties
构造里面的属性,属性没有数据,只有函数,属性的数据最终还是存放到 Struct
或者 Class
中,属性里面会记录数据存放的偏移值,计算偏移值的操作在 StaticLink
中实现,同时还会将 Property分类放到不同链表中,比如需要析构的 Property,需要构造后做一些事情的 Property(Config) 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void ConstructUScriptStruct (UScriptStruct*& OutStruct, const FStructParams& Params) { UObject* (*OuterFunc)() = Params.OuterFunc; UScriptStruct* (*SuperFunc)() = Params.SuperFunc; UScriptStruct::ICppStructOps* (*StructOpsFunc)() = (UScriptStruct::ICppStructOps* (*)())Params.StructOpsFunc; UObject* Outer = OuterFunc ? OuterFunc () : nullptr ; UScriptStruct* Super = SuperFunc ? SuperFunc () : nullptr ; UScriptStruct::ICppStructOps* StructOps = StructOpsFunc ? StructOpsFunc () : nullptr ; if (OutStruct) { return ; } UScriptStruct* NewStruct = new (EC_InternalUseOnlyConstructor, Outer, UTF8_TO_TCHAR (Params.NameUTF8), Params.ObjectFlags) UScriptStruct (FObjectInitializer (), Super, StructOps, (EStructFlags)Params.StructFlags, Params.SizeOf, Params.AlignOf); OutStruct = NewStruct; ConstructFProperties (NewStruct, Params.PropertyArray, Params.NumProperties); NewStruct->StaticLink (); }
回到 ProcessNewlyLoadedUObjects
函数中,UObjectLoadAllCompiledInDefaultProperties
是最后一个重点函数,它执行了所有 Class 的 OuterRegister,同时通知该 Class 注册完成。
DoPendingOuterRegistrations
就是执行了 OuterRegister。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 static void UObjectLoadAllCompiledInDefaultProperties (TArray<UClass*>& OutAllNewClasses) { static FName LongEnginePackageName (TEXT("/Script/Engine" )) ; FClassDeferredRegistry& ClassRegistry = FClassDeferredRegistry::Get (); if (ClassRegistry.HasPendingRegistrations ()) { SCOPED_BOOT_TIMING ("UObjectLoadAllCompiledInDefaultProperties" ); TArray<UClass*> NewClasses; TArray<UClass*> NewClassesInCoreUObject; TArray<UClass*> NewClassesInEngine; ClassRegistry.DoPendingOuterRegistrations (true , [&OutAllNewClasses, &NewClasses, &NewClassesInCoreUObject, &NewClassesInEngine](const TCHAR* PackageName, UClass& Class) -> void { UE_LOG (LogUObjectBootstrap, Verbose, TEXT ("UObjectLoadAllCompiledInDefaultProperties After Registrant %s %s" ), PackageName, *Class.GetName ()); if (Class.GetOutermost ()->GetFName () == GLongCoreUObjectPackageName) { NewClassesInCoreUObject.Add (&Class); } else if (Class.GetOutermost ()->GetFName () == LongEnginePackageName) { NewClassesInEngine.Add (&Class); } else { NewClasses.Add (&Class); } OutAllNewClasses.Add (&Class); }); auto NotifyClassFinishedRegistrationEvents = [](TArray<UClass*>& Classes) { for (UClass* Class : Classes) { TCHAR PackageName[FName::StringBufferSize]; TCHAR ClassName[FName::StringBufferSize]; Class->GetOutermost ()->GetFName ().ToString (PackageName); Class->GetFName ().ToString (ClassName); NotifyRegistrationEvent (PackageName, ClassName, ENotifyRegistrationType::NRT_Class, ENotifyRegistrationPhase::NRP_Finished, nullptr , false , Class); } }; { SCOPED_BOOT_TIMING ("NotifyClassFinishedRegistrationEvents" ); NotifyClassFinishedRegistrationEvents (NewClassesInCoreUObject); NotifyClassFinishedRegistrationEvents (NewClassesInEngine); NotifyClassFinishedRegistrationEvents (NewClasses); } { SCOPED_BOOT_TIMING ("CoreUObject Classes" ); for (UClass* Class : NewClassesInCoreUObject) { UE_LOG (LogUObjectBootstrap, Verbose, TEXT ("GetDefaultObject Begin %s %s" ), *Class->GetOutermost ()->GetName (), *Class->GetName ()); Class->GetDefaultObject (); UE_LOG (LogUObjectBootstrap, Verbose, TEXT ("GetDefaultObject End %s %s" ), *Class->GetOutermost ()->GetName (), *Class->GetName ()); } } { SCOPED_BOOT_TIMING ("Engine Classes" ); for (UClass* Class : NewClassesInEngine) { UE_LOG (LogUObjectBootstrap, Verbose, TEXT ("GetDefaultObject Begin %s %s" ), *Class->GetOutermost ()->GetName (), *Class->GetName ()); Class->GetDefaultObject (); UE_LOG (LogUObjectBootstrap, Verbose, TEXT ("GetDefaultObject End %s %s" ), *Class->GetOutermost ()->GetName (), *Class->GetName ()); } } { SCOPED_BOOT_TIMING ("Other Classes" ); for (UClass* Class : NewClasses) { UE_LOG (LogUObjectBootstrap, Verbose, TEXT ("GetDefaultObject Begin %s %s" ), *Class->GetOutermost ()->GetName (), *Class->GetName ()); Class->GetDefaultObject (); UE_LOG (LogUObjectBootstrap, Verbose, TEXT ("GetDefaultObject End %s %s" ), *Class->GetOutermost ()->GetName (), *Class->GetName ()); } } } }
Class 的 OuterRegister 如下:
1 2 3 4 5 6 7 8 UClass* Z_Construct_UClass_UMyObject () { if (!Z_Registration_Info_UClass_UMyObject.OuterSingleton) { UECodeGen_Private::ConstructUClass (Z_Registration_Info_UClass_UMyObject.OuterSingleton, Z_Construct_UClass_UMyObject_Statics::ClassParams); } return Z_Registration_Info_UClass_UMyObject.OuterSingleton; }
其实就是执行依赖项,然后通过 InnerRegister 创建一个新类, UObjectForceRegistration
注册到全局 Objects Table 中。 CreateLinkAndAddChildFunctionsToMap
其实就是执行 ConstructUFunction
来创建一个个成员函数,并将其加入到 FuncMap
,随后构建属性,并 Link,这部分逻辑和 Struct
一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 void ConstructUClass (UClass*& OutClass, const FClassParams& Params) { if (OutClass && (OutClass->ClassFlags & CLASS_Constructed)) { return ; } for (UObject* (*const *SingletonFunc)() = Params.DependencySingletonFuncArray, *(*const *SingletonFuncEnd)() = SingletonFunc + Params.NumDependencySingletons; SingletonFunc != SingletonFuncEnd; ++SingletonFunc) { (*SingletonFunc)(); } UClass* NewClass = Params.ClassNoRegisterFunc (); OutClass = NewClass; if (NewClass->ClassFlags & CLASS_Constructed) { return ; } UObjectForceRegistration (NewClass); UClass* SuperClass = NewClass->GetSuperClass (); if (SuperClass) { NewClass->ClassFlags |= (SuperClass->ClassFlags & CLASS_Inherit); } NewClass->ClassFlags |= (EClassFlags)(Params.ClassFlags | CLASS_Constructed); if ((NewClass->ClassFlags & CLASS_Intrinsic) != CLASS_Intrinsic) { check ((NewClass->ClassFlags & CLASS_TokenStreamAssembled) != CLASS_TokenStreamAssembled); NewClass->ReferenceSchema.Reset (); } NewClass->CreateLinkAndAddChildFunctionsToMap (Params.FunctionLinkArray, Params.NumFunctions); ConstructFProperties (NewClass, Params.PropertyArray, Params.NumProperties); if (Params.ClassConfigNameUTF8) { NewClass->ClassConfigName = FName (UTF8_TO_TCHAR (Params.ClassConfigNameUTF8)); } NewClass->SetCppTypeInfoStatic (Params.CppClassInfo); 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); } } NewClass->StaticLink (); NewClass->SetSparseClassDataStruct (NewClass->GetSparseClassDataArchetypeStruct ()); }
1 2 3 4 5 6 7 8 9 UFunction* Z_Construct_UFunction_UMyObject_MyFunc () { static UFunction* ReturnFunction = nullptr ; if (!ReturnFunction) { UECodeGen_Private::ConstructUFunction (&ReturnFunction, Z_Construct_UFunction_UMyObject_MyFunc_Statics::FuncParams); } return ReturnFunction; }
构造 UFunction
的内容就不细说了,Function 的 RPCId 就是在这里设置的,因为 Function 也是有参数的,所以也需要 StaticLink
。最后将 Function Bind 到 Outer 身上,也就是 Class 身上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 FORCEINLINE void ConstructUFunctionInternal (UFunction*& OutFunction, const FFunctionParams& Params, UFunction** SingletonPtr) { UObject* (*OuterFunc)() = Params.OuterFunc; UFunction* (*SuperFunc)() = Params.SuperFunc; UObject* Outer = OuterFunc ? OuterFunc () : nullptr ; UFunction* Super = SuperFunc ? SuperFunc () : nullptr ; if (OutFunction) { return ; } FName FuncName (UTF8_TO_TCHAR(Params.NameUTF8)) ; UFunction* NewFunction; if (Params.FunctionFlags & FUNC_Delegate) { if (Params.OwningClassName == nullptr ) { NewFunction = new (EC_InternalUseOnlyConstructor, Outer, FuncName, Params.ObjectFlags) UDelegateFunction ( FObjectInitializer (), Super, Params.FunctionFlags, Params.StructureSize ); } else { USparseDelegateFunction* NewSparseFunction = new (EC_InternalUseOnlyConstructor, Outer, FuncName, Params.ObjectFlags) USparseDelegateFunction ( FObjectInitializer (), Super, Params.FunctionFlags, Params.StructureSize ); NewSparseFunction->OwningClassName = FName (Params.OwningClassName); NewSparseFunction->DelegateName = FName (Params.DelegateName); NewFunction = NewSparseFunction; } } else { NewFunction = new (EC_InternalUseOnlyConstructor, Outer, FuncName, Params.ObjectFlags) UFunction ( FObjectInitializer (), Super, Params.FunctionFlags, Params.StructureSize ); } OutFunction = NewFunction; NewFunction->RPCId = Params.RPCId; NewFunction->RPCResponseId = Params.RPCResponseId; ConstructFProperties (NewFunction, Params.PropertyArray, Params.NumProperties); NewFunction->Bind (); NewFunction->StaticLink (); }
最后是 UPackage
的注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 static FPackageRegistrationInfo Z_Registration_Info_UPackage__Script_Reflection;FORCENOINLINE UPackage* Z_Construct_UPackage__Script_Reflection () { if (!Z_Registration_Info_UPackage__Script_Reflection.OuterSingleton) { static const UECodeGen_Private::FPackageParams PackageParams = { "/Script/Reflection" , nullptr , 0 , PKG_CompiledIn | 0x00000000 , 0xC0294C5F , 0x8700445F , METADATA_PARAMS (0 , nullptr ) }; UECodeGen_Private::ConstructUPackage (Z_Registration_Info_UPackage__Script_Reflection.OuterSingleton, PackageParams); } return Z_Registration_Info_UPackage__Script_Reflection.OuterSingleton; } struct FPackageParams { const char * NameUTF8; UObject* (*const *SingletonFuncArray)(); int32 NumSingletons; uint32 PackageFlags; uint32 BodyCRC; uint32 DeclarationsCRC; #if WITH_METADATA uint16 NumMetaData; const FMetaDataPairParam* MetaDataArray; #endif };
1 2 3 4 5 6 static FRegisterCompiledInInfo Z_CompiledInDeferPackage_UPackage__Script_Reflection ( Z_Construct_UPackage__Script_Reflection, TEXT("/Script/Reflection" ), Z_Registration_Info_UPackage__Script_Reflection, CONSTRUCT_RELOAD_VERSION_INFO(FPackageReloadVersionInfo, 0xC0294C5F , 0x8700445F );
Package
不是这个时候创建出来的,而是创建 Enum
等其他类型时,就提前创建好了,所以此处只是找出来。此处的 SingletonFuncArray
就是 Delegate
同一个代码包里的所有 Delegate
最终都会归集到这,可以看出它也是 Object
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 void ConstructUPackage (UPackage*& OutPackage, const FPackageParams& Params) { if (OutPackage) { return ; } UObject* FoundPackage = StaticFindObjectFast (UPackage::StaticClass (), nullptr , FName (UTF8_TO_TCHAR (Params.NameUTF8)), false ); checkf (FoundPackage, TEXT ("Code not found for generated code (package %s)." ), UTF8_TO_TCHAR (Params.NameUTF8)); UPackage* NewPackage = CastChecked <UPackage>(FoundPackage); OutPackage = NewPackage; NewPackage->SetPackageFlags (Params.PackageFlags); TCHAR PackageName[FName::StringBufferSize]; NewPackage->GetFName ().ToString (PackageName); for (UObject* (*const *SingletonFunc)() = Params.SingletonFuncArray, *(*const *SingletonFuncEnd)() = SingletonFunc + Params.NumSingletons; SingletonFunc != SingletonFuncEnd; ++SingletonFunc) { UObject* Object = (*SingletonFunc)(); if (Object->GetOuter () == NewPackage) { TCHAR ObjectName[FName::StringBufferSize]; Object->GetFName ().ToString (ObjectName); NotifyRegistrationEvent (PackageName, ObjectName, ENotifyRegistrationType::NRT_NoExportObject, ENotifyRegistrationPhase::NRP_Finished, nullptr , false , Object); } } }
总结 C++ 代码会被 UHT 工具扫描,并将相应的宏替换为辅助代码,同时去掉空宏,最终每个文件都会有一个 FRegisterCompiledInfo
的 static struct,执行该构造函数后,将反射信息全都注册到 TDeferredRegistry
中。
注册完成之后,引擎启动时,会调用到 ProcessNewlyLoadedUObject
。
构建 Class 的 Inner,并创建对应的 Package。 构建 Enum 和 Struct 的 Outer,Outer 会立刻构建 Inner。 构建 Class 的 Outer,构建里面的属性和成员函数。 通知构建完成,在 NotifyRegistrationComplete
检查是否都完成创建。