【UE4】反射系统分析(二)

一、generated.h代码分析

这节主要分析一下generated.h文件中的代码。首选先创建一个继承AActor的类,并编译,UHT会生成一个generated.h文件。下边来分析一下AActor类中的GENERATED_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)
#define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY);

我们可以看到,GENERATED_BODY()的作用是把CURRENT_FILE_ID、_、_LINE_、_GENERATED_BODY这几个参数。
CURRENT_FILE_ID这个参数被UHT在generated.h中被定义为具体值,即类文件的id。

#define CURRENT_FILE_ID StartWork_Source_StartWork_Public_MyActor_h

__LINE__表示GENERATED_BODY()在类文件中声明的行号,此类中该宏在第12行被声明。
GENERATED_BODY()的声明
所以,GENERATED_BODY()被替换为StartWork_Source_StartWork_Public_MyActor_h_12_GENERATED_BODY,而该宏可在MyActor.generated.h中找到拓展。

#define StartWork_Source_StartWork_Public_TTTActor_h_12_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
	StartWork_Source_StartWork_Public_MyActor_h_12_PRIVATE_PROPERTY_OFFSET \
	StartWork_Source_StartWork_Public_MyActor_h_12_SPARSE_DATA \
	StartWork_Source_StartWork_Public_MyActor_h_12_RPC_WRAPPERS_NO_PURE_DECLS \
	StartWork_Source_StartWork_Public_MyActor_h_12_INCLASS_NO_PURE_DECLS \
	StartWork_Source_StartWork_Public_MyActor_h_12_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS

PRAGMA_DISABLE_DEPRECATION_WARNINGS和PRAGMA_ENABLE_DEPRECATION_WARNINGS分别是禁用和启用弃用警告。而public中的五个宏,前三个暂时是空定义,所以下面分别来展开后边两个宏。

1. INCLASS_NO_PURE_DECLS

private:
	//注册类的成员方法,注册后则可被蓝图(虚拟机)访问
	static void StaticRegisterNativesAMyActor();
	//友元结构体,在gen.cpp中定义,它用来描述该类的属性和成员数据等
	friend struct Z_Construct_UClass_AMyActor_Statics;
public:
	//定义类的常用方法与别名,如StaticClass、StaticPackage等方法,Super、ThisClass等。
	DECLARE_CLASS(AMyActor, AActor, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/StartWork"), NO_API)
	//定义该类的序列化方法
	DECLARE_SERIALIZER(AMyActor)

StaticRegisterNativesAMyActor
该静态方法将会把在C++类中定义并加入反射的函数方法进行注册。后边章节分析反射方法时再做具体介绍。

Z_Construct_UClass_AMyActor_Statics
将Z_Construct_UClass_AMyActor_Statics结构体声明为友元,友元类可以访问该类的private方法。该友元结构体被UHT在该类的gen.cpp中定义。该结构体包含该类的成员信息,可以理解为对该类的静态描述。

struct Z_Construct_UClass_AMyActor_Statics
{
	/********************************************************************************************/
	/*	DependentSingletons是一个空入参返回值是UObject指针的函数指针静态常量数组。					*/
	/*	UObject* (*const Z_Construct_UClass_ATTTActor_Statics::DependentSingletons[])() = {		*/
	/*	(UObject* (*)())Z_Construct_UClass_AActor,												*/
	/*	(UObject* (*)())Z_Construct_UPackage__Script_StartWork,									*/
	/********************************************************************************************/
	};
	static UObject* (*const DependentSingletons[])();	//依赖的单例函数指针数组
#if WITH_METADATA	//(WITH_EDITORONLY_DATA && WITH_EDITOR)
	//元数据的键值对数组,仅在编辑器模式启用
	static const UE4CodeGen_Private::FMetaDataPairParam Class_MetaDataParams[];
#endif
	//返回是否是抽象类
	static const FCppClassTypeInfoStatic StaticCppClassTypeInfo;
	//该变量包含类的成员参数信息
	static const UE4CodeGen_Private::FClassParams ClassParams;
};
/*	
struct FClassParams
{
	UClass*                                  (*ClassNoRegisterFunc)();
	UObject*                          		 (*const *DependencySingletonFuncArray)();
	int32                                    NumDependencySingletons;
	uint32                                   ClassFlags; // EClassFlags
	const FClassFunctionLinkInfo*            FunctionLinkArray;
	int32                                    NumFunctions;
	const FPropertyParamsBase* const*        PropertyArray;
	int32                                    NumProperties;
	const char*                              ClassConfigNameUTF8;
	const FCppClassTypeInfoStatic*           CppClassInfo;
	const FImplementedInterfaceParams*       ImplementedInterfaceArray;
	int32                                    NumImplementedInterfaces;
#if WITH_METADATA
	const FMetaDataPairParam*                MetaDataArray;
	int32                                    NumMetaData;
#endif
};
*/

DECLARE_CLASS
此宏将会声明并定义UObject类的常用方法和别名,比如我们常用的静态方法StaticClass来获取UClass对象以及Super来指代父类等。

//第一个参数为类名,第二个为父类名,第三个该类的标识符,第三个是可以转换的类,第四个是该类的包名,第四个是导出宏
DECLARE_CLASS(AMyActor, AActor, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/StartWork"), NO_API) 
//此宏展开为下面代码:
private: 
	//重载赋值操作符,把右值引用和常量引用赋值操作符放到private作用域下,目的是“禁用”常规的引用初始化方法
	AMyActor& operator=(AMyActor&&);   
	AMyActor& operator=(const AMyActor&);   
	//返回此类的UClass对象,下面的StaticClass调用此方法。该类在gen.cpp中的宏中定义
	NO_API static UClass* GetPrivateStaticClass(); 	
public: 
	/** EClassFlags的位运算适用于此类.*/ 
	enum {StaticClassFlags=EClassFlags::CLASS_Intrinsic}; /**EClassFlags枚举是用来描述类的标识符*/
	/** 为此列的父类起别名Super,方便使用 */ 
	typedef AActor Super;
	/** 为此类类型起别名ThisClass */ 
	typedef AMyActor ThisClass;
	/**返回表示此类运行时状态的UClass对象 */
	inline static UClass* StaticClass() { return GetPrivateStaticClass(); }
	/** 返回此类所属包,返回的是包名。可以通过FindPackage方法传入包名找到该包的UPackage对象。FindObject方法传入UPackage对象,可以在包的范围内搜索类 */
	inline static const TCHAR* StaticPackage() { return TEXT("/Script/StartWork"); }
	/** 返回这个类的静态转换标识符 */
	inline static EClassCastFlags StaticClassCastFlags()
	{/** EClassCastFlags是类型转换标识符,类的转换标识符是可继承的。*/
		return EClassCastFlags::CASTCLASS_None;
	}
	/** 仅供内部使用,使用StaticConstructObject()创建新的对象. */
	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); }
	/** 仅供内部使用,重写new方法,使用StaticConstructObject()创建新的对象. */
	inline void* operator new( const size_t InSize, EInternal* InMem ) { return (void*)InMem; }

DECLARE_SERIALIZER
此宏主要是定义序列化的方法。

DECLARE_SERIALIZER(AMyActor)
//此宏展开为下面代码:
friend FArchive &operator<<( FArchive& Ar, AMyActor*& Res ) { return Ar << (UObject*&)Res; } 
friend void operator<<(FStructuredArchive::FSlot InSlot, AMyActor*& Res) { InSlot << (UObject*&)Res; }

2. ENHANCED_CONSTRUCTORS

#define StartWork_Source_StartWork_Public_MyActor_h_12_ENHANCED_CONSTRUCTORS \
private: \
	/** 将赋值拷贝构造器放在private下,禁止开发者通过此方法创建对象*/ \
	NO_API AMyActor(AMyActor&&); \
	NO_API AMyActor(const AMyActor&); \
public: \
	//用于热重载的构造方法
	DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, AMyActor); \
	DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(AMyActor); \
	DEFINE_DEFAULT_CONSTRUCTOR_CALL(AMyActor)

DECLARE_VTABLE_PTR_HELPER_CTOR

DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, AMyActor);
//该宏展开后为下面代码:
NO_API AMyActor(FVTableHelper& Helper);/** 此构造器仅用于热重载。*/ 

DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER

DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(AMyActor);
//该宏展开后为以下代码:
static UObject* __VTableCtorCaller(FVTableHelper& Helper)
{
	return new (EInternal::EC_InternalUseOnlyConstructor, (UObject*)GetTransientPackage(), NAME_None, RF_NeedLoad | RF_ClassDefaultObject | RF_TagGarbageTemp) AMyActor(Helper); 
}

DEFINE_DEFAULT_CONSTRUCTOR_CALL

DEFINE_DEFAULT_CONSTRUCTOR_CALL(AMyActor)
//该宏展开后代码为:
static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())AMyActor; }

二、gen.cpp代码分析

void EmptyLinkFunctionForGeneratedCodeMyActor() {}
// 方法声明
STARTWORK_API UClass* Z_Construct_UClass_AMyActor_NoRegister();	//无注册构造UClass对象,直接返回StaticClass方法
STARTWORK_API UClass* Z_Construct_UClass_AMyActor();			//有注册构造UClass对象
ENGINE_API UClass* Z_Construct_UClass_AActor();					//AActor类的UClass对象构造方法,定义在Actor.gen.cpp文件中
UPackage* Z_Construct_UPackage__Script_StartWork();				//构造该模块UPackage对象的方法声明,该UPackage对象为静态成员
/** 该方法在ModuleName.init.gen.cpp中被定义
	UPackage* Z_Construct_UPackage__Script_StartWork()
	{
		static UPackage* ReturnPackage = nullptr;
		if (!ReturnPackage)
		{
			static const UE4CodeGen_Private::FPackageParams PackageParams = {
				"/Script/StartWork",			//NameUTF8,包名
				nullptr,						//SingletonFuncArray,单例函数指针数组
				0,								//NumSingletons,单例函数数量
				PKG_CompiledIn | 0x00000000,	//PackageFlags,包的标识符
				0xC86909DB,						//BodyCRC, 本体校验码
				0x2A968D62,						//DeclarationsCRC,声明校验码
				METADATA_PARAMS(nullptr, 0)		//MetaDataArray,NumMetaData,元数据数组和数量
			};
			UE4CodeGen_Private::ConstructUPackage(ReturnPackage, PackageParams);
		}
		return ReturnPackage;
	}
*/
//此函数会将类中使用UFUNCTION宏反射的方法注册,该方法在generated.h中声明。具体注册后续章节成员方法反射时分析。
void AMyActor::StaticRegisterNativesAMyActor(){}
//无注册构造UClass对象,直接返回StaticClass方法结果,即GetPrivateStaticClass方法构造的UClass对象
UClass* Z_Construct_UClass_AMyActor_NoRegister(){ return AMyActor::StaticClass(); }
//包含对类的描述数据,此结构体会根据类的定义增加更多成员变量,当前成员变量是创建默认Actor类的默认结构体的数据结构
struct Z_Construct_UClass_AMyActor_Statics
{
	static UObject* (*const DependentSingletons[])();
#if WITH_METADATA	//在编辑器模式下启用
	static const UE4CodeGen_Private::FMetaDataPairParam Class_MetaDataParams[];	//路径键值对参数
#endif
	/*struct FCppClassTypeInfoStatic { bool bIsAbstract; };*/
	static const FCppClassTypeInfoStatic StaticCppClassTypeInfo;
	static const UE4CodeGen_Private::FClassParams ClassParams;
};
/*************************************************************/
/*	后续四个赋值都是对上述结构体的静态成员变量初始化			 */
/*************************************************************/
//对上述结构体的静态成员DependentSingletons赋值
UObject* (*const Z_Construct_UClass_AMyActor_Statics::DependentSingletons[])() = {
	(UObject* (*)())Z_Construct_UClass_AActor,
	(UObject* (*)())Z_Construct_UPackage__Script_StartWork,
};
#if WITH_METADATA
//在编辑器模式时,将类文件在模块的路径和类文件名赋值到上述结构体的静态成员
const UE4CodeGen_Private::FMetaDataPairParam Z_Construct_UClass_AMyActor_Statics::Class_MetaDataParams[] = {
	{ "IncludePath", "MyActor.h" },
	{ "ModuleRelativePath", "Public/MyActor.h" },
};
#endif
//返回类的类型信息,即该类是否是抽象类
const FCppClassTypeInfoStatic Z_Construct_UClass_AMyActor_Statics::StaticCppClassTypeInfo = {
	TCppClassTypeTraits<AMyActor>::IsAbstract,
};
//初始化类的成员信息
const UE4CodeGen_Private::FClassParams Z_Construct_UClass_AMyActor_Statics::ClassParams = {
	&AMyActor::StaticClass,									//ClassNoRegisterFunc,函数指针,指向StaticClass方法(未注册方法)
	DependentSingletons, ARRAY_COUNT(DependentSingletons),	//DependencySingletonFuncArray, NumDependencySingletons
	0x009000A0u,				//ClassFlags,类的标识符
	nullptr, 0,					//FunctionLinkArray, NumFunctions分别是该类成员方法的数据数组和方法数量,后续分析
	nullptr, 0,					//PropertyArray, NumProperties分别是该类成员属性的数据数组和属性数量。若存在反射属性,则为Z_Construct_UClass_AMyActor_Statics::PropPointers, ARRAY_COUNT(Z_Construct_UClass_AMyActor_Statics::PropPointers)
	nullptr,					//ClassConfigNameUTF8,该类的配置名称,当该类被表示为config=ConfigName时有值
	&StaticCppClassTypeInfo,	//CppClassInfo,类的类型数据
	nullptr, 0,					//ImplementedInterfaceArray, NumImplementedInterfaces,实现的抽象类数据数组和数量
	METADATA_PARAMS(Z_Construct_UClass_AMyActor_Statics::Class_MetaDataParams, 		//MetaDataArray,只在编辑器模式有效的元数据参数数组
	ARRAY_COUNT(Z_Construct_UClass_AMyActor_Statics::Class_MetaDataParams))			//NumMetaData,元数据数量
};

//构造该类的UClass对象并注册
UClass* Z_Construct_UClass_AMyActor()
{
	static UClass* OuterClass = nullptr;
	if (!OuterClass)
	{
		UE4CodeGen_Private::ConstructUClass(OuterClass, Z_Construct_UClass_AMyActor_Statics::ClassParams);
	}
	return OuterClass;
}
//在启动时注册类
IMPLEMENT_CLASS(AMyActor, 788795244);
//类对象的延迟注册,IMPLEMENT_CLASS宏里包含类UClass对象的延迟注册
static FCompiledInDefer Z_CompiledInDefer_UClass_AMyActor(Z_Construct_UClass_AMyActor, &AMyActor::StaticClass, TEXT("/Script/StartWork"), TEXT("AMyActor"), false, nullptr, nullptr, nullptr);
DEFINE_VTABLE_PTR_HELPER_CTOR(AMyActor);
/* 展开之后为:AMyActor::AMyActor(FVTableHelper& Helper) : Super(Helper) {};  */

IMPLEMENT_CLASS

包含两个内容,一个是UClass对象的延迟注册,一个是(无注册)构造/获取类的UClass对象。

//第一个参数是类型名,第二个参数是CRC(校验码)
IMPLEMENT_CLASS(AMyActor, 788795244);
//展开宏后:
/*AutoInitializeAMyActor是一个延迟编译对象。当构造该对象时,若是热加载模式,
则会通过延迟注册表获取旧的延迟编译对象和当前延迟编译对象比较,若有修改,则会更新延迟注册表。
当非热加载时,则直接创建/更新延迟注册表。
该变量是一个静态变量,且变量初始化时会注册延迟注册表。所以当启动程序时,便会执行此方法,将该类注册,且只执行一遍。*/
static TClassCompiledInDefer<AMyActor> AutoInitializeAMyActor(TEXT("AMyActor"), sizeof(AMyActor), 788795244); 
//StaticClass返回该方法的返回值。创建一个静态UClass对象,第一次执行时初始化该对象。
UClass* AMyActor::GetPrivateStaticClass() 
{ 
	static UClass* PrivateStaticClass = NULL; 
	if (!PrivateStaticClass) 
	{ 
		GetPrivateStaticClassBody( 
			StaticPackage(), 								//返回包名的方法
			(TCHAR*)TEXT("AMyActor") + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), 	//类名
			PrivateStaticClass, 							//UClass对象指针
			StaticRegisterNativesAMyActor, 					//注册成员方法的函数指针
			sizeof(AMyActor), 								//该类的大小
			(EClassFlags)AMyActor::StaticClassFlags, 		//类标识符
			AMyActor::StaticClassCastFlags(), 				//类转换标识符
			AMyActor::StaticConfigName(), 					//类作配置文件时的名称
			(UClass::ClassConstructorType)InternalConstructor<AMyActor>, 	//UClass对象内部构建函数指针,其实就是__DefaultConstructor方法
			(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<AMyActor>, 	//热重载回调函数指针,__VTableCtorCaller方法
			&AMyActor::AddReferencedObjects, 				//添加引用对象的函数指针
			&AMyActor::Super::StaticClass, 					//获取父类UClass对象指针的函数指针
			&AMyActor::WithinClass::StaticClass 			//UObjet的StaticClass方法
		); 
	} 
	return PrivateStaticClass; 
}

三、UClass的构造及注册

void ConstructUClass(UClass*& OutClass, const FClassParams& Params)
{
	//如果UClass对象有效,且对象包含已构造标识符,则直接返回
	if (OutClass && (OutClass->ClassFlags & CLASS_Constructed)) { return; }	
	//执行依赖函数,创建构造该UClass依赖的父类UClass对象和UPackage包对象。
	for (UObject* (*const *SingletonFunc)() = Params.DependencySingletonFuncArray, *(*const *SingletonFuncEnd)() = SingletonFunc + Params.NumDependencySingletons; SingletonFunc != SingletonFuncEnd; ++SingletonFunc)
	{ (*SingletonFunc)(); }
	//获取未注册UClass对象
	UClass* NewClass = Params.ClassNoRegisterFunc();
	OutClass = NewClass;
	//如果获取的UClass对象已经构造(包含构造完成标识符),则返回
	if (NewClass->ClassFlags & CLASS_Constructed) { return; }	
	//强制注册类的UClass对象。将等待注册的对象添加到延迟注册。
	UObjectForceRegistration(NewClass);							
/**
	//UObjectForceRegistration的代码为:
	//获取等待注册表
	TMap<UObjectBase*, FPendingRegistrantInfo>& PendingRegistrants = FPendingRegistrantInfo::GetMap();	
	//在等待注册表中查找是否存在该对象
	FPendingRegistrantInfo* Info = PendingRegistrants.Find(NewClass);
	//如果等待注册表中存在该UClass对象等待被注册则将其延迟注册。
	if (Info)									
	{			
		const TCHAR* PackageName = Info->PackageName;		//获取UClass对象所在包名
		const TCHAR* Name = Info->Name;						//获取UClass名称
		PendingRegistrants.Remove(NewClass);  				//先从等待注册表中移除,防止重复注册
		NewClass->DeferredRegister(UClass::StaticClass(),PackageName,Name);		//延迟注册
	}
*/
	UClass* SuperClass = NewClass->GetSuperClass();	
	//如果父类标识符包含可继承,则将其添加到当前类的标识符中
	if (SuperClass)	{ NewClass->ClassFlags |= (SuperClass->ClassFlags & CLASS_Inherit); }
	//将Params参数参数中的类标识符和已构造标识符添加到
	NewClass->ClassFlags |= (EClassFlags)(Params.ClassFlags | CLASS_Constructed);	
	// Make sure the reference token stream is empty since it will be reconstructed later on
	// This should not apply to intrinsic classes since they emit native references before AssembleReferenceTokenStream is called.
	if ((NewClass->ClassFlags & CLASS_Intrinsic) != CLASS_Intrinsic)
	{
		check((NewClass->ClassFlags & CLASS_TokenStreamAssembled) != CLASS_TokenStreamAssembled);
		NewClass->ReferenceTokenStream.Empty();
	}
	//创建成员函数链接表。构造(获取)成员函数的UFunction指针,形成链表并将UFunction对象保存到函数表(FuncMap)。
	//FindFunction函数即是调用FuncMap,通过函数名进行查找。
	NewClass->CreateLinkAndAddChildFunctionsToMap(Params.FunctionLinkArray, Params.NumFunctions);
	//构造成员属性,下节分析
	ConstructUProperties(NewClass, Params.PropertyArray, Params.NumProperties);
	//设置配置目录名,如果没有设置的话,一般为类名
	if (Params.ClassConfigNameUTF8) { NewClass->ClassConfigName = FName(UTF8_TO_TCHAR(Params.ClassConfigNameUTF8)); }
	//设置类型信息,是否是抽象类
	NewClass->SetCppTypeInfoStatic(Params.CppClassInfo);
	//遍历类实现的接口,并获取它们的UClass对象,将其添加到此类UClass对象中。
	if (int32 NumImplementedInterfaces = Params.NumImplementedInterfaces)
	{
		NewClass->Interfaces.Reserve(NumImplementedInterfaces);
		for (const FImplementedInterfaceParams* ImplementedInterface = Params.ImplementedInterfaceArray, *ImplementedInterfaceEnd = ImplementedInterface + NumImplementedInterfaces; ImplementedInterface != ImplementedInterfaceEnd; ++ImplementedInterface)
		{
			UClass* (*ClassFunc)() = ImplementedInterface->ClassFunc;
			UClass* InterfaceClass = ClassFunc ? ClassFunc() : nullptr;

			NewClass->Interfaces.Emplace(InterfaceClass, ImplementedInterface->Offset, ImplementedInterface->bImplementedByK2);
		}
	}

#if WITH_METADATA	//设置UClass对象的元数据
	AddMetaData(NewClass, Params.MetaDataArray, Params.NumMetaData);
#endif
	//创建属性链接和获取它们的结构,在运行时使用
	NewClass->StaticLink();

	NewClass->SetSparseClassDataStruct(NewClass->GetSparseClassDataArchetypeStruct());
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章