我有故人抱剑去
斩尽春风未肯归
要解释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
中定义。
所以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
。
这样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
。
贴出完整代码:
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
指针数组中。
Z_Construct_UClass_UHH_Statics::PropPointers
则作为参数传入,创建了 Z_Construct_UClass_UHH_Statics::ClassParams
。
此时肯定注意到了 Z_Construct_UClass_UHH_Statics
结构体,ClassParams
正是该结构体中的一个静态成员:
也就是说,属性最终会注册到 Z_Construct_UClass_UHH_Statics::ClassParams
中,关于结构体Z_Construct_UClass_UHH_Statics
,先挖坑,后面和函数注册信息放一起接着讲。
成员函数 / UFUNCTION
函数 HHFunc
声明如下。
函数的注册是分两部分完成的,一个是注册函数名到函数指针的映射,另外就是函数签名信息的记录。
首先可以看到,UHT已经生成了一个前缀为 exec
的函数:
很显然,这是为了统一函数签名,并将不同函数签名的处理则封装在内部。
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
。
在引擎代码中,一步步跳转,寻找映射最终存储的位置:
会 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行对应):
同样会将参数和返回值信息,存储到 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
函数指针,在后续分析中仍然会用到,不要忘记!
除了结构体内部对齐等细节问题,目前还剩下三个疑问:
- ` ClassParams
最终用于生成
UClass对象吗?是的话,什么时候生成,在哪里生成?与调用
StaticClass()返回
UClass` 对象是什么关系? - 函数指针的收集是如何完成的?
- 如何利用两个全局静态变量的构造函数?
两个静态的全局变量直接在 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
宏判断后要执行的逻辑,均是用于在编辑器中显示,实际游戏发布不会有这些东西的。
2. 为什么存在__DefaultConstructor()
函数?
这是因为通过名字动态生成对象,而构造函数无法使用函数指针来直接指向,因此这里就用一个static函数包装一下,变成一个”平凡”的函数指针,而且所有类的签名一致,就可以在UClass里用一个函数指针里保存起来。
static void __DefaultConstructor(const FObjectInitializer& X)
{
new((EInternal*)X.GetObj())UHH(X);
}
这是C++的placement new的使用。
同时引擎里 Class.h 也有对应的声明:
也就是定义了一个函数指针,用于指向__DefaultConstructor()
。
3. 函数 Z_Construct_UPackage__Script_CCReflection()
的实现在哪,和UPackage的关系?
其实生成文件除了 *.generated.h 和 *.gen.cpp 以外,每个Package还有一个 *.init.gen.cpp 文件。
于是可以得到函数 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
对象。