UE4类型数据自动注册
Version:4.26.2在《宏GENERATED_BODY做了什么?》中,简单分析了GENERATED_BODY宏给一个简单的、继承自UObject的自定义类添加了什么。
UE4 C++工程名:MyProject
当中涉及到的源码文件有:ObjectMacros.h、MyObject.h、MyObject.generated.h, UObjectGlobals.h;
现在来分析一下UHT生成的另外一个文件:MyObject.gen.cpp
当中会额外涉及到的源文件有:UObjectBase.h, UObjectBase.cpp, Class.h, Class.cpp, UObjectGlobals.cpp
MyObject.gen.cpp中有什么? 先无脑贴一下代码,部分会添加中文注释
// Copyright Epic Games, Inc. All Rights Reserved.
/*===========================================================================
Generated code exported from UnrealHeaderTool.
DO NOT modify this manually! Edit the corresponding .h files instead!
===========================================================================*/#include "UObject/GeneratedCppIncludes.h"
#include "MyProject/Public/MyObject.h"
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable : 4883)
#endif
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCodeMyObject() {}
// Cross Module References
MYPROJECT_API UClass* Z_Construct_UClass_UMyObject_NoRegister();
MYPROJECT_API UClass* Z_Construct_UClass_UMyObject();
COREUOBJECT_API UClass* Z_Construct_UClass_UObject();
UPackage* Z_Construct_UPackage__Script_MyProject();
// End Cross Module References
void UMyObject::StaticRegisterNativesUMyObject()
{
}
UClass* Z_Construct_UClass_UMyObject_NoRegister()
{
return UMyObject::StaticClass();
}
struct Z_Construct_UClass_UMyObject_Statics
{
static UObject* (*const DependentSingletons[])();
#if WITH_METADATA
static const UE4CodeGen_Private::FMetaDataPairParam Class_MetaDataParams[];
#endif
static const FCppClassTypeInfoStatic StaticCppClassTypeInfo;
static const UE4CodeGen_Private::FClassParams ClassParams;
};
UObject* (*const Z_Construct_UClass_UMyObject_Statics::DependentSingletons[])() = {
(UObject* (*)())Z_Construct_UClass_UObject,
(UObject* (*)())Z_Construct_UPackage__Script_MyProject,
};
#if WITH_METADATA
const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UClass_UMyObject_Statics::Class_MetaDataParams[] = {
{ "BlueprintType", "true" },
{ "Comment", "/**\n *n */" },
{ "IncludePath", "MyObject.h" },
{ "ModuleRelativePath", "Public/MyObject.h" },
{ "ObjectInitializerConstructorDeclared", "" },
};
#endif
const FCppClassTypeInfoStatic Z_Construct_UClass_UMyObject_Statics::StaticCppClassTypeInfo = {
TCppClassTypeTraits::IsAbstract,
};
// UE_ARRAY_COUNT宏计算数组的大小
// METADATA_PARAMS简单的宏拆成两个参数,或者支取第二个宏;根据WITH_METADATA宏是否有定义;参看UObjectGlobals.h源文件中的定义
const UE4CodeGen_Private::FClassParams Z_Construct_UClass_UMyObject_Statics::ClassParams = {
&UMyObject::StaticClass,
nullptr,
&StaticCppClassTypeInfo,
DependentSingletons,
nullptr,
nullptr,
nullptr,
UE_ARRAY_COUNT(DependentSingletons),
0,
0,
0,
0x001000A0u,
METADATA_PARAMS(Z_Construct_UClass_UMyObject_Statics::Class_MetaDataParams, UE_ARRAY_COUNT(Z_Construct_UClass_UMyObject_Statics::Class_MetaDataParams)) };
// 关注点-1
UClass* Z_Construct_UClass_UMyObject()
{
static UClass* OuterClass = nullptr;
if (!OuterClass)
{
UE4CodeGen_Private::ConstructUClass(OuterClass, Z_Construct_UClass_UMyObject_Statics::ClassParams);
}
return OuterClass;
}
// IMPLEMENT_CLASS(UMyObject, 1944586990);
// 下面时宏展开后的代码
// 关注点-2
static TClassCompiledInDefer AutoInitializeUMyObject(TEXT("UMyObject"), sizeof(UMyObject), 1944586990);
UClass* UMyObject::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("UMyObject") + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0),
PrivateStaticClass,
StaticRegisterNativesUMyObject,
sizeof(UMyObject),
alignof(UMyObject),
(EClassFlags)UMyObject::StaticClassFlags,
UMyObject::StaticClassCastFlags(),
UMyObject::StaticConfigName(),
(UClass::ClassConstructorType)InternalConstructor,
(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller,
&UMyObject::AddReferencedObjects,
&UMyObject::Super::StaticClass,
&UMyObject::WithinClass::StaticClass
);
}
return PrivateStaticClass;
}
template<> MYPROJECT_API UClass* StaticClass()
{
return UMyObject::StaticClass();
}
// 关注点-3
static FCompiledInDefer Z_CompiledInDefer_UClass_UMyObject(Z_Construct_UClass_UMyObject, &UMyObject::StaticClass, TEXT("/Script/MyProject"), TEXT("UMyObject"), false, nullptr, nullptr, nullptr);
// DEFINE_VTABLE_PTR_HELPER_CTOR(UMyObject);
// 下面时宏展开后的代码
UMyObject::UMyObject(FVTableHelper& Helper) : Super(Helper) {};
PRAGMA_ENABLE_DEPRECATION_WARNINGS
#ifdef _MSC_VER
#pragma warning (pop)
#endif
上面代码中加了三个关注点注释,下面是一点分析
分析 上面罗列了一下MyObject.gen.cpp文件的内容,下面来分析一下关注点
FCompiledInDefer类 先看【关注点-3】吧,该类定义在UObjectBase.h文件中:
struct FCompiledInDefer
{
FCompiledInDefer(class UClass *(*InRegister)(), class UClass *(*InStaticClass)(), const TCHAR* PackageName, const TCHAR* Name, bool bDynamic, const TCHAR* DynamicPackageName = nullptr, const TCHAR* DynamicPathName = nullptr, void (*InInitSearchableValues)(TMap&) = nullptr)
{
if (bDynamic)
{
GetConvertedDynamicPackageNameToTypeName().Add(FName(DynamicPackageName), FName(Name));
}
UObjectCompiledInDefer(InRegister, InStaticClass, Name, PackageName, bDynamic, DynamicPathName, InInitSearchableValues);
}
};
构造函数内部直接调用了
UObjectCompiledInDefer(...)
函数;由于参数
bDynamic=false
,函数UObjectCompiledInDefer(...)
内部有效的代码如下: TArray& DeferredCompiledInRegistration = GetDeferredCompiledInRegistration();
checkSlow(!DeferredCompiledInRegistration.Contains(InRegister));
DeferredCompiledInRegistration.Add(InRegister);
函数
GetDeferredCompiledInRegistration()
定义如下:static TArray& GetDeferredCompiledInRegistration()
{
static TArray DeferredCompiledInRegistration;
return DeferredCompiledInRegistration;
}
内部的数组
DeferredCompiledInRegistration
也是静态对象;参数
InRegister
这个函数指针加入DeferredCompiledInRegistration
数组中;即函数
Z_Construct_UClass_UMyObject
地址会被加入到DeferredCompiledInRegistration
数组中;TClassCompiledInDefer类: 【关注点-2】这个类同样定义在UObjectBase.h文件中;
与FCompiledInDefer写法类似
区别是这里将
static TClassCompiledInDefer AutoInitializeUMyObject
这个对象加入另了一个静态数组中;这里不再赘述了;
函数UClass* Z_Construct_UClass_UMyObject() 【关注点-1】有啥好说的呢?
上面分析,这个函数通过函数指针被添加到静态数组
DeferredCompiledInRegistration
;
这里需要关注:
- 它的返回值,是一个UClass对象;
- 内部
ConstructUClass
函数调的第二个参数是Z_Construct_UClass_UMyObject_Statics::ClassParams
, 这正是上半部分代码对UMyObject类信息的收集数据
ConstructUClass
这个函数定义在UObjectGlobals.h/UObjectGlobals.cpp文件中;分析结果
- 结合前面《宏GENERATED_BODY做了什么?》里面的分析,这里会得到一个调用堆栈:
Z_Construct_UClass_UMyObject(...) -> ConstructUClass(...) -> UMyObject::StaticClass() -> UMyObject::GetPrivateStaticClass() -> GetPrivateStaticClassBody(...)
- 并且从
GetPrivateStaticClass()
中就可以看出,一个自定义类只会创建一个UClass对象; - 函数
Z_Construct_UClass_UMyObject
只是做了注册,真正调用的时候是在引擎初始阶段;
并且分下了一下关键的注册机制;
在MyObject.gen.cpp中,通过静态对象的特性(程序加载时就会被创建,并且时间早于main函数),收集自定义类的信息:
- 通过
static TClassCompiledInDefer
对象,收集名字、size、一个唯一ID;AutoInitializeUMyObject - 通过
static FCompiledInDefer Z_CompiledInDefer_UClass_UMyObject
对象,注册一个函数,该函数返回一个UClass对象,该对象用来描述UMyObject类;
这里用来测试的时一个没有方法、没有属性的简单类;
但类型自动注册的总体机制是相同的。
【UE4类型数据自动注册】完结
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- 使用协程爬取网页,计算网页数据大小
- Java|Java基础——数组
- Python数据分析(一)(Matplotlib使用)
- Jsr303做前端数据校验
- Spark|Spark 数据倾斜及其解决方案
- 数据库设计与优化
- 爬虫数据处理HTML转义字符
- 数据库总结语句
- MySql数据库备份与恢复