之前写了两篇 UE 中实现反射的文章分析,介绍了 UE 的反射基础概念和依赖的一些 C++ 特性,本篇文章开始分析 UE 反射实现的具体流程。
C++ 标准中并没有反射的特性,UE 使用的反射是基于 标记语法 和UHT 扫描生成辅助代码 来实现的一套机制,正如 David Wheeler 的那句名言一样:“All problems in computer science can be solved by another level of indirection”,UHT 做的就是这样的事情,在真正执行编译之前分析标记代码并产生真正的 C++ 代码,收集反射类型的元数据,供运行时之用。
// This pair of macros is used to help implement GENERATED_BODY() and GENERATED_USTRUCT_BODY() #define BODY_MACRO_COMBINE_INNER(A,B,C,D) A##B##C##D #define BODY_MACRO_COMBINE(A,B,C,D) BODY_MACRO_COMBINE_INNER(A,B,C,D)
// Include a redundant semicolon at the end of the generated code block, so that intellisense parsers can start parsing // a new declaration if the line number/generated code is out of date. #define GENERATED_BODY_LEGACY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY_LEGACY); #define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY);
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. /*=========================================================================== Generated code exported from UnrealHeaderTool. DO NOT modify this manually! Edit the corresponding .h files instead! ===========================================================================*/
#define ReflectionExample_Source_ReflectionExample_NetActor_h_8_STANDARD_CONSTRUCTORS \ /** Standard constructor, called after all reflected properties have been initialized */ \ NO_API ANetActor(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \ DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(ANetActor) \ DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, ANetActor); \ DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(ANetActor); \ private: \ /** Private move- and copy-constructors, should never be used */ \ NO_API ANetActor(ANetActor&&); \ NO_API ANetActor(const ANetActor&); \ public:
#define ReflectionExample_Source_ReflectionExample_NetActor_h_8_ENHANCED_CONSTRUCTORS \ /** Standard constructor, called after all reflected properties have been initialized */ \ NO_API ANetActor(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \ private: \ /** Private move- and copy-constructors, should never be used */ \ NO_API ANetActor(ANetActor&&); \ NO_API ANetActor(const ANetActor&); \ public: \ DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, ANetActor); \ DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(ANetActor); \ DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(ANetActor)
/** Standard constructor, called after all reflected properties have been initialized */ NO_API ANetActor(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; private: /** Private move- and copy-constructors, should never be used */ NO_API ANetActor(ANetActor&&); NO_API ANetActor(const ANetActor&); public: DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, ANetActor); DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(ANetActor); DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(ANetActor)
public: // DECLARE_CLASS(ANetActor, AActor, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/ReflectionExample"), NO_API) /** Bitwise union of #EClassFlags pertaining to this class.*/ enum {StaticClassFlags=COMPILED_IN_FLAGS(0)}; /** Typedef for the base class ({{ typedef-type }}) */ typedef AActor Super /** Typedef for {{ typedef-type }}. */ typedef ANetActor ThisClass /** Returns a UClass object representing this class at runtime */ inlinestatic UClass* StaticClass() { returnGetPrivateStaticClass(); } /** Returns the package this class belongs in */ inlinestaticconst TCHAR* StaticPackage() { returnTEXT("/Script/ReflectionExample"); } /** Returns the static cast flags for this class */ inlinestatic EClassCastFlags StaticClassCastFlags() { return CASTCLASS_None; } /** For internal use only; use StaticConstructObject() to create new objects. */ inlinevoid* operatornew(constsize_t InSize, EInternal InInternalOnly, UObject* InOuter = (UObject*)GetTransientPackage(), FName InName = NAME_None, EObjectFlags InSetFlags = RF_NoFlags) { returnStaticAllocateObject(StaticClass(), InOuter, InName, InSetFlags); } /** For internal use only; use StaticConstructObject() to create new objects. */ inlinevoid* operatornew(constsize_t InSize, EInternal* InMem ) { return (void*)InMem; }
/** Standard constructor, called after all reflected properties have been initialized */ NO_API ANetActor(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; private: /** Private move- and copy-constructors, should never be used */ NO_API ANetActor(ANetActor&&); NO_API ANetActor(const ANetActor&); public: // DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, ANetActor); static UObject* __VTableCtorCaller(FVTableHelper& Helper) { returnnullptr; } // DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(ANetActor); /** DO NOT USE. This constructor is for internal usage only for hot-reload purposes. */ \ API ANetActor(FVTableHelper& Helper);
// This macro is used to declare a thunk function in autogenerated boilerplate code #define DECLARE_FUNCTION(func) static void func(UObject* Context, FFrame& Stack, RESULT_DECL)
// This macro is used to define a thunk function in autogenerated boilerplate code #define DEFINE_FUNCTION(func) void func(UObject* Context, FFrame& Stack, RESULT_DECL)
// This macro is used to declare a thunk function in autogenerated boilerplate code #define DECLARE_FUNCTION(func) static void func(UObject* Context, FFrame& Stack, RESULT_DECL) // This macro is used to define a thunk function in autogenerated boilerplate code #define DEFINE_FUNCTION(func) void func(UObject* Context, FFrame& Stack, RESULT_DECL)
在我之前的文章中有提到过,C++ 的成员函数和非成员函数本质没有区别,只不过 C++ 的成员函数有一个隐式的 this 指针参数,这个 DECLARE_FUNCTION 处理的思想也一样,可以把成员和非成员函数通过这种形式统一起来,至于 Context 自然就是传统 C++ 的那个 隐式 this 指针 了,代表着当前调用该成员函数的对象。