反射

UClass注册时机

Posted by Bob on April 15, 2025

在Unreal中创建一个继承UObject的类时,默认会导入一个头文件BaseRole.generated.h,它在LearnCode\Intermediate\Build\Win64\UnrealEditor\Inc\LearnCode\UHT目录下由UHT生成BaseRole.generated.h,该目录下还有BaseRole.gen.cpp,


// BaseRole.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BaseRole.generated.h"

UCLASS() //LINE 9
class LEARNCODE_API ABaseRole : public AActor
{
	GENERATED_BODY() //LINE 12
	
public:	
	// Sets default values for this actor's properties
	ABaseRole();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

};


// BaseRole.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "BaseRole.h"

// Sets default values
ABaseRole::ABaseRole()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ABaseRole::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ABaseRole::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}



调试UnrealBuildTool启动参数 -Target=”LearnCode Win64 Development” -Project=”D:\TrainWorkSpace\LearnCode\LearnCode.uproject” -WaitMutex -FromMsBuild

生成generated.h流程

//Engine\Source\Programs\UnrealBuildTool
UnrealBuildTool.cs Main(string[] ArgumentsArray)
UnrealHeaderToolMode.cs  ExecuteAsync(CommandLineArguments Arguments, ILogger Logger)
//Engine\Source\Programs\Shared\EpicGames.UHT
UhtSession.cs Run(string manifestFilePath)
UhtCodeGenerator.cs CodeGenerator(IUhtExportFactory factory)

UClass()宏

// ObjectMacros.h
#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 UCLASS(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_PROLOG)

GENERATED_BODY()宏

// ObjectMacros.h
#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);

#define GENERATED_USTRUCT_BODY(...) GENERATED_BODY()
#define GENERATED_UCLASS_BODY(...) GENERATED_BODY_LEGACY()
#define GENERATED_UINTERFACE_BODY(...) GENERATED_BODY_LEGACY()
#define GENERATED_IINTERFACE_BODY(...) GENERATED_BODY_LEGACY()

BaseRole.generated.h

// Copyright Epic Games, Inc. All Rights Reserved.
/*===========================================================================
	Generated code exported from UnrealHeaderTool.
	DO NOT modify this manually! Edit the corresponding .h files instead!
===========================================================================*/

// IWYU pragma: private, include "BaseRole.h"
#include "UObject/ObjectMacros.h"
#include "UObject/ScriptMacros.h"

PRAGMA_DISABLE_DEPRECATION_WARNINGS
#ifdef LEARNCODE_BaseRole_generated_h
#error "BaseRole.generated.h already included, missing '#pragma once' in BaseRole.h"
#endif
#define LEARNCODE_BaseRole_generated_h

#define FID_LearnCode_Source_LearnCode_BaseRole_h_12_INCLASS_NO_PURE_DECLS \
private: \
	static void StaticRegisterNativesABaseRole(); \
	friend struct Z_Construct_UClass_ABaseRole_Statics; \
public: \
	DECLARE_CLASS(ABaseRole, AActor, COMPILED_IN_FLAGS(0 | CLASS_Config), CASTCLASS_None, TEXT("/Script/LearnCode"), NO_API) \
	DECLARE_SERIALIZER(ABaseRole)


#define FID_LearnCode_Source_LearnCode_BaseRole_h_12_ENHANCED_CONSTRUCTORS \
private: \
	/** Private move- and copy-constructors, should never be used */ \
	ABaseRole(ABaseRole&&); \
	ABaseRole(const ABaseRole&); \
public: \
	DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, ABaseRole); \
	DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(ABaseRole); \
	DEFINE_DEFAULT_CONSTRUCTOR_CALL(ABaseRole) \
	NO_API virtual ~ABaseRole();


#define FID_LearnCode_Source_LearnCode_BaseRole_h_9_PROLOG
#define FID_LearnCode_Source_LearnCode_BaseRole_h_12_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
	FID_LearnCode_Source_LearnCode_BaseRole_h_12_INCLASS_NO_PURE_DECLS \
	FID_LearnCode_Source_LearnCode_BaseRole_h_12_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS


template<> LEARNCODE_API UClass* StaticClass<class ABaseRole>();

#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID FID_LearnCode_Source_LearnCode_BaseRole_h

UClass展开后是FID_LearnCode_Source_LearnCode_BaseRole_h_9_PROLOG,GENERATED_BODY展开后是FID_LearnCode_Source_LearnCode_BaseRole_h_12_GENERATED_BODY,其展开FID_LearnCode_Source_LearnCode_BaseRole_h_12_INCLASS_NO_PURE_DECLS和FID_LearnCode_Source_LearnCode_BaseRole_h_12_ENHANCED_CONSTRUCTORS。

static void StaticRegisterNativesABaseRole()是空函数。

Z_Construct_UClass_ABaseRole_Statics结构体下面介绍。

DECLARE_CLASS(ABaseRole, AActor, COMPILED_IN_FLAGS(0 | CLASS_Config), CASTCLASS_None, TEXT("/Script/LearnCode"), NO_API)

DECLARE_CLASS()宏

// ObjectMacros.h
#define DECLARE_CLASS( TClass, TSuperClass, TStaticFlags, TStaticCastFlags, TPackage, TRequiredAPI  ) \
private: \
    TClass& operator=(TClass&&);   \
    TClass& operator=(const TClass&);   \
	TRequiredAPI static UClass* GetPrivateStaticClass(); \
public: \
	/** Bitwise union of #EClassFlags pertaining to this class.*/ \
	static constexpr EClassFlags StaticClassFlags=EClassFlags(TStaticFlags); \
	/** Typedef for the base class () */ \
	typedef TSuperClass Super;\
	/** Typedef for . */ \
	typedef TClass ThisClass;\
	/** Returns a UClass object representing this class at runtime */ \
	inline static UClass* StaticClass() \
	{ \
		return GetPrivateStaticClass(); \
	} \
	/** Returns the package this class belongs in */ \
	inline static const TCHAR* StaticPackage() \
	{ \
		return TPackage; \
	} \
	/** Returns the static cast flags for this class */ \
	inline static EClassCastFlags StaticClassCastFlags() \
	{ \
		return TStaticCastFlags; \
	} \
	/** For internal use only; use StaticConstructObject() to create new objects. */ \
	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); \
	} \
	/** For internal use only; use StaticConstructObject() to create new objects. */ \
	inline void* operator new( const size_t InSize, EInternal* InMem ) \
	{ \
		return (void*)InMem; \
	} \
	/* Eliminate V1062 warning from PVS-Studio while keeping MSVC and Clang happy. */ \
	inline void operator delete(void* InMem) \
	{ \
		::operator delete(InMem); \
	}


// Implement the GetPrivateStaticClass and the registration info but do not auto register the class.  
// This is primarily used by UnrealHeaderTool
#define IMPLEMENT_CLASS_NO_AUTO_REGISTRATION(TClass) \
	FClassRegistrationInfo Z_Registration_Info_UClass_##TClass; \
	UClass* TClass::GetPrivateStaticClass() \
	{ \
		if (!Z_Registration_Info_UClass_##TClass.InnerSingleton) \
		{ \
			/* this could be handled with templates, but we want it external to avoid code bloat */ \
			GetPrivateStaticClassBody( \
				StaticPackage(), \
				(TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), \
				Z_Registration_Info_UClass_##TClass.InnerSingleton, \
				StaticRegisterNatives##TClass, \
				sizeof(TClass), \
				alignof(TClass), \
				TClass::StaticClassFlags, \
				TClass::StaticClassCastFlags(), \
				TClass::StaticConfigName(), \
				(UClass::ClassConstructorType)InternalConstructor<TClass>, \
				(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<TClass>, \
				UOBJECT_CPPCLASS_STATICFUNCTIONS_FORCLASS(TClass), \
				&TClass::Super::StaticClass, \
				&TClass::WithinClass::StaticClass \
			); \
		} \
		return Z_Registration_Info_UClass_##TClass.InnerSingleton; \
	}

StaticClass()里调用GetPrivateStaticClass,最终在GetPrivateStaticClassBody里构造UClass,大约3700个左右

//Engine\Source\Runtime\CoreUObject\Private\UObject\Class.cpp
void GetPrivateStaticClassBody(
	const TCHAR* PackageName,
	const TCHAR* Name,
	UClass*& ReturnClass,
	void(*RegisterNativeFunc)(),
	uint32 InSize,
	uint32 InAlignment,
	EClassFlags InClassFlags,
	EClassCastFlags InClassCastFlags,
	const TCHAR* InConfigName,
	UClass::ClassConstructorType InClassConstructor,
	UClass::ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,
	FUObjectCppClassStaticFunctions&& InCppClassStaticFunctions,
	UClass::StaticClassFunctionType InSuperClassFn,
	UClass::StaticClassFunctionType InWithinClassFn
	)
{
#if WITH_RELOAD
	if (IsReloadActive() && GetActiveReloadType() != EActiveReloadType::Reinstancing)
	{
		UPackage* Package = FindPackage(NULL, PackageName);
		if (Package)
		{
			ReturnClass = FindObject<UClass>((UObject *)Package, Name);
			if (ReturnClass)
			{
				if (ReturnClass->HotReloadPrivateStaticClass(
					InSize,
					InClassFlags,
					InClassCastFlags,
					InConfigName,
					InClassConstructor,
					InClassVTableHelperCtorCaller,
					FUObjectCppClassStaticFunctions(InCppClassStaticFunctions),
					InSuperClassFn(),
					InWithinClassFn()
					))
				{
					// Register the class's native functions.
					RegisterNativeFunc();
				}
				return;
			}
			else
			{
				UE_LOG(LogClass, Log, TEXT("Could not find existing class %s in package %s for reload, assuming new or modified class"), Name, PackageName);
			}
		}
		else
		{
			UE_LOG(LogClass, Log, TEXT("Could not find existing package %s for reload of class %s, assuming a new package."), PackageName, Name);
		}
	}
#endif

	ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UClass), alignof(UClass), true);
	ReturnClass = ::new (ReturnClass)
		UClass
		(
		EC_StaticConstructor,
		Name,
		InSize,
		InAlignment,
		InClassFlags,
		InClassCastFlags,
		InConfigName,
		EObjectFlags(RF_Public | RF_Standalone | RF_Transient | RF_MarkAsNative | RF_MarkAsRootSet),
		InClassConstructor,
		InClassVTableHelperCtorCaller,
		MoveTemp(InCppClassStaticFunctions)
		);
	check(ReturnClass);
	
	InitializePrivateStaticClass(
		InSuperClassFn(),
		ReturnClass,
		InWithinClassFn(),
		PackageName,
		Name
		);

	// Register the class's native functions.
	RegisterNativeFunc();
}

DECLARE_SERIALIZER宏 ,系列化对象 DECLARE_SERIALIZER(ABaseRole)

// ObjectMacros.h
#define DECLARE_SERIALIZER( TClass ) \
	friend FArchive &operator<<( FArchive& Ar, TClass*& Res ) \
	{ \
		return Ar << (UObject*&)Res; \
	} \
	friend void operator<<(FStructuredArchive::FSlot InSlot, TClass*& Res) \
	{ \
		InSlot << (UObject*&)Res; \
	}

移动构造函数ABaseRole(ABaseRole&&)和拷贝函数ABaseRole(const ABaseRole&)被禁用。

如果是GENERATED_BODY_LEGACY 需要自己实现这个构造函数 NO_API UTestBTTask_Log(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \

接着是二个和 hot-reload相关的宏

DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, ABaseRole);

// ObjectMacros.h
#define DECLARE_VTABLE_PTR_HELPER_CTOR(API, TClass) \
	/** DO NOT USE. This constructor is for internal usage only for hot-reload purposes. */ \
	API TClass(FVTableHelper& Helper);

DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(ABaseRole);

// ObjectMacros.h
#define DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER_DUMMY() \
	static UObject* __VTableCtorCaller(FVTableHelper& Helper) \
	{ \
		return nullptr; \
	}

#if WITH_RELOAD && !CHECK_PUREVIRTUALS
	#define DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(TClass) \
		static UObject* __VTableCtorCaller(FVTableHelper& Helper) \
		{ \
			return new (EC_InternalUseOnlyConstructor, (UObject*)GetTransientPackage(), NAME_None, RF_NeedLoad | RF_ClassDefaultObject | RF_TagGarbageTemp) TClass(Helper); \
		}
#else // WITH_RELOAD && !CHECK_PUREVIRTUALS
	#define DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(TClass) \
		DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER_DUMMY()
#endif // WITH_RELOAD && !CHECK_PUREVIRTUALS

构造函数 DEFINE_DEFAULT_CONSTRUCTOR_CALL(ABaseRole)

// ObjectMacros.h
#define DEFINE_DEFAULT_CONSTRUCTOR_CALL(TClass) \
	static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())TClass; }

//Class.h
/**
 * Helper template to call the default constructor for a class
 */
template<class T>
void InternalConstructor( const FObjectInitializer& X )
{ 
	T::__DefaultConstructor(X);
}

析构函数 NO_API virtual ~ABaseRole();

接下来是具体实现

BaseRole.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 "LearnCode/BaseRole.h"
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCodeBaseRole() {}

// Begin Cross Module References
ENGINE_API UClass* Z_Construct_UClass_AActor();
LEARNCODE_API UClass* Z_Construct_UClass_ABaseRole();
LEARNCODE_API UClass* Z_Construct_UClass_ABaseRole_NoRegister();
UPackage* Z_Construct_UPackage__Script_LearnCode();
// End Cross Module References

// Begin Class ABaseRole
void ABaseRole::StaticRegisterNativesABaseRole()
{
}
IMPLEMENT_CLASS_NO_AUTO_REGISTRATION(ABaseRole);
UClass* Z_Construct_UClass_ABaseRole_NoRegister()
{
	return ABaseRole::StaticClass();
}
struct Z_Construct_UClass_ABaseRole_Statics
{
#if WITH_METADATA
	static constexpr UECodeGen_Private::FMetaDataPairParam Class_MetaDataParams[] = {
		{ "IncludePath", "BaseRole.h" },
		{ "ModuleRelativePath", "BaseRole.h" },
	};
#endif // WITH_METADATA
	static UObject* (*const DependentSingletons[])();
	static constexpr FCppClassTypeInfoStatic StaticCppClassTypeInfo = {
		TCppClassTypeTraits<ABaseRole>::IsAbstract,
	};
	static const UECodeGen_Private::FClassParams ClassParams;
};
UObject* (*const Z_Construct_UClass_ABaseRole_Statics::DependentSingletons[])() = {
	(UObject* (*)())Z_Construct_UClass_AActor,
	(UObject* (*)())Z_Construct_UPackage__Script_LearnCode,
};
static_assert(UE_ARRAY_COUNT(Z_Construct_UClass_ABaseRole_Statics::DependentSingletons) < 16);
const UECodeGen_Private::FClassParams Z_Construct_UClass_ABaseRole_Statics::ClassParams = {
	&ABaseRole::StaticClass,
	"Engine",
	&StaticCppClassTypeInfo,
	DependentSingletons,
	nullptr,
	nullptr,
	nullptr,
	UE_ARRAY_COUNT(DependentSingletons),
	0,
	0,
	0,
	0x009000A4u,
	METADATA_PARAMS(UE_ARRAY_COUNT(Z_Construct_UClass_ABaseRole_Statics::Class_MetaDataParams), Z_Construct_UClass_ABaseRole_Statics::Class_MetaDataParams)
};
UClass* Z_Construct_UClass_ABaseRole()
{
	if (!Z_Registration_Info_UClass_ABaseRole.OuterSingleton)
	{
		UECodeGen_Private::ConstructUClass(Z_Registration_Info_UClass_ABaseRole.OuterSingleton, Z_Construct_UClass_ABaseRole_Statics::ClassParams);
	}
	return Z_Registration_Info_UClass_ABaseRole.OuterSingleton;
}
template<> LEARNCODE_API UClass* StaticClass<ABaseRole>()
{
	return ABaseRole::StaticClass();
}
DEFINE_VTABLE_PTR_HELPER_CTOR(ABaseRole);
ABaseRole::~ABaseRole() {}
// End Class ABaseRole

// Begin Registration
struct Z_CompiledInDeferFile_FID_LearnCode_Source_LearnCode_BaseRole_h_Statics
{
	static constexpr FClassRegisterCompiledInInfo ClassInfo[] = {
		{ Z_Construct_UClass_ABaseRole, ABaseRole::StaticClass, TEXT("ABaseRole"), &Z_Registration_Info_UClass_ABaseRole, CONSTRUCT_RELOAD_VERSION_INFO(FClassReloadVersionInfo, sizeof(ABaseRole), 4034982424U) },
	};
};
static FRegisterCompiledInInfo Z_CompiledInDeferFile_FID_LearnCode_Source_LearnCode_BaseRole_h_2509242738(TEXT("/Script/LearnCode"),
	Z_CompiledInDeferFile_FID_LearnCode_Source_LearnCode_BaseRole_h_Statics::ClassInfo, UE_ARRAY_COUNT(Z_CompiledInDeferFile_FID_LearnCode_Source_LearnCode_BaseRole_h_Statics::ClassInfo),
	nullptr, 0,
	nullptr, 0);
// End Registration
PRAGMA_ENABLE_DEPRECATION_WARNINGS

DependentSingletons 该对象处理时需要先处理的依赖

InOuterRegister :Z_Construct_UClass_ABaseRole 函数指针 UECodeGen_Private::ConstructUClass 通过Z_Construct_UClass_ABaseRole_Statics::ClassParams主要是为Uclass初始一些属性

InInnerRegister: ABaseRole::StaticClass 函数指针 实际调用GetPrivateStaticClass 通过GetPrivateStaticClassBody 创建UClass

ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UClass), alignof(UClass), true);
ReturnClass = ::new (ReturnClass)
	UClass
	(xx,xx)

placement new语法:所谓placement new就是在用户指定的内存位置上构建新的对象,这个构建过程不需要额外分配内存,只需要调用对象的构造函数即可

::new (placement_address) Type(arguments);

static FRegisterCompiledInInfo 记录注册UClass的信息,数据最终存在Registrations中,它是在Main函数之前完成的。


//UObjectBase.cpp

/**
 * Helper class to perform registration of object information.  It blindly forwards a call to RegisterCompiledInInfo
 */
struct FRegisterCompiledInInfo
{
	template <typename ... Args>
	FRegisterCompiledInInfo(Args&& ... args)
	{
		RegisterCompiledInInfo(std::forward<Args>(args)...);
	}
};


void RegisterCompiledInInfo(const TCHAR* PackageName, const FClassRegisterCompiledInInfo* ClassInfo, size_t NumClassInfo, const FStructRegisterCompiledInInfo* StructInfo, size_t NumStructInfo, const FEnumRegisterCompiledInInfo* EnumInfo, size_t NumEnumInfo)
{
	LLM_SCOPE(ELLMTag::UObject);

	for (size_t Index = 0; Index < NumClassInfo; ++Index)
	{
		const FClassRegisterCompiledInInfo& Info = ClassInfo[Index];
		RegisterCompiledInInfo(Info.OuterRegister, Info.InnerRegister, PackageName, Info.Name, *Info.Info, Info.VersionInfo);
	}

	for (size_t Index = 0; Index < NumStructInfo; ++Index)
	{
		const FStructRegisterCompiledInInfo& Info = StructInfo[Index];
		RegisterCompiledInInfo(Info.OuterRegister, PackageName, Info.Name, *Info.Info, Info.VersionInfo);
		if (Info.CreateCppStructOps != nullptr)
		{
			UScriptStruct::DeferCppStructOps(FTopLevelAssetPath(FName(PackageName), FName(Info.Name)), (UScriptStruct::ICppStructOps*)Info.CreateCppStructOps());
		}
	}

	for (size_t Index = 0; Index < NumEnumInfo; ++Index)
	{
		const FEnumRegisterCompiledInInfo& Info = EnumInfo[Index];
		RegisterCompiledInInfo(Info.OuterRegister, PackageName, Info.Name, *Info.Info, Info.VersionInfo);
	}
}

void RegisterCompiledInInfo(class UClass* (*InOuterRegister)(), class UClass* (*InInnerRegister)(), const TCHAR* InPackageName, const TCHAR* InName, FClassRegistrationInfo& InInfo, const FClassReloadVersionInfo& InVersionInfo)
{
	check(InOuterRegister);
	check(InInnerRegister);
	FClassDeferredRegistry::AddResult result = FClassDeferredRegistry::Get().AddRegistration(InOuterRegister, InInnerRegister, InPackageName, InName, InInfo, InVersionInfo);
#if WITH_RELOAD
	if (result == FClassDeferredRegistry::AddResult::ExistingChanged && !IsReloadActive())
	{
		// Class exists, this can only happen during hot-reload or live coding
		UE_LOG(LogUObjectBase, Fatal, TEXT("Trying to recreate changed class '%s' outside of hot reload and live coding!"), InName);
	}
#endif
	FString NoPrefix(UObjectBase::RemoveClassPrefix(InName));
	NotifyRegistrationEvent(InPackageName, *NoPrefix, ENotifyRegistrationType::NRT_Class, ENotifyRegistrationPhase::NRP_Added, (UObject * (*)())(InOuterRegister), false);
	NotifyRegistrationEvent(InPackageName, *(FString(DEFAULT_OBJECT_PREFIX) + NoPrefix), ENotifyRegistrationType::NRT_ClassCDO, ENotifyRegistrationPhase::NRP_Added, (UObject * (*)())(InOuterRegister), false);
}

//DeferredRegistry.h
	AddResult AddRegistration(TType* (*InOuterRegister)(), TType* (*InInnerRegister)(), const TCHAR* InPackageName, const TCHAR* InName, TInfo& InInfo, const TVersion& InVersion)
	{
#if WITH_RELOAD
		const FPackageAndNameKey Key = FPackageAndNameKey{ InPackageName, InName };
		TInfo** ExistingInfo = InfoMap.Find(Key);

		bool bHasChanged = !ExistingInfo || (*ExistingInfo)->ReloadVersionInfo != InVersion;
		InInfo.ReloadVersionInfo = InVersion;
		TType* OldSingleton = ExistingInfo ? ((*ExistingInfo)->InnerSingleton ? (*ExistingInfo)->InnerSingleton : (*ExistingInfo)->OuterSingleton) : nullptr;

		bool bAdd = true;
		if (ExistingInfo)
		{
			if (IReload* Reload = GetActiveReloadInterface())
			{
				bAdd = Reload->GetEnableReinstancing(bHasChanged);
			}
			if (bAdd)
			{
				if (!bHasChanged)
				{
					// With live coding, the existing might be the same as the new info.  
					// We still invoke the copy method to allow UClasses to clear the singletons.
					UpdateSingletons(InInfo, **ExistingInfo);
				}
				*ExistingInfo = &InInfo;
			}
		}
		else
		{
			InfoMap.Add(Key, &InInfo);
		}
		if (bAdd)
		{
			Registrations.Add(FRegistrant{ InOuterRegister, InInnerRegister, InPackageName, &InInfo, OldSingleton, bHasChanged });
		}
		return ExistingInfo == nullptr ? AddResult::New : (bHasChanged ? AddResult::ExistingChanged : AddResult::ExistingNoChange);
#else
		Registrations.Add(FRegistrant{ InOuterRegister, InInnerRegister, InPackageName, &InInfo });
		return AddResult::New;
#endif
	}

加载CoreUObject时候处理之前注册的所有UClass,


//LaunchEngineLoop.cpp
bool FEngineLoop::LoadCoreModules()
{
	// Always attempt to load CoreUObject. It requires additional pre-init which is called from its module's StartupModule method.
#if WITH_COREUOBJECT
	// Always register the UObjects callback for VNI and general consistency with the callbacks ProcessNewlyLoadedUObjects calls.
	RegisterProcessNewlyLoadedUObjects();
	return FModuleManager::Get().LoadModule(TEXT("CoreUObject")) != nullptr;
#else
	return true;
#endif
}


//CoreNative.cpp
class FCoreUObjectModule : public FDefaultModuleImpl
{
    	virtual void StartupModule() override
	{
		// Register all classes that have been loaded so far. This is required for CVars to work.		
		UClassRegisterAllCompiledInClasses();

		void InitUObject();
		FCoreDelegates::OnInit.AddStatic(InitUObject);
    }
}

//UObjectBase.cpp
/** Register all loaded classes */
void UClassRegisterAllCompiledInClasses()
{
#if WITH_RELOAD
	TArray<UClass*> AddedClasses;
#endif
	SCOPED_BOOT_TIMING("UClassRegisterAllCompiledInClasses");
	LLM_SCOPE(ELLMTag::UObject);

	FClassDeferredRegistry& Registry = FClassDeferredRegistry::Get();

	Registry.ProcessChangedObjects();

	for (const FClassDeferredRegistry::FRegistrant& Registrant : Registry.GetRegistrations())
	{
		UClass* RegisteredClass = FClassDeferredRegistry::InnerRegister(Registrant);
#if WITH_RELOAD
		if (IsReloadActive() && Registrant.OldSingleton == nullptr)
		{
			AddedClasses.Add(RegisteredClass);
		}
#endif
	}

#if WITH_RELOAD
	if (AddedClasses.Num() > 0)
	{
		FCoreUObjectDelegates::ReloadAddedClassesDelegate.Broadcast(AddedClasses);
		PRAGMA_DISABLE_DEPRECATION_WARNINGS
		FCoreUObjectDelegates::RegisterHotReloadAddedClassesDelegate.Broadcast(AddedClasses);
		PRAGMA_ENABLE_DEPRECATION_WARNINGS
	}
#endif
}

ProcessNewlyLoadedUObjects处理加载module后用到的Uclass


//UObjectBase.cpp
void RegisterProcessNewlyLoadedUObjects()
{
	static bool bHasRegistered = false;
	if (!bHasRegistered)
	{
		bHasRegistered = true;
		FModuleManager::Get().OnProcessLoadedObjectsCallback().AddStatic(ProcessNewlyLoadedUObjects);
	}
}

void ProcessNewlyLoadedUObjects(FName Package, bool bCanProcessNewlyLoadedObjects)
{
	SCOPED_BOOT_TIMING("ProcessNewlyLoadedUObjects");
#if USE_PER_MODULE_UOBJECT_BOOTSTRAP
	if (Package != NAME_None)
	{
		UObjectReleaseModuleRegistrants(Package);
	}
#endif
	if (!bCanProcessNewlyLoadedObjects)
	{
		FCoreUObjectDelegates::CompiledInUObjectsRegisteredDelegate.Broadcast(Package, ECompiledInUObjectsRegisteredStatus::Delayed);
		return;
	}
	LLM_SCOPE(ELLMTag::UObject);
	DECLARE_SCOPE_CYCLE_COUNTER(TEXT("ProcessNewlyLoadedUObjects"), STAT_ProcessNewlyLoadedUObjects, STATGROUP_ObjectVerbose);

	FPackageDeferredRegistry& PackageRegistry = FPackageDeferredRegistry::Get();
	FClassDeferredRegistry& ClassRegistry = FClassDeferredRegistry::Get();
	FStructDeferredRegistry& StructRegistry = FStructDeferredRegistry::Get();
	FEnumDeferredRegistry& EnumRegistry = FEnumDeferredRegistry::Get();

	PackageRegistry.ProcessChangedObjects(true);
	StructRegistry.ProcessChangedObjects();
	EnumRegistry.ProcessChangedObjects();

	UClassRegisterAllCompiledInClasses();

	bool bNewUObjects = false;
	TArray<UClass*> AllNewClasses;
	while (GFirstPendingRegistrant ||
		ClassRegistry.HasPendingRegistrations() ||
		StructRegistry.HasPendingRegistrations() ||
		EnumRegistry.HasPendingRegistrations())
	{
		bNewUObjects = true;
		UObjectProcessRegistrants();
		UObjectLoadAllCompiledInStructs();

		FCoreUObjectDelegates::CompiledInUObjectsRegisteredDelegate.Broadcast(Package, ECompiledInUObjectsRegisteredStatus::PreCDO);

		UObjectLoadAllCompiledInDefaultProperties(AllNewClasses);
	}

	FCoreUObjectDelegates::CompiledInUObjectsRegisteredDelegate.Broadcast(Package, ECompiledInUObjectsRegisteredStatus::PostCDO);

#if WITH_RELOAD
	IReload* Reload = GetActiveReloadInterface();
	if (Reload != nullptr)
	{
		UClassReplaceReloadClasses(); // Legacy
		PackageRegistry.NotifyReload(*Reload);
		EnumRegistry.NotifyReload(*Reload);
		StructRegistry.NotifyReload(*Reload);
		ClassRegistry.NotifyReload(*Reload);
		Reload->Reinstance();
	}
#endif

	PackageRegistry.EmptyRegistrations();
	EnumRegistry.EmptyRegistrations();
	StructRegistry.EmptyRegistrations();
	ClassRegistry.EmptyRegistrations();

	if (TMap<UObjectBase*, FPendingRegistrantInfo>& PendingRegistrants = FPendingRegistrantInfo::GetMap(); PendingRegistrants.IsEmpty())
	{
		PendingRegistrants.Empty();
	}

	if (bNewUObjects && !GIsInitialLoad)
	{
		for (UClass* Class : AllNewClasses)
		{
			// Assemble reference token stream for garbage collection/ RTGC.
			if (!Class->HasAnyFlags(RF_ClassDefaultObject) && !Class->HasAnyClassFlags(CLASS_TokenStreamAssembled))
			{
				Class->AssembleReferenceTokenStream();
			}
		}
	}
}

将注册的Class信息转化为真正的对象


/**
 * Convert a boot-strap registered class into a real one, add to uobject array, etc
 *
 * @param UClassStaticClass Now that it is known, fill in UClass::StaticClass() as the class
 */
void UObjectBase::DeferredRegister(UClass *UClassStaticClass,const TCHAR* PackageName,const TCHAR* InName)
{
	check(UObjectInitialized());
	// Set object properties.
	UPackage* Package = CreatePackage(PackageName);
	check(Package);
	Package->SetPackageFlags(PKG_CompiledIn);
	OuterPrivate = Package;

	check(UClassStaticClass);
	check(!ClassPrivate);
	ClassPrivate = UClassStaticClass;

	// Add to the global object table.
	AddObject(FName(InName), EInternalObjectFlags::None);
	// At this point all compiled-in objects should have already been fully constructed so it's safe to remove the NotFullyConstructed flag
	// which was set in FUObjectArray::AllocateUObjectIndex (called from AddObject)
	GUObjectArray.IndexToObject(InternalIndex)->ClearFlags(EInternalObjectFlags::PendingConstruction);

	// Make sure that objects disregarded for GC are part of root set.
	check(!GUObjectArray.IsDisregardForGC(this) || GUObjectArray.IndexToObject(InternalIndex)->IsRootSet());

	UE_LOG(LogUObjectBootstrap, Verbose, TEXT("UObjectBase::DeferredRegister %s %s"), PackageName, InName);
}

EXPAND_MACRO 宏展开工具


#ifndef _CRT_STRINGIZE
#define _CRT_STRINGIZE_(x) #x
#define _CRT_STRINGIZE(x) _CRT_STRINGIZE_(x)
#endif

//Expands to macro:
#define EXPAND_MACRO(x) __pragma(message(__FILE__ _CRT_STRINGIZE((__LINE__): \nmacro\t)#x" expands to:\n" _CRT_STRINGIZE(x)))


EXPAND_MACRO(FID_LearnCode_Source_LearnCode_BaseRole_h_9_PROLOG);
EXPAND_MACRO(FID_LearnCode_Source_LearnCode_BaseRole_h_12_GENERATED_BODY);

读取反射信息


UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "BaseRole")
int Level;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "BaseRole")
int Health;
UFUNCTION(BlueprintCallable, Category = "BaseRole")
void OnHit(int NewLevel);
void ABaseRole::OnHit(int NewLevel)
{
	UE_LOG(LogTemp, Warning, TEXT("OnHit %d") , NewLevel);
}


// Called when the game starts or when spawned
void ABaseRole::BeginPlay()
{
	Super::BeginPlay();

	TArray<UObject*> Objects;
	GetObjectsOfClass(UClass::StaticClass(), Objects);

	UClass* Class = FindObject<UClass>(ANY_PACKAGE, TEXT("BaseRole"));
	if (Class)
	{
		UE_LOG(LogTemp, Warning, TEXT("Class found: %s"), *Class->GetName());

		for (const FProperty* Property = Class->PropertyLink; Property; Property = Property->PropertyLinkNext)
		{
			FName propertyName = Property->GetFName();
			UE_LOG(LogTemp, Warning, TEXT("Property found: %s"), *propertyName.ToString());
		}

	
		const FProperty* LevelPro = Class->FindPropertyByName(TEXT("Level"));
		int* ProValue = LevelPro->ContainerPtrToValuePtr<int>(this);
		*ProValue = 1;

		UFunction* Func = Class->FindFunctionByName(TEXT("OnHit"));
		this->ProcessEvent(Func,ProValue);
		

		for (TFieldIterator<UFunction> Fit(Class, EFieldIteratorFlags::IncludeSuper); Fit; ++Fit)
		{
			const UFunction* Function = *Fit;
			UE_LOG(LogTemp, Log, TEXT( "Function Found: %s();" ), *Function->GetName());
			for (TFieldIterator<FProperty> It(Function); It; ++It)
			{
				const FProperty* Property = *It;
				UE_LOG(LogTemp, Log, TEXT( "	Property Found: %s;" ), *Property->GetName());
				UE_LOG(LogTemp, Log, TEXT( "	Property Type: %s;" ), *Property->GetCPPType());
				if (Property->GetPropertyFlags() & CPF_ReturnParm)
				{
					UE_LOG(LogTemp, Log, TEXT( "	Property is Return Parm;" ));
				}
			}
		}


		TArray<UClass*> DerivedClasses;
		GetDerivedClasses(Class, DerivedClasses);

        UClass* SuperClass = Class->GetSuperClass();
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("Class not found"));
	}
}