UE4中反射用于什么情况?
#define UPROPERTY(...)
#define UFUNCTION(...)
#define USTRUCT(...)
#define UMETA(...)
#define UPARAM(...)
#define UENUM(...)
#define UDELEGATE(...)
// 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);
当我们给变量/函数/类/结构体添加U###的时候,UHT就会帮助我们实现反射机制
C++与蓝图交互,UE4的变量回收系统,几乎UE4所有的Module都利用了反射机制
UBT和UHT介绍
UnrealBuildTool(UBT):UE4来编译各个模块之间的依赖
UnrealHeaderTool(UHT,C++编译器强化版):UE4 C++代码编译。UHT利用.generated.h信息生成C++反射代码。完成后,再调用普通的C++编译器
启动UE4编译时,UE4首先调用UHT,检索.h中的UCLASS、GENERATED_BODY、UPROPERTY、UFUNTION等关键字,然后生成generate.h和generate.cpp文件
生成阶段
helloworld.generated.h文件中
GENERATED_BODY
#define GENERATED_BODY_LEGACY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY_LEGACY);
对于某个类的GENERATED_BODY来说,CURRENT_FILE_ID定义在该文件的.generated.h文件中
DECLARE_FUNCTION
- NavtiveFuncTest定义BlueprintNativeEvent,蓝图和C++均可以实现。在C++中实现的方法要加上NavtiveFuncTest_Implementation(),因为UBT内部已经实现这部分的定义?(理由见下)
- DECLARE_FUNCTION(execNavtiveFuncTest)。声明一个函数为execNavtiveFuncTest,会优先调用蓝图方法,如果不存在的话再调用C++的NavtiveFuncTest_Implementation()
DECLARE_CLASS
private: \
static void StaticRegisterNativesAHelloGameMode(); \
friend struct Z_Construct_UClass_AHelloGameMode_Statics; \
public: \
DECLARE_CLASS(AHelloGameMode, AGameModeBase, COMPILED_IN_FLAGS(0 | CLASS_Transient), CASTCLASS_None, TEXT("/Script/helloworld"), NO_API) \
DECLARE_SERIALIZER(AHelloGameMode)
Generated.cpp文件中
ProcessEvent
static FName NAME_AHelloGameMode_NavtiveFuncTest = FName(TEXT("NavtiveFuncTest"));
void AHelloGameMode::NavtiveFuncTest()
{
ProcessEvent(FindFunctionChecked(NAME_AHelloGameMode_NavtiveFuncTest),NULL);
}
很明显,在.cpp文件中,NativeFuncTest函数已经被自动生成。因此对于都可用&&蓝图>C++优先级的情况下,需要加上_Implementablement来声明,否则会报错已经定义
IMPLEMENT_CLASS
MPLEMENT_CLASS(AHelloGameMode, 3705664059);
template<> HELLOWORLD_API UClass* StaticClass<AHelloGameMode>()
{
return AHelloGameMode::StaticClass();
}
收集阶段(利用Static自动注册方式,将UCLASS登记,放进Array统一管理)
在收集阶段(上一阶段)在IMPLEMENT_CLASS和ConstructClass两个函数中静态声明了两个变量
#define IMPLEMENT_CLASS(TClass, TClassCrc) \
static TClassCompiledInDefer<TClass> AutoInitialize##TClass(TEXT(#TClass), sizeof(TClass), TClassCrc); \
和
static FCompiledInDefer Z_CompiledInDefer_UClass_##TClass(Z_Construct_UClass_##TClass, &TClass::StaticClass, TEXT(TPackage), TEXT(#TClass), false);
- TClassCompiledInDefer(调用UClassCompiledInDefer收集数据)是分配空间
- FCompiledInDefer(调用UObjectCompiledInDefer收集数据),调用初始化函数
- 并且将注册信息放入ClassInfo延迟注册,如果类太多,全部都要注册会很卡
void ProcessNewlyLoadedUObjects(FName Package, bool bCanProcessNewlyLoadedObjects)
{
UClassRegisterAllCompiledInClasses();
const TArray<UClass* (*)()>& DeferredCompiledInRegistration = GetDeferredCompiledInRegistration();
const TArray<FPendingStructRegistrant>& DeferredCompiledInStructRegistration = GetDeferredCompiledInStructRegistration();
const TArray<FPendingEnumRegistrant>& DeferredCompiledInEnumRegistration = GetDeferredCompiledInEnumRegistration();
bool bNewUObjects = false;
while (GFirstPendingRegistrant || DeferredCompiledInRegistration.Num() || DeferredCompiledInStructRegistration.Num() || DeferredCompiledInEnumRegistration.Num())
{
bNewUObjects = true;
UObjectProcessRegistrants();
UObjectLoadAllCompiledInStructs();
UObjectLoadAllCompiledInDefaultProperties();
}
}
ProcessNewlyLoadedUObjects用于注册类,结构体,枚举的反射信息
收集阶段
通过UClassCompiledInDefer收集
在Static Array里添加ClassInfo→Register()→StaticClass()→GetPrivateStaticClass()→GetPrivateStaticClassBody()
GetPrivateStaticClassBody():分配内存,
通过UObjectCompiledInDefer收集