UE4类型数据自动注册

Version:4.26.2
UE4 C++工程名:MyProject

《宏GENERATED_BODY做了什么?》中,简单分析了GENERATED_BODY宏给一个简单的、继承自UObject的自定义类添加了什么。

当中涉及到的源码文件有: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<UMyObject>::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<UMyObject> 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<UMyObject>,
				(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<UMyObject>,
				&UMyObject::AddReferencedObjects,
				&UMyObject::Super::StaticClass,
				&UMyObject::WithinClass::StaticClass
			);
		}
		return PrivateStaticClass;
	}
	template<> MYPROJECT_API UClass* StaticClass<UMyObject>()
	{
		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<FName, FName>&) = nullptr)
	{
		if (bDynamic)
		{
			GetConvertedDynamicPackageNameToTypeName().Add(FName(DynamicPackageName), FName(Name));
		}
		UObjectCompiledInDefer(InRegister, InStaticClass, Name, PackageName, bDynamic, DynamicPathName, InInitSearchableValues);
	}
};

构造函数内部直接调用了UObjectCompiledInDefer(...)函数;

由于参数bDynamic=false,函数UObjectCompiledInDefer(...)内部有效的代码如下:

	TArray<UClass *(*)()>& DeferredCompiledInRegistration = GetDeferredCompiledInRegistration();
	checkSlow(!DeferredCompiledInRegistration.Contains(InRegister));
	DeferredCompiledInRegistration.Add(InRegister);

函数GetDeferredCompiledInRegistration()定义如下:

static TArray<class UClass *(*)()>& GetDeferredCompiledInRegistration()
{
	static TArray<class UClass *(*)()> DeferredCompiledInRegistration;
	return DeferredCompiledInRegistration;
}

内部的数组DeferredCompiledInRegistration也是静态对象;

参数InRegister这个函数指针加入DeferredCompiledInRegistration数组中;

即函数Z_Construct_UClass_UMyObject地址会被加入到DeferredCompiledInRegistration数组中;


TClassCompiledInDefer类:

【关注点-2】这个类同样定义在UObjectBase.h文件中;

与FCompiledInDefer写法类似

区别是这里将static TClassCompiledInDefer<UMyObject> 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中有什么东西;

并且分下了一下关键的注册机制;

在MyObject.gen.cpp中,通过静态对象的特性(程序加载时就会被创建,并且时间早于main函数),收集自定义类的信息:

  • 通过static TClassCompiledInDefer<UMyObject> AutoInitializeUMyObject对象,收集名字、size、一个唯一ID;
  • 通过static FCompiledInDefer Z_CompiledInDefer_UClass_UMyObject对象,注册一个函数,该函数返回一个UClass对象,该对象用来描述UMyObject类;

需要重复指出的是,整个类型信息注册的时机是在程序加载阶段,要早于main函数;

这里用来测试的时一个没有方法、没有属性的简单类;

但类型自动注册的总体机制是相同的。

完结

posted @ 2021-12-06 20:54  阿佑001  阅读(293)  评论(0编辑  收藏  举报