UE5 反射源码分析

UE5反射

分析基于ue5.44版本

.gen.cpp分析均基于这个文件:

#pragma once

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

USTRUCT()
struct FMyStruct
{
	GENERATED_BODY()
	int a;
	float b;
};
UCLASS(Blueprintable)
class ACTIONRPG_API AReflectTestActor : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AReflectTestActor();

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

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

	UPROPERTY()
	float Speed;

	UPROPERTY(Replicated)	
	float Health;

	UFUNCTION()
	void AddSpeed(float InSpeed);

	UFUNCTION(Server, Reliable)
	void RPC_Test(float InDamage);

	void GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const override;
};

//-------------------------------------------展开后👇-----------------------------------------------
UCLASS()
class ACTIONRPG_API AReflectTestActor : public AActor
{
//GENERATED_BODY()
#define FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_12_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS 
public: 
//FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_12_RPC_WRAPPERS_NO_PURE_DECLS 
    virtual void RPC_Test_Implementation(float InDamage); 
	static void execRPC_Test( UObject* Context, FFrame& Stack, RESULT_DECL ); 
	static void execAddSpeed( UObject* Context, FFrame& Stack, RESULT_DECL );
//FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_12_CALLBACK_WRAPPERS \
    //空宏
//FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_12_INCLASS_NO_PURE_DECLS \
private: 
	static void StaticRegisterNativesAReflectTestActor(); 
	friend struct Z_Construct_UClass_AReflectTestActor_Statics; 
public: 
	//DECLARE_CLASS(AReflectTestActor, AActor, COMPILED_IN_FLAGS(0 | CLASS_Config), CASTCLASS_None, TEXT("/Script/ActionRPG"), NO_API) \
	//#define DECLARE_CLASS( TClass, TSuperClass, TStaticFlags, TStaticCastFlags, TPackage, TRequiredAPI  )
private: 
    AReflectTestActor& operator=(AReflectTestActor&&);   
    AReflectTestActor& operator=(const AReflectTestActor&);   
	TRequiredAPI static UClass* GetPrivateStaticClass(); 
public: 
	/** Bitwise union of #EClassFlags pertaining to this class.*/ 
	static constexpr EClassFlags StaticClassFlags=EClassFlags(COMPILED_IN_FLAGS(0 | CLASS_Config)); 
	/** Typedef for the base class ({{ typedef-type }}) */ 
	typedef AActor Super;
	/** Typedef for {{ typedef-type }}. */ 
	typedef AReflectTestActor 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 TEXT("/Script/ActionRPG"); 
	} 
	/** Returns the static cast flags for this class */ 
	inline static EClassCastFlags StaticClassCastFlags() 
	{ 
		return CASTCLASS_None; 
	} 
	/** 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); 
	}
	//DECLARE_SERIALIZER(AReflectTestActor) 
    friend FArchive &operator<<( FArchive& Ar, AReflectTestActor*& Res ) 
    { 
        return Ar << (UObject*&)Res; 
    } 
    friend void operator<<(FStructuredArchive::FSlot InSlot, AReflectTestActor*& Res) 
    { 
        InSlot << (UObject*&)Res; 
    }
	enum class ENetFields_Private : uint16 
	{ 
		NETFIELD_REP_START=(uint16)((int32)Super::ENetFields_Private::NETFIELD_REP_END + (int32)1), 
		Health=NETFIELD_REP_START, 
		NETFIELD_REP_END=Health	}; 
	NO_API virtual void ValidateGeneratedRepEnums(const TArray<struct FRepRecord>& ClassReps) const override;
//FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_12_ENHANCED_CONSTRUCTORS \/
private: 
	/** Private move- and copy-constructors, should never be used */ \
	AReflectTestActor(AReflectTestActor&&); 
	AReflectTestActor(const AReflectTestActor&); 
public: 
	//DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, AReflectTestActor); 
    	/** DO NOT USE. This constructor is for internal usage only for hot-reload purposes. */ 
	API AReflectTestActor(FVTableHelper& Helper);
	//DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(AReflectTestActor); 
    static UObject* __VTableCtorCaller(FVTableHelper& Helper) 
    { 
        return new (EC_InternalUseOnlyConstructor, (UObject*)GetTransientPackage(), NAME_None, RF_NeedLoad | RF_ClassDefaultObject | RF_TagGarbageTemp) AReflectTestActor(Helper); \
    }
    //DEFINE_DEFAULT_CONSTRUCTOR_CALL(AReflectTestActor) 
    static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())AReflectTestActor; }
	NO_API virtual ~AReflectTestActor();
private: 
PRAGMA_ENABLE_DEPRECATION_WARNINGS
    
public:
	// Sets default values for this actor's properties
	AReflectTestActor();

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

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

	UPROPERTY()
	float Speed;

    //下面改过一次
    //原来是:
    /*
    UFUNCTION()
	void AddSpeed();
    */
	UPROPERTY(Replicated)//后面增加的,给RPC用的	
	float Health;

	UFUNCTION()
	void AddSpeed(float InSpeed);//分析到ConstructClass中构造函数的时候,发现没参数,后面增加了
    
	UFUNCTION(Server, Reliable)
	void RPC_Test(float InDamage);

	void GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const override;
};


//CPP:

#include "ReflectTestActor.h"
#include"net/UnrealNetwork.h"


// Sets default values
AReflectTestActor::AReflectTestActor()
{
	// 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;
	Speed = 1.0f;
}

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

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

void AReflectTestActor::AddSpeed(float InSpeed)
{
	Speed += InSpeed;
}

void AReflectTestActor::RPC_Test_Implementation(float InDamage)
{
	Health = InDamage;
}

void AReflectTestActor::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(AReflectTestActor, Health);
}

.generated.h中生成的宏展开和分析:

下面的内容ActionRPGCharacter生成的内容

  • GENERATED_BODY()被定义在ObjectMacros.h: Helper macros and defines for UObject system中

    而.generated.h和.gen.cpp则是UHT扫描我们标记的宏生成的另一些宏

  • GENERATED_BODY():一个宏拼接当前文件id、_、行号、_GENERATED_BODY生成一个新的宏,这个宏的定义在.gen.h中,后面内容也均在其内

    #define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY);
    //变成下面的 FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_GENERATED_BODY
    
    #define FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_GENERATED_BODY \
    PRAGMA_DISABLE_DEPRECATION_WARNINGS \
    public: \
        FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_RPC_WRAPPERS_NO_PURE_DECLS \
        FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_CALLBACK_WRAPPERS \
        FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_INCLASS_NO_PURE_DECLS \
        FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_ENHANCED_CONSTRUCTORS \
    private: \
    PRAGMA_ENABLE_DEPRECATION_WARNINGS
    
    • RPC_WRAPPERS_NO_PURE_DECLS

      #define FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_RPC_WRAPPERS_NO_PURE_DECLS \
          virtual void HandleFire_Implementation(); \
          DECLARE_FUNCTION(execHandleFire); \
          DECLARE_FUNCTION(execStopFire); \
          DECLARE_FUNCTION(execStartFire); \
          DECLARE_FUNCTION(execOnRep_CurrentHealth); \
          DECLARE_FUNCTION(execTakeDamage); \
          DECLARE_FUNCTION(execSetCurrentHealth); \
          DECLARE_FUNCTION(execGetCurrentHealth); \
          DECLARE_FUNCTION(execGetMaxHealth);
      
      • DECLARE_FUNCTION:声明exec函数,其实现在.gen.cpp中

        #define DECLARE_FUNCTION(func) static void func( UObject* Context, FFrame& Stack, RESULT_DECL )
        
    • CALLBACK_WRAPPERS:空的宏

    • INCLASS_NO_PURE_DECLS:定义UClass 的主体:

      #define FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_INCLASS_NO_PURE_DECLS \
      private: \
          static void StaticRegisterNativesAActionRPGCharacter(); \
          friend struct Z_Construct_UClass_AActionRPGCharacter_Statics; \
      public: \
          DECLARE_CLASS(AActionRPGCharacter, ACharacter, COMPILED_IN_FLAGS(0 | CLASS_Config), CASTCLASS_None, TEXT("/Script/ActionRPG"), NO_API) \
          DECLARE_SERIALIZER(AActionRPGCharacter) \
          enum class ENetFields_Private : uint16 \
          { \
              NETFIELD_REP_START=(uint16)((int32)Super::ENetFields_Private::NETFIELD_REP_END + (int32)1), \
              CurrentHealth=NETFIELD_REP_START, \
              NETFIELD_REP_END=CurrentHealth    }; \
          NO_API virtual void ValidateGeneratedRepEnums(const TArray<struct FRepRecord>& ClassReps) const override;
      
      • DECLARE_CLASS:这里生成的内容很重要:

        1. 定义了我们常用的Super
        2. 定义我们常用的StaticClass()和声明了其内部的GetPrivateStaticClass(),实现在.gen.cpp中
        3. 用于优化Cast的CastFlag
        4. 重载了的自定义new和delete运算符
        DECLARE_CLASS(AReflectTestActor, AActor, COMPILED_IN_FLAGS(0 | CLASS_Config), CASTCLASS_None, TEXT("/Script/ActionRPG"), NO_API)
        #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-type }}) */ 
            typedef TSuperClass Super;
            /** Typedef for {{ typedef-type }}. */ 
            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); 
            }
        
      • DECLARE_SERIALIZER:重载序列化使用的<<

        #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; \
            }
        
    • ENHANCED_CONSTRUCTORS:构造函数相关,定义了拷贝构造函数和移动构造函数为Private(相当于禁止使用)

      #define FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ActionRPGCharacter_h_21_ENHANCED_CONSTRUCTORS \
      private: 
          /** Private move- and copy-constructors, should never be used */ \
          AActionRPGCharacter(AActionRPGCharacter&&); \
          AActionRPGCharacter(const AActionRPGCharacter&); \
      public: \
          DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, AActionRPGCharacter); \
          DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(AActionRPGCharacter); \
          DEFINE_DEFAULT_CONSTRUCTOR_CALL(AActionRPGCharacter) \
          NO_API virtual ~AActionRPGCharacter();
      
      • DECLARE_VTABLE_PTR_HELPER_CTORDEFINE_VTABLE_PTR_HELPER_CTOR_CALLER是热重载相关

      • DEFINE_DEFAULT_CONSTRUCTOR_CALL是重点,这里定义构造函数:这里使用的是placementnew,语法是new(指针)Class,在一块分配好内存的地方构造Class

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

.gen.cpp分析

第一部分,.generated.h中声明的一些重要函数的实现

  • GetPrivateStaticClass实现:

    TRequiredAPI static UClass* GetPrivateStaticClass(); 在.h中声明,我们平时获取CDO的StaticClass()实际上就是调用这个函数

      inline static UClass* StaticClass() 
      { 
          return GetPrivateStaticClass();
      } 
    

    IMPLEMENT_CLASS_NO_AUTO_REGISTRATION(AReflectTestActor)

    #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; \
        }
    
    void GetPrivateStaticClassBody(
        const TCHAR* PackageName, 
        //实参:StaticPackage(),
        //说明:在.generrated.h中DECLARE_CLASS 定义的StaticPackage()
        const TCHAR* Name, //实参:(TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0)
        //说明:+1去掉前缀比如AActor的A,给准备废弃的类加上
        UClass*& ReturnClass, //这个类的注册信息单例Z_Registration_Info_UClass_##TClass.InnerSingleton
        void(*RegisterNativeFunc)(),//StaticRegisterNatives##TClass,注册函数用
        uint32 InSize,//sizeof(TClass),类的大小
        uint32 InAlignment,// alignof(TClass),结构体对齐的字节数16/8/4/2/1
        EClassFlags InClassFlags,//StaticClassFlags,解释这个类的信息的enum
        EClassCastFlags InClassCastFlags,//StaticClassCastFlags(), 用于在cast的时候计算类之间关系的位向量
        const TCHAR* InConfigName,//配置文件名
        UClass::ClassConstructorType InClassConstructor, //__DefaultConstructor
        UClass::ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,//hotreload的时候使用来构造虚函数表,暂时不管
        FUObjectCppClassStaticFunctions&& InCppClassStaticFunctions,// GC使用的添加额外引用对象的静态函数指针,若没有定义,则会调用到UObject::AddReferencedObjects,默认函数体为空。
        UClass::StaticClassFunctionType InSuperClassFn,//获取基类UClass*的函数指针
        UClass::StaticClassFunctionType InWithinClassFn//获取对象外部类UClass*的函数指针,默认是UObject
        )
    {
    #if WITH_RELOAD
    //忽略热加载
    #endif
    	//使用全局内存分配器获取一块内存,让这个单例指向其地址	
        ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UClass), alignof(UClass), true);
        ReturnClass = ::new (ReturnClass)//使用placement new 来在刚刚分配的内存上调用UClass的构造函数,构造了UClass对象(这里应该还未注册反射信息)
            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);
        
        //初始化Super、Outer的Uclass,里面进行与this的关联、注册Package和自身到一个队列和哈希表中
        InitializePrivateStaticClass(
            InSuperClassFn(),
            ReturnClass,
            InWithinClassFn(),
            PackageName,
            Name
            );
    
        // Register the class's native functions.
        RegisterNativeFunc();//StaticRegisterNatives##TClass,注册函数到Class里的TArray<FNativeFunctionLookup> NativeFunctionLookupTable;
    }
    
    

    withinClass被设置的地方,下面是UFunction的例子,为何设置withinClass后能限制其只能被声明在该Class的解释看下面
    image-20250811152542205

    image-20250811152736521

    UClass::UClass
    (
    	EStaticConstructor,
    	FName			InName,
    	uint32			InSize,
    	uint32			InAlignment,
    	EClassFlags		InClassFlags,
    	EClassCastFlags	InClassCastFlags,
    	const TCHAR*    InConfigName,
    	EObjectFlags	InFlags,
    	ClassConstructorType InClassConstructor,
    	ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,
    	FUObjectCppClassStaticFunctions&& InCppClassStaticFunctions
    )
    :	UStruct					( EC_StaticConstructor, InSize, InAlignment, InFlags )
    ,	ClassConstructor		( InClassConstructor )
    ,	ClassVTableHelperCtorCaller(InClassVTableHelperCtorCaller)
    ,	CppClassStaticFunctions(MoveTemp(InCppClassStaticFunctions))
    ,	ClassUnique				( 0 )
    ,	bCooked					( false )
    ,	bLayoutChanging			( false )
    ,	ClassFlags				( InClassFlags | CLASS_Native )
    ,	ClassCastFlags			( InClassCastFlags )
    ,	ClassWithin				( nullptr )
    #if WITH_EDITORONLY_DATA
    ,	ClassGeneratedBy		( nullptr )
    ,	PropertiesPendingDestruction( nullptr )
    #endif
    ,	ClassConfigName			()
    ,	NetFields				()
    ,	ClassDefaultObject		( nullptr )
    ,	SparseClassData			( nullptr )
    ,	SparseClassDataStruct	( nullptr )
    {
    	// If you add properties here, please update the other constructors and PurgeClass()
    
    	SetCppTypeInfoStatic(&DefaultCppClassTypeInfoStatic);
    
    	// We store the pointer to the ConfigName in an FName temporarily, this cast is intentional
    	// as we expect the mis-typed data to get picked up in UClass::DeferredRegister. PVS-Studio
    	// complains about this operation, but AFAIK it is safe (and we've been doing it a long time)
    	// so the warning has been disabled for now:
    	*(const TCHAR**)&ClassConfigName = InConfigName; //-V580
    }
    

    InClassConstructor调用的就是在.generated.h中生成的ENHANCED_CONSTRUCTORS中的__DefaultConstructor

    /**
     * Helper template to call the default constructor for a class
     */
    template<class T>
    void InternalConstructor( const FObjectInitializer& X )
    { 
        T::__DefaultConstructor(X);
    }
    
    COREUOBJECT_API void InitializePrivateStaticClass(
    	class UClass* TClass_Super_StaticClass,//函数调用之前调用了Super的StaicClass,构造Super先再传参进来
    	class UClass* TClass_PrivateStaticClass,//这里就是前文构造好的StaticClass
    	class UClass* TClass_WithinClass_StaticClass,//也是构造好了Outer的StaticClass先,再传参数
    	const TCHAR* PackageName,
    	const TCHAR* Name
    	)
    {
    	TRACE_LOADTIME_CLASS_INFO(TClass_PrivateStaticClass, Name);
    
    	/* No recursive ::StaticClass calls allowed. Setup extras. */
    	if (TClass_Super_StaticClass != TClass_PrivateStaticClass)
    	{
    		TClass_PrivateStaticClass->SetSuperStruct(TClass_Super_StaticClass);//设定super
    	}
    	else
    	{
    		TClass_PrivateStaticClass->SetSuperStruct(NULL);//如果super和自己一样,就设定为NULL
    	}
    	TClass_PrivateStaticClass->ClassWithin = TClass_WithinClass_StaticClass;//设定OuterClass
    
    	// Register the class's dependencies, then itself.
    	TClass_PrivateStaticClass->RegisterDependencies();//这里留了一个位置给先注册依赖项,但是什么都每干,也没找到哪个UE core 类用到的
    	{
    		// Defer
    		TClass_PrivateStaticClass->Register(PackageName, Name);
    	}
    }
    
    /** Enqueue the registration for this object. */
    void UObjectBase::Register(const TCHAR* PackageName,const TCHAR* InName)
    {
    	LLM_SCOPE(ELLMTag::UObject);
        //获得单例哈希表,UClass 地址做Key,PedningRegistrantInfo做Value(这个结构存储的是PackageName,和UclassNmae)
    	TMap<UObjectBase*, FPendingRegistrantInfo>& PendingRegistrants = FPendingRegistrantInfo::GetMap();
    
    	FPendingRegistrant* PendingRegistration = new FPendingRegistrant(this);
    	PendingRegistrants.Add(this, FPendingRegistrantInfo(InName, PackageName));
    
    #if USE_PER_MODULE_UOBJECT_BOOTSTRAP
    	if (FName(PackageName) != FName("/Script/CoreUObject"))
    	{
    		TMap<FName, TArray<FPendingRegistrant*>>& PerModuleMap = GetPerModuleBootstrapMap();
    
    		PerModuleMap.FindOrAdd(FName(PackageName)).Add(PendingRegistration);
    	}
    	else
    #endif
    	{
    		if (GLastPendingRegistrant)
    		{
    			GLastPendingRegistrant->NextAutoRegister = PendingRegistration;如果链表不为空,加入后面
    		}
    		else
    		{
    			check(!GFirstPendingRegistrant);
    			GFirstPendingRegistrant = PendingRegistration;//如果没链表为空,那我们现在这个就是链表头
    		}
    		GLastPendingRegistrant = PendingRegistration;//我们现在是链表尾部
    	}
    }
    

    RegisterNativeFunc()调用下面的函数:

    void AReflectTestActor::StaticRegisterNativesAReflectTestActor()
    {
    	UClass* Class = AReflectTestActor::StaticClass();
    	static const FNameNativePtrPair Funcs[] = {
    		{ "AddSpeed", &AReflectTestActor::execAddSpeed },
    		{ "RPC_Test", &AReflectTestActor::execRPC_Test },
    	};
    	FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, UE_ARRAY_COUNT(Funcs));
    }
    
    void FNativeFunctionRegistrar::RegisterFunctions(class UClass* Class, const FNameNativePtrPair* InArray, int32 NumFunctions)
    {
        //一个个注册对于名称和地址到这个Class的TArray<FNativeFunctionLookup> NativeFunctionLookupTable;
    	for (; NumFunctions; ++InArray, --NumFunctions)
    	{
    		Class->AddNativeFunction(UTF8_TO_TCHAR(InArray->NameUTF8), InArray->Pointer);
    	}
    }
    void UClass::AddNativeFunction(const WIDECHAR* InName, FNativeFuncPtr InPointer)
    {
    	FName InFName(InName);
    #if WITH_RELOAD
        //掠过热重载
    #endif
    	NativeFunctionLookupTable.Emplace(InFName, InPointer);
    }
    
    void UClass::AddNativeFunction(const WIDECHAR* InName, FNativeFuncPtr InPointer)
    {
    	FName InFName(InName);
    #if WITH_RELOAD
    //热加载忽略
    #endif
    	NativeFunctionLookupTable.Emplace(InFName, InPointer);
    }
    
    Class.h:
    	/** This class's native functions. */
    	TArray<FNativeFunctionLookup> NativeFunctionLookupTable;
    

第二部分,通过静态结构体构造函数收集反射信息(main之前)

注册以文件为单位,一个.h文件生成的ReflectTestActor_h_Statics中包含了里面用UClass、UStruct等标记的类、结构体、枚举、接口(interface)的RegisterCompiledInInfo,RegisterCompiledInInfo里包含了

// Begin Registration
struct Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_Statics
{
	static constexpr FStructRegisterCompiledInInfo ScriptStructInfo[] = {
		{ FMyStruct::StaticStruct, Z_Construct_UScriptStruct_FMyStruct_Statics::NewStructOps, TEXT("MyStruct"), &Z_Registration_Info_UScriptStruct_MyStruct, CONSTRUCT_RELOAD_VERSION_INFO(FStructReloadVersionInfo, sizeof(FMyStruct), 2195146121U) },
	};
	static constexpr FClassRegisterCompiledInInfo ClassInfo[] = {
		{ Z_Construct_UClass_AReflectTestActor, AReflectTestActor::StaticClass, TEXT("AReflectTestActor"), &Z_Registration_Info_UClass_AReflectTestActor, CONSTRUCT_RELOAD_VERSION_INFO(FClassReloadVersionInfo, sizeof(AReflectTestActor), 3803201096U) },
	};
};
static FRegisterCompiledInInfo Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_2038008627(TEXT("/Script/ActionRPG"),
	Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_Statics::ClassInfo, UE_ARRAY_COUNT(Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_Statics::ClassInfo),
	Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_Statics::ScriptStructInfo, UE_ARRAY_COUNT(Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_Statics::ScriptStructInfo),
	nullptr, 0);
// End Registration
PRAGMA_ENABLE_DEPRECATION_WARNINGS

这个就是上面结构体的定义,构造函数是一个可变参数模板,下面的代码块是被调用的重载版本

struct FRegisterCompiledInInfo
{
    template <typename ... Args>
    FRegisterCompiledInInfo(Args&& ... args)
    {
        RegisterCompiledInInfo(std::forward<Args>(args)...);
    }
};

这个函数会遍历文件中的各个F##对应结构##RegisterCompiledInInfo,放入对应的F##对应结构##RegistrationInfo中的TArray<FRegistrant> Registrations中

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);
    }
}

RegisterCompiledInInfo的Class重载版本

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
//略去
#endif
    FString NoPrefix(UObjectBase::RemoveClassPrefix(InName));
    //下面这两个函数好像都会return,等于什么都没干,ref:https://zhuanlan.zhihu.com/p/26725639107
    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);
}


RegisterCompiledInInfo的Struct重载版本

void RegisterCompiledInInfo(class UScriptStruct* (*InOuterRegister)(), const TCHAR* InPackageName, const TCHAR* InName, FStructRegistrationInfo& InInfo, const FStructReloadVersionInfo& InVersionInfo)
{
	check(InOuterRegister);
	FStructDeferredRegistry::Get().AddRegistration(InOuterRegister, nullptr, InPackageName, InName, InInfo, InVersionInfo);
	NotifyRegistrationEvent(InPackageName, InName, ENotifyRegistrationType::NRT_Struct, ENotifyRegistrationPhase::NRP_Added, (UObject * (*)())(InOuterRegister), false);
}

AddRegistration:讲生成的反射信息加入全局表中

AddResult AddRegistration(TType* (*InOuterRegister)(), TType* (*InInnerRegister)(), const TCHAR* InPackageName, const TCHAR* InName, TInfo& InInfo, const TVersion& InVersion)
{
#if WITH_RELOAD
//略去
#else
    Registrations.Add(FRegistrant{ InOuterRegister, InInnerRegister, InPackageName, &InInfo });
    return AddResult::New;
}

FRegistrant的定义:

    /**
    * Maintains information about a pending registration
    */
    struct FRegistrant
    {
        TType* (*OuterRegisterFn)();
        TType* (*InnerRegisterFn)();
        const TCHAR* PackageName;
        TInfo* Info;
#if WITH_RELOAD
        TType* OldSingleton;
#endif

#if WITH_RELOAD
        bool bHasChanged;
#endif
    };

FClassRegisterCompiledInInfo的定义:前面四个会被传入构造FRegistrant

struct FClassRegisterCompiledInInfo
{
    class UClass* (*OuterRegister)();
    class UClass* (*InnerRegister)();
    const TCHAR* Name;
    FClassRegistrationInfo* Info;
    FClassReloadVersionInfo VersionInfo;
};
//TDeferredRegistry是一个单例,里面存储着TArray<FRegistrant> Registrations
using FClassDeferredRegistry = TDeferredRegistry<FClassRegistrationInfo>;
using FEnumDeferredRegistry = TDeferredRegistry<FEnumRegistrationInfo>;
using FStructDeferredRegistry = TDeferredRegistry<FStructRegistrationInfo>;
using FPackageDeferredRegistry = TDeferredRegistry<FPackageRegistrationInfo>;

第三部分,main后的延迟注册 ProcessNewlyLoadedUObjects

ProcessNewlyLoadedUObjects是进行延迟注册的地方,在下面这两个地方被调用进行注册
EngineLoop::PreInit中的PreinitPostStartUpScreen或者
LoadModuleWithFailureReason中会广播委托,其在下面的FEngineLoop::LoadCoreModules()中

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
#if USE_PER_MODULE_UOBJECT_BOOTSTRAP // otherwise do it later
    FModuleManager::Get().OnProcessLoadedObjectsCallback().AddStatic(ProcessNewlyLoadedUObjects);
#endif
    return FModuleManager::Get().LoadModule(TEXT("CoreUObject")) != nullptr;
#else
    return true;
#endif
}

截图

ss

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)
    {
        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();//第一个分析的地方,这里进行了UClass初步的构造

    bool bNewUObjects = false;
    TArray<UClass*> AllNewClasses;
    while (GFirstPendingRegistrant ||
        ClassRegistry.HasPendingRegistrations() ||
        StructRegistry.HasPendingRegistrations() ||
        EnumRegistry.HasPendingRegistrations())
    {
        bNewUObjects = true;
        UObjectProcessRegistrants();//第二个分析的地方,这里进行了UClass的注册(注册到全局map和list里)
        UObjectLoadAllCompiledInStructs();//第三个分析的地方,这里进行了Enum和Ustruct的反射类的构造

        FCoreUObjectDelegates::CompiledInUObjectsRegisteredDelegate.Broadcast(Package);

        UObjectLoadAllCompiledInDefaultProperties(AllNewClasses);//最后一个分析的地方,这里完成了UClass最后的构造(属性的构造连接、函数的构造(其里面也有属性构造连接)和连接)
    }

#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();
            }
        }
    }
}

UClassRegisterAllCompiledInClasses:

这里干的事情就是每个文件里的UClass(),都会在这里调用StaticClass使用反射生成的内容初步构造UClass(是innersingleton):为UClass对象申请内存,通过大钊文章里的细节讲解,这里进行的初步构造应该是防止后面Ustruct嵌套UClass导致的循环调用的问题,UClass不完全的构造也是因为UStruct还没构造,需要等待UStruct和Enum的构造完成。

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);//这里调用innerRegister最终调用StaticClass
#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
}


static TType* InnerRegister(const FRegistrant& Registrant)
{
    return Registrant.InnerRegisterFn();
}

FRegistrant的定义:

/**
    * Maintains information about a pending registration
    */
    struct FRegistrant
    {
      //这里以AReflectTestActor的FClassRegisterCompiledInInfo为例填入信息
        TType* (*OuterRegisterFn)();// Z_Construct_UClass_AReflectTestActor
        TType* (*InnerRegisterFn)();//AReflectTestActor::StaticClass
        const TCHAR* PackageName;// TEXT("AReflectTestActor")
        TInfo* Info;//&Z_Registration_Info_UClass_AReflectTestActor
#if WITH_RELOAD
        TType* OldSingleton;
#endif

#if WITH_RELOAD
        bool bHasChanged;
#endif
    };

这里调用的InnerRegisterFn是前面收集信息的时候,收集的FClassRegisterCompiledInInfo中的AReflectTestActor::StaticClass,我们回看代码生成部分的解析,这里的AReflectTestActor::StaticClass其实就是GetPrivateStaticClassBody()

FClassRegisterCompiledInInfoAReflectTestActorstruct Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_Statics
{
 static constexpr FClassRegisterCompiledInInfo ClassInfo[] = {
     { Z_Construct_UClass_AReflectTestActor, AReflectTestActor::StaticClass, TEXT("AReflectTestActor"), &Z_Registration_Info_UClass_AReflectTestActor, CONSTRUCT_RELOAD_VERSION_INFO(FClassReloadVersionInfo, sizeof(AReflectTestActor), 2785921082U) },
 };
};

所以UClassRegisterAllCompiledInClasses做的其实就是三件事,初始化了这个类和其super、Outer的StaticClass、加入Package的链表和哈希表、设置了这个类的super和ClassWithin(outer)

void GetPrivateStaticClassBody(
 const TCHAR* PackageName, 
 //实参:StaticPackage(),
 //说明:在.generrated.h中DECLARE_CLASS 定义的StaticPackage()
 const TCHAR* Name, //实参:(TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0)
 //说明:+1去掉前缀比如AActor的A,给准备废弃的类加上
 UClass*& ReturnClass, //这个类的注册信息单例Z_Registration_Info_UClass_##TClass.InnerSingleton
 void(*RegisterNativeFunc)(),//StaticRegisterNatives##TClass,注册函数用
 uint32 InSize,//sizeof(TClass),类的大小
 uint32 InAlignment,// alignof(TClass),结构体对齐的字节数16/8/4/2/1
 EClassFlags InClassFlags,//StaticClassFlags,解释这个类的信息的enum
 EClassCastFlags InClassCastFlags,//StaticClassCastFlags(), 用于在cast的时候计算类之间关系的位向量
 const TCHAR* InConfigName,//配置文件名
 UClass::ClassConstructorType InClassConstructor, //__DefaultConstructor
 UClass::ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,//hotreload的时候使用来构造虚函数表,暂时不管
 FUObjectCppClassStaticFunctions&& InCppClassStaticFunctions,// GC使用的添加额外引用对象的静态函数指针,若没有定义,则会调用到UObject::AddReferencedObjects,默认函数体为空。
 UClass::StaticClassFunctionType InSuperClassFn,//获取基类UClass*的函数指针
 UClass::StaticClassFunctionType InWithinClassFn//获取对象外部类UClass*的函数指针,默认是UObject
 )
{
#if WITH_RELOAD
//忽略热加载
#endif
	//使用全局内存分配器获取一块内存,让这个单例指向其地址	
 ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UClass), alignof(UClass), true);
 ReturnClass = ::new (ReturnClass)//使用placement new 来在刚刚分配的内存上调用UClass的构造函数,构造了UClass对象(这里应该还未注册反射信息)
     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);

 //初始化Super、Outer的Uclass,里面进行与this的关联、注册Package和自身到一个链表和哈希表中
 InitializePrivateStaticClass(
     InSuperClassFn(),
     ReturnClass,
     InWithinClassFn(),
     PackageName,
     Name
     );

 // Register the class's native functions.
 RegisterNativeFunc();//StaticRegisterNatives##TClass,注册函数到Class里的TArray<FNativeFunctionLookup> NativeFunctionLookupTable;
}

UObjectProcessRegistrants:

主要做的事情是:在DeferredRegister完善UClass对象第一次构造没补充的内容,并放进全局GUObjectArray中和到FUObjectHashTables中

/**
 * Process the auto register objects adding them to the UObject array
 */
static void UObjectProcessRegistrants()
{
	SCOPED_BOOT_TIMING("UObjectProcessRegistrants");

	check(UObjectInitialized());
	// Make list of all objects to be registered.
	TArray<FPendingRegistrant> PendingRegistrants;
	DequeuePendingAutoRegistrants(PendingRegistrants);//将我们之前的那个链表GFirstPendingRegistrant放到这个数组里

	for(int32 RegistrantIndex = 0;RegistrantIndex < PendingRegistrants.Num();++RegistrantIndex)
	{
		const FPendingRegistrant& PendingRegistrant = PendingRegistrants[RegistrantIndex];

		UObjectForceRegistration(PendingRegistrant.Object, false);

		check(PendingRegistrant.Object->GetClass()); // should have been set by DeferredRegister

		// Register may have resulted in new pending registrants being enqueued, so dequeue those.
		DequeuePendingAutoRegistrants(PendingRegistrants);
	}
}
void UObjectForceRegistration(UObjectBase* Object, bool bCheckForModuleRelease)
{
	LLM_SCOPE(ELLMTag::UObject);
    //这个就是我们前面构造好的哈希表
	TMap<UObjectBase*, FPendingRegistrantInfo>& PendingRegistrants = FPendingRegistrantInfo::GetMap();

	FPendingRegistrantInfo* Info = PendingRegistrants.Find(Object);
	if (Info)
	{
		const TCHAR* PackageName = Info->PackageName;
#if USE_PER_MODULE_UOBJECT_BOOTSTRAP
		if (bCheckForModuleRelease)
		{
			UObjectReleaseModuleRegistrants(FName(PackageName));
		}
#endif
		const TCHAR* Name = Info->Name;
		PendingRegistrants.Remove(Object);  // delete this first so that it doesn't try to do it twice
		Object->DeferredRegister(UClass::StaticClass(),PackageName,Name);
	}
}
void UObjectBase::DeferredRegister(UClass *UClassStaticClass,const TCHAR* PackageName,const TCHAR* InName)
{
	check(UObjectInitialized());
	// Set object properties.
	UPackage* Package = CreatePackage(PackageName);//初步构造Package
	check(Package);
	Package->SetPackageFlags(PKG_CompiledIn);
	OuterPrivate = Package;//设定这个UClass的Outer是Package

	check(UClassStaticClass);
	check(!ClassPrivate);
	ClassPrivate = UClassStaticClass;//设定这个UClass的类型,所以就是UClass

    //加入全局Object表
	// 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);
}
void UObjectBase::AddObject(FName InName, EInternalObjectFlags InSetInternalFlags, int32 InInternalIndex, int32 InSerialNumber)
{
	NamePrivate = InName;
	EInternalObjectFlags InternalFlagsToSet = InSetInternalFlags;
	if (!IsInGameThread())
	{
		InternalFlagsToSet |= EInternalObjectFlags::Async;
	}
	if (ObjectFlags & RF_MarkAsRootSet)
	{		
		InternalFlagsToSet |= EInternalObjectFlags::RootSet;
		ObjectFlags &= ~RF_MarkAsRootSet;
	}
	if (ObjectFlags & RF_MarkAsNative)
	{
		InternalFlagsToSet |= EInternalObjectFlags::Native;
		ObjectFlags &= ~RF_MarkAsNative;
	}
    //加入全局UObjArray,GUObjectArray中
	GUObjectArray.AllocateUObjectIndex(this, InternalFlagsToSet, InInternalIndex, InSerialNumber);
	check(InName != NAME_None && InternalIndex >= 0);
    //哈希这个Object,到FUObjectHashTables中
	HashObject(this);
	check(IsValidLowLevel());
}

UObjectLoadAllCompiledInStructs

/**
 * Call StaticStruct for each struct...this sets up the internal singleton, and important works correctly with hot reload
 */
static void UObjectLoadAllCompiledInStructs()
{
	SCOPED_BOOT_TIMING("UObjectLoadAllCompiledInStructs");

	FEnumDeferredRegistry& EnumRegistry = FEnumDeferredRegistry::Get();
	FStructDeferredRegistry& StructRegistry = FStructDeferredRegistry::Get();

	{
		SCOPED_BOOT_TIMING("UObjectLoadAllCompiledInStructs -  CreatePackages (could be optimized!)");
		EnumRegistry.DoPendingPackageRegistrations();
		StructRegistry.DoPendingPackageRegistrations();
	}

	// Load Structs
	EnumRegistry.DoPendingOuterRegistrations(true);
	StructRegistry.DoPendingOuterRegistrations(true);
}

StructRegistry.DoPendingPackageRegistrations()

这里进行Package的创建,还是那一套,在全局object表里找Package,找到了就返回,找不到就创建

	/**
	* Create all the packages for the packages associated with the registrations
	*/
	void DoPendingPackageRegistrations()
	{
		for (int32 Index = ProcessedRegistrations, Num = Registrations.Num(); Index < Num; ++Index)
		{
			CreatePackage(Registrations[Index].PackageName);
            //packageName = TEXT("/Script/ActionRPG")
            //在RegisterCompiledInInfo即通过静态结构体构造函数手机反射信息的时候,把packageName存入了Registrations中
		}
	}

StructRegistry.DoPendingOuterRegistrations(true);

这里进行ScriptStruct即Ustruct反射信息类的创建:
这里就是调用了第二部分提到的收集的静态反射信息

	/**
	* Invoke the outer registration method for all the registrations
	*/
	void DoPendingOuterRegistrations(bool UpdateCounter)
	{
		int32 Num = Registrations.Num();
		for (int32 Index = ProcessedRegistrations; Index < Num; ++Index)
		{
			OuterRegister(Registrations[Index]);//StaticStruct()
		}

		if (UpdateCounter)
		{
			ProcessedRegistrations = Num;
		}
	}

下面是调用链:

class UScriptStruct* FMyStruct::StaticStruct()
{
	if (!Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton)
	{
		Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton = GetStaticStruct(Z_Construct_UScriptStruct_FMyStruct, (UObject*)Z_Construct_UPackage__Script_ActionRPG(), TEXT("MyStruct"));
	}
	return Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton;
}
class UScriptStruct *GetStaticStruct(class UScriptStruct *(*InRegister)(), UObject* StructOuter, const TCHAR* StructName)
{
	UScriptStruct *Result = (*InRegister)();
	NotifyRegistrationEvent(*StructOuter->GetOutermost()->GetName(), StructName, ENotifyRegistrationType::NRT_Struct, ENotifyRegistrationPhase::NRP_Finished, nullptr, false, Result);
	return Result;
}
UScriptStruct* Z_Construct_UScriptStruct_FMyStruct()
{
	if (!Z_Registration_Info_UScriptStruct_MyStruct.InnerSingleton)
	{
		UECodeGen_Private::ConstructUScriptStruct(Z_Registration_Info_UScriptStruct_MyStruct.InnerSingleton, Z_Construct_UScriptStruct_FMyStruct_Statics::StructParams);
	}
	return Z_Registration_Info_UScriptStruct_MyStruct.InnerSingleton;
}
ConstructUScriptStruct

下面就是真正构造UScriptStruct的地方:和UClass的构造一一样,OutStruct是返回给外部的引用参数,Params就是生成的反射信息
经历以下步骤:

  1. Outer的构造
  2. Super的构造
  3. UScriptStruct::ICppStructOps的构造,就是自身反射类的构造,调用的是NewStructOps
    实际上是(UScriptStruct::ICppStructOps*)new UScriptStruct::TCppStructOps<FMyStruct>();下方进行分析
  4. UScriptStruct的构造,传入前面的Outer、super、ICppStructOps、Params中的StructFlags、sizeof、Alignof调用其构造函数构造UScriptStruct,这里就是其区别于Enum的地方:在于其调用了PrepareCppStructOps(),将StructOps中的traits提出并存放到StructFlags中,下方继续分析
  5. ConstructFProperties:这里和UClass一样,就是构造里面标记的Peoperty,并添加到属性链表中,详细分析看后文
  6. StaticLink:这里做的事情就是对前文放入ChildProperties的每个Property进行Link,其实就是设定他们大小、Flag,到下面再分门别类,比如包含对象引用的ObjectPtr..、对象析构后需要再析构的、需要内部再次初始化的属性,便于后面日后的序列化、GC、初始化的时候使用,详细分析看后文
  7. AddMetaData:处理宏标记的meta信息,这里略过(后面补充了Metadata)
	void ConstructUScriptStruct(UScriptStruct*& OutStruct, const FStructParams& Params)
	{
		UObject*                      (*OuterFunc)()     = Params.OuterFunc;
		UScriptStruct*                (*SuperFunc)()     = Params.SuperFunc;
		UScriptStruct::ICppStructOps* (*StructOpsFunc)() = (UScriptStruct::ICppStructOps* (*)())Params.StructOpsFunc;

		UObject*                      Outer     = OuterFunc     ? OuterFunc() : nullptr;
		UScriptStruct*                Super     = SuperFunc     ? SuperFunc() : nullptr;
		UScriptStruct::ICppStructOps* StructOps = StructOpsFunc ? StructOpsFunc() : nullptr;

		if (OutStruct)
		{
			return;
		}

		UScriptStruct* NewStruct = new(EC_InternalUseOnlyConstructor, Outer, UTF8_TO_TCHAR(Params.NameUTF8), Params.ObjectFlags) UScriptStruct(FObjectInitializer(), Super, StructOps, (EStructFlags)Params.StructFlags, Params.SizeOf, Params.AlignOf);
		OutStruct = NewStruct;

		ConstructFProperties(NewStruct, Params.PropertyArray, Params.NumProperties);

		NewStruct->StaticLink();

#if WITH_METADATA
		AddMetaData(NewStruct, Params.MetaDataArray, Params.NumMetaData);
#endif
	}

这是上方用到的参数:StructParams,

//------.gen.cpp中的内容-------
struct Z_Construct_UScriptStruct_FMyStruct_Statics
{
#if WITH_METADATA
	static constexpr UECodeGen_Private::FMetaDataPairParam Struct_MetaDataParams[] = {
		{ "ModuleRelativePath", "ReflectTestActor.h" },
	};
#endif // WITH_METADATA
	static void* NewStructOps()
	{
		return (UScriptStruct::ICppStructOps*)new UScriptStruct::TCppStructOps<FMyStruct>();
	}
	static const UECodeGen_Private::FStructParams StructParams;
};
const UECodeGen_Private::FStructParams Z_Construct_UScriptStruct_FMyStruct_Statics::StructParams = {
	(UObject* (*)())Z_Construct_UPackage__Script_ActionRPG,
	nullptr,
	&NewStructOps,
	"MyStruct",
	nullptr,
	0,
	sizeof(FMyStruct),
	alignof(FMyStruct),
	RF_Public|RF_Transient|RF_MarkAsNative,
	EStructFlags(0x00000001),
	METADATA_PARAMS(UE_ARRAY_COUNT(Z_Construct_UScriptStruct_FMyStruct_Statics::Struct_MetaDataParams), Z_Construct_UScriptStruct_FMyStruct_Statics::Struct_MetaDataParams)
};
//-------------------FStructParams的定义-----------------
	struct FStructParams
	{
		UObject*                          (*OuterFunc)();
		UScriptStruct*                    (*SuperFunc)();
		void*                             (*StructOpsFunc)(); // really returns UScriptStruct::ICppStructOps*
		const char*                         NameUTF8;
		const FPropertyParamsBase* const*   PropertyArray;
		uint16                              NumProperties;
		uint16                              SizeOf;
		uint8                               AlignOf;
		EObjectFlags                        ObjectFlags;
		uint32                              StructFlags; // EStructFlags
#if WITH_METADATA
		uint16                              NumMetaData;
		const FMetaDataPairParam*           MetaDataArray;
#endif
	};


static void* NewStructOps()
{
	return (UScriptStruct::ICppStructOps*)new UScriptStruct::TCppStructOps<FMyStruct>();
}

我之前一直在思考,FastArray中的StructOps模板特化到底是干嘛的

template<>
struct TStructOpsTypeTraits<FInventoryContainerList> : TStructOpsTypeTraitsBase2<FInventoryContainerList>
{
	enum { WithNetDeltaSerializer = true };
};

这里下意识会以为TStructOpsTypeTraits<FInventoryContainerList>这个类型是跨模块的并疑惑为什么能访问到这个信息,但其实不是的,TStructOpsTypeTraitsBase2这个模板类被定义在Class.h中(模板类随着头文件传播是一种经典的实践,具体行为看符号表与链接),我们在定义自己的TStructOpsTypeTraits的时候,其整个会实例化到我们自己的模块中,任何直接使用到TStructOpsTypeTraits<FInventoryContainerList>的行为,实际上都是在模块内的,所有跨模块的行为都是使用导入的函数举例子:constructUClass是CoreUObjectAPI下的函数,里面使用的StructParams中的参数NewStructOps,就是传递我们模块内部的函数指针NewStructOps。

	static void* NewStructOps()
	{
		return (UScriptStruct::ICppStructOps*)new UScriptStruct::TCppStructOps<FMyStruct>();
	}

在这里,讲TStructOpsTypeTraits、UScriptStruct、UScriptStruct中的ICppStructOps、ICppStructOps的派生模板类TCppStructOps全部理清楚:

ICPPStructOps派生TCppStructOps<>这种类派生模板类的方式,

  1. 统一接口

todo:完善上面的这个模式的理解、补充对下面的解析(TStructOpsTypeTraitsBase2的还没有,大钊文章里有详细解释,好像是Insideue4第十篇)https://zhuanlan.zhihu.com/p/59553490

UScriptStruct::UScriptStruct(const FObjectInitializer& ObjectInitializer, UScriptStruct* InSuperStruct, ICppStructOps* InCppStructOps, EStructFlags InStructFlags, SIZE_T ExplicitSize, SIZE_T ExplicitAlignment )
    : UStruct(ObjectInitializer, InSuperStruct, InCppStructOps ? InCppStructOps->GetSize() : ExplicitSize, InCppStructOps ? InCppStructOps->GetAlignment() : ExplicitAlignment )
    , StructFlags(EStructFlags(InStructFlags | (InCppStructOps ? STRUCT_Native : STRUCT_NoFlags)))
    , bPrepareCppStructOpsCompleted(false)
    , CppStructOps(InCppStructOps)
{
    PrepareCppStructOps(); // propgate flags, etc
}
/** Look for the CppStructOps if we don't already have it and set the property size **/
void UScriptStruct::PrepareCppStructOps()
{
	if (bPrepareCppStructOpsCompleted)
	{
		return;
	}
	if (!CppStructOps)
	{	
//特殊情况,先略过
	}
	check(!(StructFlags & STRUCT_ComputedFlags));
	if (CppStructOps->HasSerializer() || CppStructOps->HasStructuredSerializer())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has a custom serializer."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_SerializeNative );
	}
	if (CppStructOps->HasPostSerialize())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s wants post serialize."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_PostSerializeNative );
	}
	if (CppStructOps->HasPostScriptConstruct())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s wants post script construct."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_PostScriptConstruct);
	}
	if (CppStructOps->HasNetSerializer())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has a custom net serializer."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_NetSerializeNative);

		if (CppStructOps->HasNetSharedSerialization())
		{
			UE_LOG(LogClass, Verbose, TEXT("Native struct %s can share net serialization."),*GetName());
			StructFlags = EStructFlags(StructFlags | STRUCT_NetSharedSerialization);
		}
	}
	if (CppStructOps->HasNetDeltaSerializer())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has a custom net delta serializer."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_NetDeltaSerializeNative);
	}

	if (CppStructOps->IsPlainOldData())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s is plain old data."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_IsPlainOldData | STRUCT_NoDestructor);
	}
	else
	{
		if (CppStructOps->HasCopy())
		{
			UE_LOG(LogClass, Verbose, TEXT("Native struct %s has a native copy."),*GetName());
			StructFlags = EStructFlags(StructFlags | STRUCT_CopyNative);
		}
		if (!CppStructOps->HasDestructor())
		{
			UE_LOG(LogClass, Verbose, TEXT("Native struct %s has no destructor."),*GetName());
			StructFlags = EStructFlags(StructFlags | STRUCT_NoDestructor);
		}
	}
	if (CppStructOps->HasZeroConstructor())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has zero construction."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_ZeroConstructor);
	}
	if (CppStructOps->IsPlainOldData() && !CppStructOps->HasZeroConstructor())
	{
		// hmm, it is safe to see if this can be zero constructed, lets try
		int32 Size = CppStructOps->GetSize();
		uint8* TestData00 = (uint8*)FMemory::Malloc(Size);
		FMemory::Memzero(TestData00,Size);
		CppStructOps->Construct(TestData00);
		CppStructOps->Construct(TestData00); // slightly more like to catch "internal counters" if we do this twice
		bool IsZeroConstruct = true;
		for (int32 Index = 0; Index < Size && IsZeroConstruct; Index++)
		{
			if (TestData00[Index])
			{
				IsZeroConstruct = false;
			}
		}
		FMemory::Free(TestData00);
		if (IsZeroConstruct)
		{
			UE_LOG(LogClass, Verbose, TEXT("Native struct %s has DISCOVERED zero construction. Size = %d"),*GetName(), Size);
			StructFlags = EStructFlags(StructFlags | STRUCT_ZeroConstructor);
		}
	}
	if (CppStructOps->HasIdentical())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has native identical."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_IdenticalNative);
	}
	if (CppStructOps->HasAddStructReferencedObjects())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has native AddStructReferencedObjects."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_AddStructReferencedObjects);
	}
	if (CppStructOps->HasExportTextItem())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has native ExportTextItem."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_ExportTextItemNative);
	}
	if (CppStructOps->HasImportTextItem())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has native ImportTextItem."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_ImportTextItemNative);
	}
	if (CppStructOps->HasSerializeFromMismatchedTag() || CppStructOps->HasStructuredSerializeFromMismatchedTag())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has native SerializeFromMismatchedTag."),*GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_SerializeFromMismatchedTag);
	}
#if WITH_EDITOR
	if (CppStructOps->HasCanEditChange())
	{
		UE_LOG(LogClass, Verbose, TEXT("Native struct %s has native CanEditChange."), *GetName());
		StructFlags = EStructFlags(StructFlags | STRUCT_CanEditChange);
	}
#endif

	check(!bPrepareCppStructOpsCompleted); // recursion is unacceptable
	bPrepareCppStructOpsCompleted = true;
}

todo:PrepareCppStructOps中有一段是“//特殊情况,先略过”,当时我忽略了,现在想来,这里大概是和动态构造有关,UScriptStruct和UClass一样,不只是native用来承载对应反射数据的,在运行时也有构造的需求,但是我不太清楚是什么需求需要用到,查看了一下UDataTable好像会用到。

UClass据我所知,在动态使用的是派生的blueprintGeneratedClass,作为蓝图的动态信息的承载,但是也没细看

搞懂这个有助于深入理解动态类型在ue中的需求、真正理解UScriptStruct

不过似乎和我一开始想了解的:TCppOps和ICppOps这个架构和Tdelegate、IDelegate关系不太大

唯一有关系的地方就是TCppOps的收集第二部分,通过静态结构体构造函数收集反射信息(main之前)

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());
     }
 }

这里之前根本没分析,因为确实和native无关

image-20250625222812700

>	UnrealEditor-CoreUObject.dll!TSet<TTuple<FTopLevelAssetPath,UScriptStruct::ICppStructOps *>,TDefaultMapHashableKeyFuncs<FTopLevelAssetPath,UScriptStruct::ICppStructOps *,0>,FDefaultSetAllocator>::Emplace<TPairInitializer<FTopLevelAssetPath const &,UScriptStruct::ICppStructOps * const &>>(TPairInitializer<FTopLevelAssetPath const &,UScriptStruct::ICppStructOps * const &> && Args, bool * bIsAlreadyInSetPtr) 行 738	C++
 	[内联框架] UnrealEditor-CoreUObject.dll!TMapBase<FTopLevelAssetPath,UScriptStruct::ICppStructOps *,FDefaultSetAllocator,TDefaultMapHashableKeyFuncs<FTopLevelAssetPath,UScriptStruct::ICppStructOps *,0>>::Emplace(const FTopLevelAssetPath &) 行 433	C++
 	[内联框架] UnrealEditor-CoreUObject.dll!TMapBase<FTopLevelAssetPath,UScriptStruct::ICppStructOps *,FDefaultSetAllocator,TDefaultMapHashableKeyFuncs<FTopLevelAssetPath,UScriptStruct::ICppStructOps *,0>>::Add(const FTopLevelAssetPath &) 行 391	C++
 	UnrealEditor-CoreUObject.dll!UScriptStruct::DeferCppStructOps(FTopLevelAssetPath Target, UScriptStruct::ICppStructOps * InCppStructOps) 行 2759	C++
 	UnrealEditor-CoreUObject.dll!RegisterCompiledInInfo(const wchar_t * PackageName, const FClassRegisterCompiledInInfo * ClassInfo, unsigned __int64 NumClassInfo, const FStructRegisterCompiledInInfo * StructInfo, unsigned __int64 NumStructInfo, const FEnumRegisterCompiledInInfo * EnumInfo, unsigned __int64 NumEnumInfo) 行 649	C++
 	UnrealEditor-ActionRPG-Win64-DebugGame.dll!`dynamic initializer for 'Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_2038008627''() 行 266	C++
 	ucrtbase.dll!00007ff86b3ce473()	未知
 	UnrealEditor-ActionRPG-Win64-DebugGame.dll!dllmain_crt_process_attach(HINSTANCE__ * const instance, void * const reserved) 行 66	C++
 	UnrealEditor-ActionRPG-Win64-DebugGame.dll!dllmain_dispatch(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) 行 276	C++
 	ntdll.dll!00007ff86da49a1d()	未知
 	ntdll.dll!00007ff86da9d2f7()	未知
 	ntdll.dll!00007ff86da9d08a()	未知
 	ntdll.dll!00007ff86da6d947()	未知
 	ntdll.dll!00007ff86da4fbae()	未知
 	ntdll.dll!00007ff86da473e4()	未知
 	ntdll.dll!00007ff86da46af4()	未知
 	KernelBase.dll!00007ff86b511ea2()	未知
 	[内联框架] UnrealEditor-Core.dll!FWindowsPlatformProcess::LoadLibraryWithSearchPaths::__l2::<lambda_2>::operator()() 行 2244	C++
 	UnrealEditor-Core.dll!FWindowsPlatformProcess::LoadLibraryWithSearchPaths(const FString & FileName, const TArray<FString,TSizedDefaultAllocator<32>> & SearchPaths) 行 2238	C++
 	UnrealEditor-Core.dll!FWindowsPlatformProcess::GetDllHandle(const wchar_t * FileName) 行 162	C++
 	UnrealEditor-Core.dll!FModuleManager::LoadModuleWithFailureReason(const FName InModuleName, EModuleLoadResult & OutFailureReason, ELoadModuleFlags InLoadModuleFlags) 行 631	C++
 	UnrealEditor-Projects.dll!FModuleDescriptor::LoadModulesForPhase(ELoadingPhase::Type LoadingPhase, const TArray<FModuleDescriptor,TSizedDefaultAllocator<32>> & Modules, TMap<FName,enum EModuleLoadResult,FDefaultSetAllocator,TDefaultMapHashableKeyFuncs<FName,enum EModuleLoadResult,0>> & ModuleLoadErrors) 行 696	C++
 	UnrealEditor-Projects.dll!FProjectManager::LoadModulesForProject(const ELoadingPhase::Type LoadingPhase) 行 62	C++
 	UnrealEditor-Win64-DebugGame.exe!FEngineLoop::LoadStartupModules() 行 4738	C++
 	UnrealEditor-Win64-DebugGame.exe!FEngineLoop::PreInitPostStartupScreen(const wchar_t * CmdLine) 行 4000	C++
 	[内联框架] UnrealEditor-Win64-DebugGame.exe!FEngineLoop::PreInit(const wchar_t *) 行 4483	C++
 	[内联框架] UnrealEditor-Win64-DebugGame.exe!EnginePreInit(const wchar_t *) 行 41	C++
 	UnrealEditor-Win64-DebugGame.exe!GuardedMain(const wchar_t * CmdLine) 行 136	C++
 	UnrealEditor-Win64-DebugGame.exe!LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) 行 247	C++
 	UnrealEditor-Win64-DebugGame.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) 行 298	C++
 	[内联框架] UnrealEditor-Win64-DebugGame.exe!invoke_main() 行 102	C++
 	UnrealEditor-Win64-DebugGame.exe!__scrt_common_main_seh() 行 288	C++
 	kernel32.dll!00007ff86ca37374()	未知
 	ntdll.dll!00007ff86da7cc91()	未知

UEnum

TextureDefines.h中的ETextureSourceCompressionFormat为例子

UENUM()
enum ETextureSourceCompressionFormat : int
{
    TSCF_None  UMETA(DisplayName = "None"),
    TSCF_PNG   UMETA(DisplayName = "PNG"),
    TSCF_JPEG  UMETA(DisplayName = "JPEG"),
    TSCF_UEJPEG    UMETA(DisplayName = "UE JPEG"),

    TSCF_MAX
};

以Texture.h中的TEnumAsByte<enum ETextureSourceCompressionFormat> CompressionFormat;为例子

image-20250615213317462

const UECodeGen_Private::FBytePropertyParams Z_Construct_UScriptStruct_FTextureSource_Statics::NewProp_CompressionFormat = { "CompressionFormat", nullptr, (EPropertyFlags)0x0040000800020001, UECodeGen_Private::EPropertyGenFlags::Byte, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(FTextureSource, CompressionFormat), Z_Construct_UEnum_Engine_ETextureSourceCompressionFormat, METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_CompressionFormat_MetaData), NewProp_CompressionFormat_MetaData) }; // 1327261017

UObjectLoadAllCompiledInDefaultProperties:

这里是一个很重要的地方,里调用了反射生成的OuterSingleton(还是StaticClass)构造函数为UClass*们继续构造和创建类默认对象(CDO)

/**
 * Load any outstanding compiled in default properties
 */
static void UObjectLoadAllCompiledInDefaultProperties(TArray<UClass*>& OutAllNewClasses)
{
	TRACE_LOADTIME_REQUEST_GROUP_SCOPE(TEXT("UObjectLoadAllCompiledInDefaultProperties"));

	static FName LongEnginePackageName(TEXT("/Script/Engine"));

	FClassDeferredRegistry& ClassRegistry = FClassDeferredRegistry::Get();

	if (ClassRegistry.HasPendingRegistrations())
	{
		SCOPED_BOOT_TIMING("UObjectLoadAllCompiledInDefaultProperties");
		TArray<UClass*> NewClasses;//存放Packge为TEXT("/Script/ActionRPG")的UClass指针,就是我们项目的PackageName
		TArray<UClass*> NewClassesInCoreUObject;//存放Package为"/Script/CoreUObject"的UClass指针
		TArray<UClass*> NewClassesInEngine;//存放Package为"/Script/Engine"的UClass指针
		//这里会调用.gen生成的构造函数Z_Construct_UClass_AReflectTestActor()来继续构造我们的UClass,把返回的UClass放入对应的TArray中,下面逐个构造CDO     
		ClassRegistry.DoPendingOuterRegistrations(true, [&OutAllNewClasses, &NewClasses, &NewClassesInCoreUObject, &NewClassesInEngine](const TCHAR* PackageName, UClass& Class) -> void
			{
				UE_LOG(LogUObjectBootstrap, Verbose, TEXT("UObjectLoadAllCompiledInDefaultProperties After Registrant %s %s"), PackageName, *Class.GetName());

				if (Class.GetOutermost()->GetFName() == GLongCoreUObjectPackageName)
				{
					NewClassesInCoreUObject.Add(&Class);
				}
				else if (Class.GetOutermost()->GetFName() == LongEnginePackageName)
				{
					NewClassesInEngine.Add(&Class);
				}
				else
				{
					NewClasses.Add(&Class);
				}

				OutAllNewClasses.Add(&Class);//所有UClass都要加进来
			}); 

				//.......第二次分析:

		auto NotifyClassFinishedRegistrationEvents = [](TArray<UClass*>& Classes)
		{
			for (UClass* Class : Classes)
			{
				TCHAR PackageName[FName::StringBufferSize];
				TCHAR ClassName[FName::StringBufferSize];
				Class->GetOutermost()->GetFName().ToString(PackageName);
				Class->GetFName().ToString(ClassName);
				NotifyRegistrationEvent(PackageName, ClassName, ENotifyRegistrationType::NRT_Class, ENotifyRegistrationPhase::NRP_Finished, nullptr, false, Class);
			}
		};

		// notify async loader of all new classes before creating the class default objects
		{
			SCOPED_BOOT_TIMING("NotifyClassFinishedRegistrationEvents");
			NotifyClassFinishedRegistrationEvents(NewClassesInCoreUObject);
			NotifyClassFinishedRegistrationEvents(NewClassesInEngine);
			NotifyClassFinishedRegistrationEvents(NewClasses);
		}

		{
			SCOPED_BOOT_TIMING("CoreUObject Classes");
			for (UClass* Class : NewClassesInCoreUObject) // we do these first because we assume these never trigger loads
			{
				UE_LOG(LogUObjectBootstrap, Verbose, TEXT("GetDefaultObject Begin %s %s"), *Class->GetOutermost()->GetName(), *Class->GetName());
				Class->GetDefaultObject();
				UE_LOG(LogUObjectBootstrap, Verbose, TEXT("GetDefaultObject End %s %s"), *Class->GetOutermost()->GetName(), *Class->GetName());
			}
		}
		{
			SCOPED_BOOT_TIMING("Engine Classes");
			for (UClass* Class : NewClassesInEngine) // we do these second because we want to bring the engine up before the game
			{
				UE_LOG(LogUObjectBootstrap, Verbose, TEXT("GetDefaultObject Begin %s %s"), *Class->GetOutermost()->GetName(), *Class->GetName());
				Class->GetDefaultObject();
				UE_LOG(LogUObjectBootstrap, Verbose, TEXT("GetDefaultObject End %s %s"), *Class->GetOutermost()->GetName(), *Class->GetName());
			}
		}
		{
			SCOPED_BOOT_TIMING("Other Classes");
			for (UClass* Class : NewClasses)
			{
				UE_LOG(LogUObjectBootstrap, Verbose, TEXT("GetDefaultObject Begin %s %s"), *Class->GetOutermost()->GetName(), *Class->GetName());
				Class->GetDefaultObject();//这里是创建我们类的CDO的入口
				UE_LOG(LogUObjectBootstrap, Verbose, TEXT("GetDefaultObject End %s %s"), *Class->GetOutermost()->GetName(), *Class->GetName());
			}
		}
//下面好像也是GC相关的
		FFeedbackContext& ErrorsFC = UClass::GetDefaultPropertiesFeedbackContext();
		if (ErrorsFC.GetNumErrors() || ErrorsFC.GetNumWarnings())
		{
			TArray<FString> AllErrorsAndWarnings;
			ErrorsFC.GetErrorsAndWarningsAndEmpty(AllErrorsAndWarnings);

			FString AllInOne;
			UE_LOG(LogUObjectBase, Warning, TEXT("-------------- Default Property warnings and errors:"));
			for (const FString& ErrorOrWarning : AllErrorsAndWarnings)
			{
				UE_LOG(LogUObjectBase, Warning, TEXT("%s"), *ErrorOrWarning);
				AllInOne += ErrorOrWarning;
				AllInOne += TEXT("\n");
			}
			FMessageDialog::Open(EAppMsgType::Ok, FText::Format( NSLOCTEXT("Core", "DefaultPropertyWarningAndErrors", "Default Property warnings and errors:\n{0}"), FText::FromString( AllInOne ) ) );
		}
	}
}

DoPendingOuterRegistrations

这里会调用.gen生成的构造函数Z_Construct_UClass_AReflectTestActor()来继续构造我们的UClass,把返回的UClass放入对应的TArray中,下面再逐个构造CDO

	/**
	* Invoke the outer registration method for all the registrations and invoke the given function with the resulting object
	*/
	template <typename FuncType>
	void DoPendingOuterRegistrations(bool UpdateCounter, FuncType&& InOnRegistration)
	{
		int32 Num = Registrations.Num();
		for (int32 Index = ProcessedRegistrations; Index < Num; ++Index)
		{
			TType* Object = OuterRegister(Registrations[Index]);
			InOnRegistration(Registrations[Index].PackageName, *Object);
		}
		if (UpdateCounter)
		{
			ProcessedRegistrations = Num;
		}
	}
ConstructUClass:

OuterRegister 会调用Z_Construct_UClass_AReflectTestActor(),最终调用到ConstructUClass

UClass* Z_Construct_UClass_AReflectTestActor()
{
    //OuterSingleton依然是StaticClass
	if (!Z_Registration_Info_UClass_AReflectTestActor.OuterSingleton)
	{
    	UECodeGen_Private::ConstructUClass(Z_Registration_Info_UClass_AReflectTestActor.OuterSingleton, Z_Construct_UClass_AReflectTestActor_Statics::ClassParams);
	}
	return Z_Registration_Info_UClass_AReflectTestActor.OuterSingleton;
}

下面是ConstructUClass核心

//@@@ OutClass = Z_Registration_Info_UClass_AReflectTestActor.OuterSingleton
//@@@ Params = Z_Construct_UClass_AReflectTestActor_Statics::ClassParams
void ConstructUClass(UClass*& OutClass, const FClassParams& Params)
{
	if (OutClass && (OutClass->ClassFlags & CLASS_Constructed))
	{
		return;//如果已经构造了就直接返回,通过判NULL和Flag来判断是否已经构造
	}

	for (UObject* (*const *SingletonFunc)() = Params.DependencySingletonFuncArray, *(*const *SingletonFuncEnd)() = SingletonFunc + Params.NumDependencySingletons; SingletonFunc != SingletonFuncEnd; ++SingletonFunc)
	{
		(*SingletonFunc)();//调用依赖项的构造函数,是和这个一样的ConstructUClass,在我这里的例子是:
			/*
			(UObject* (*)())Z_Construct_UClass_AActor,我们的Actor依赖于AActor
			(UObject* (*)())Z_Construct_UPackage__Script_ActionRPG,依赖于Package
			*/
	}

	UClass* NewClass = Params.ClassNoRegisterFunc();//这里调用的就是inner的StaticClass,构造好了的会直接返回(没经过前面流程的需要调用)
	OutClass = NewClass;
	//防止再次构造
	if (NewClass->ClassFlags & CLASS_Constructed)
	{
		return;
	}
	
	UObjectForceRegistration(NewClass);//前面调用过一次,就是把Uclass放到全局obj表里(没经过前面流程的需要调用)

	UClass* SuperClass = NewClass->GetSuperClass();//这里返回的就是SuperStruct在innerConstruct中设置过,无论是前面流程UClassRegisterAllCompiledInClasses调用过STaticClass还是在这里调用过ClassNoRegisterFunc()的StaticClass,到了这一步,都调用过了StaticClass
	if (SuperClass)
	{
		NewClass->ClassFlags |= (SuperClass->ClassFlags & CLASS_Inherit);
	}

	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->ReferenceSchema.Reset();//gc相关
	}
    
	//下面分析
	NewClass->CreateLinkAndAddChildFunctionsToMap(Params.FunctionLinkArray, Params.NumFunctions);

    //下面分析
	ConstructFProperties(NewClass, Params.PropertyArray, Params.NumProperties);

	if (Params.ClassConfigNameUTF8)
	{
        //ClassConfigNameUTF8 = "Engine"
		NewClass->ClassConfigName = FName(UTF8_TO_TCHAR(Params.ClassConfigNameUTF8));
	}
	
    //@@@ CppClassInfo = static constexpr FCppClassTypeInfoStatic StaticCppClassTypeInfo = {
	//	TCppClassTypeTraits<AReflectTestActor>::IsAbstract,
	//};
	NewClass->SetCppTypeInfoStatic(Params.CppClassInfo);// 设置是否为虚类
	
    //这里是对interface的,先掠过
	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
    AddMetaData(NewClass, Params.MetaDataArray, Params.NumMetaData);
#endif

    NewClass->StaticLink();//下面进行独立分析

    NewClass->SetSparseClassDataStruct(NewClass->GetSparseClassDataArchetypeStruct());//SparseClassDataStruct是一个UClass的一个实验性新功能,如果一些属性不会在实例化后更改,比如他是一个ReadOnly的,那么就可以放在这里,作为常量,类似字符串的短字符串优化
}

ConstructUFunction & CreateLinkAndAddChildFunctionsToMap

CreateLinkAndAddChildFunctionsToMap:这个函数干的就是构造好UClass里的FuncMap
其实就是根据不同的情况创建UFunction对象,然后Bind(绑定函数指针),Link,然后放到了FuncMap当中

//	/** Map of all functions by name contained in this class */
//TMap<FName, TObjectPtr<UFunction>> FuncMap;

    //@@@ FunctionLinkArray = static constexpr FClassFunctionLinkInfo FuncInfo[] = {
	//	{ &Z_Construct_UFunction_AReflectTestActor_AddSpeed, "AddSpeed" }, // 2567349281
	//};
    //@@@ NumFunctions = UE_ARRAY_COUNT(FuncInfo),
void UClass::CreateLinkAndAddChildFunctionsToMap(const FClassFunctionLinkInfo* Functions, uint32 NumFunctions)
{
	for (; NumFunctions; --NumFunctions, ++Functions)
	{
		const char* FuncNameUTF8 = Functions->FuncNameUTF8;
		UFunction*  Func         = Functions->CreateFuncPtr();

		Func->Next = Children;
		Children = Func;

		AddFunctionToFunctionMap(Func, FName(UTF8_TO_TCHAR(FuncNameUTF8)));
	}
}

	/** Add a function to the function map */
	void AddFunctionToFunctionMap(UFunction* Function, FName FuncName)
	{
		{
			FUClassFuncScopeWriteLock ScopeLock(FuncMapLock);
			FuncMap.Add(FuncName, Function);
		}
		{
			// Remove from the function cache if it exists
			FUClassFuncScopeWriteLock ScopeLock(AllFunctionsCacheLock);
			AllFunctionsCache.Remove(FuncName);
		}
	}
//--------------------------插入FClassFunctionLinkInfo的定义
struct FClassFunctionLinkInfo
{
	UFunction* (*CreateFuncPtr)();
	const char* FuncNameUTF8;
};
//-------------------------------------------------------------------
//--------------------------插入gen.cpp中生成的内容---------------------
UFunction* Z_Construct_UFunction_AReflectTestActor_AddSpeed()
{
	static UFunction* ReturnFunction = nullptr;
	if (!ReturnFunction)
	{
		UECodeGen_Private::ConstructUFunction(&ReturnFunction, Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::FuncParams);
	}
	return ReturnFunction;
}
------------------------------------------------------------------------
//Functions的调用会最终来到这里
	FORCEINLINE void ConstructUFunctionInternal(UFunction*& OutFunction, const FFunctionParams& Params, UFunction** SingletonPtr)
	{
		UObject*   (*OuterFunc)() = Params.OuterFunc;
		UFunction* (*SuperFunc)() = Params.SuperFunc;

		UObject*   Outer = OuterFunc ? OuterFunc() : nullptr;
		UFunction* Super = SuperFunc ? SuperFunc() : nullptr;

		if (OutFunction)
		{
			return;
		}

		FName FuncName(UTF8_TO_TCHAR(Params.NameUTF8));

#if WITH_LIVE_CODING
//这里先不管
#endif

		UFunction* NewFunction;
		if (Params.FunctionFlags & FUNC_Delegate)
		{
			if (Params.OwningClassName == nullptr)
			{
				NewFunction = new (EC_InternalUseOnlyConstructor, Outer, FuncName, Params.ObjectFlags) UDelegateFunction(
					FObjectInitializer(),
					Super,
					Params.FunctionFlags,
					Params.StructureSize
				);
			}
			else
			{
				USparseDelegateFunction* NewSparseFunction = new (EC_InternalUseOnlyConstructor, Outer, FuncName, Params.ObjectFlags) USparseDelegateFunction(
					FObjectInitializer(),
					Super,
					Params.FunctionFlags,
					Params.StructureSize
				);
				NewSparseFunction->OwningClassName = FName(Params.OwningClassName);
				NewSparseFunction->DelegateName = FName(Params.DelegateName);
				NewFunction = NewSparseFunction;
			}
		}
		else
		{
			NewFunction = new (EC_InternalUseOnlyConstructor, Outer, FuncName, Params.ObjectFlags) UFunction(
				FObjectInitializer(),
				Super,
				Params.FunctionFlags,
				Params.StructureSize
			);
		}
		OutFunction = NewFunction;

#if WITH_LIVE_CODING
		NewFunction->SingletonPtr = SingletonPtr;
		if (NewFunction == PrevFunction)
		{
			NewFunction->Next = PrevFunctionNextField;
		}
#endif

#if WITH_METADATA
		AddMetaData(NewFunction, Params.MetaDataArray, Params.NumMetaData);
#endif
		NewFunction->RPCId = Params.RPCId; //设置RPCId
		NewFunction->RPCResponseId = Params.RPCResponseId;//设置RPCResponseId
		//把返回值和参数,像构建Property一样,构造后init,放入UFunction(UFunction继承自UStruct)中
		ConstructFProperties(NewFunction, Params.PropertyArray, Params.NumProperties);
		//绑定这个UFunction到对应函数指针
		NewFunction->Bind();
		NewFunction->StaticLink();
	}

/*Bind就是绑定UFUnction内部的Func到都是一样签名的DECLARE_FUNCTION定义的函数中,
蓝图调用函数会经过void UObject::ProcessEvent( UFunction* Function, void* Parms )
UFunction::Invoke{return (*Func)(Obj, Stack, RESULT_PARAM);}
最终来到这里绑定的函数入口
*/
void UFunction::Bind()
{
	UClass* OwnerClass = GetOwnerClass();

	// if this isn't a native function, or this function belongs to a native interface class (which has no C++ version), 
	// use ProcessInternal (call into script VM only) as the function pointer for this function
    // 不是Native函数则绑定ProcessInternal地址,UObject中DECLARE_FUNCTION(ProcessInternal)
	if (!HasAnyFunctionFlags(FUNC_Native))
	{
		// Use processing function.
		Func = &UObject::ProcessInternal;
	}
	else
	{
        // 是Native函数则从NativeFunctionLookupTable表中查询指针便规定,这里再STaticClass中的最后把生成的exec函数都放入了NativeFunctionLookupTable中。
		// Find the function in the class's native function lookup table.
		FName Name = GetFName();
		FNativeFunctionLookup* Found = OwnerClass->NativeFunctionLookupTable.FindByPredicate([=](const FNativeFunctionLookup& NativeFunctionLookup){ return Name == NativeFunctionLookup.Name; });
		if (Found)
		{
			Func = Found->Pointer;
		}
#if USE_COMPILED_IN_NATIVES
		else if (!HasAnyFunctionFlags(FUNC_NetRequest))
		{
			UE_LOG(LogClass, Warning,TEXT("Failed to bind native function %s.%s"),*OwnerClass->GetName(),*GetName());
		}
#endif
	}
}
//UObject::ProcessInternal:
    DEFINE_FUNCTION(UObject::ProcessInternal)
    {
    #if DO_BLUEPRINT_GUARD
        // remove later when stable
        if (P_THIS->GetClass()->HasAnyClassFlags(CLASS_NewerVersionExists))
        {
            if (!GIsReinstancing)
            {
                ensureMsgf(!P_THIS->GetClass()->HasAnyClassFlags(CLASS_NewerVersionExists), TEXT("Object '%s' is being used for execution, but its class is out of date and has been replaced with a recompiled class!"), *P_THIS->GetFullName());
            }
            return;
        }
    #endif

        UFunction* Function = (UFunction*)Stack.Node;
        int32 FunctionCallspace = P_THIS->GetFunctionCallspace(Function, NULL);
        if (FunctionCallspace & FunctionCallspace::Remote)
        {
            P_THIS->CallRemoteFunction(Function, Stack.Locals, Stack.OutParms, NULL);
        }

        if (FunctionCallspace & FunctionCallspace::Local)
        {
            ProcessLocalScriptFunction(Context, Stack, RESULT_PARAM);
        }
        else
        {
            FProperty* ReturnProp = (Function)->GetReturnProperty();
            ClearReturnValue(ReturnProp, RESULT_PARAM);
        }
    }
ConstructFProperties:

就是根据FProperty类型来new一个对应的对象,什么FintProperty自己的构造函数体都是空的,FProperty干完了,在FProperty构造函数中有绑定到Outer的操作(init)、还有设置其到开头地址的Offset的操作
细节:

  1. FxxxxPropertyParams:
    在存储的时候,不同FProperty的FxxxxPropertyParams*靠强制类型转换,统一到FPropertyParamsBase*(类型擦除)来存储到容器中(因为这里只是要统一的指针类型来存储,所以貌似用void*都行)
    在使用的时候,再靠模板类型,进行强制类型转换实现静态多态
    image-20250523221751932
//const UECodeGen_Private::FFloatPropertyParams Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Speed = { "Speed", nullptr, (EPropertyFlags)0x0010000000000000, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(AReflectTestActor, Speed), METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_Speed_MetaData), NewProp_Speed_MetaData) };
//const UECodeGen_Private::FFloatPropertyParams Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Health = { "Health", nullptr, (EPropertyFlags)0x0010000000000020, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(AReflectTestActor, Health), METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_Health_MetaData), NewProp_Health_MetaData) };
//@@@ PropertyArray = const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_AReflectTestActor_Statics::PropPointers[] = {
//	(const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Speed,
//	(const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Health,
//};
    //@@@ NumProperties = UE_ARRAY_COUNT (Z_Construct_UClass_AReflectTestActor_Statics::PropPointers)

void ConstructFProperties(UObject* Outer, const FPropertyParamsBase* const* PropertyArray, int32 NumProperties)
{
    // Move pointer to the end, because we'll iterate backwards over the properties
    PropertyArray += NumProperties;
    while (NumProperties)
    {
        ConstructFProperty(Outer, PropertyArray, NumProperties);
    }
}

void ConstructFProperty(FFieldVariant Outer, const FPropertyParamsBase* const*& PropertyArray, int32& NumProperties)
{
	const FPropertyParamsBase* PropBase = *--PropertyArray;

	uint32 ReadMore = 0;

	FProperty* NewProp = nullptr;
	switch (PropBase->Flags & PropertyTypeMask)
	{
		default:
		{
			// Unsupported property type
			check(false);
		}

		case EPropertyGenFlags::Byte:
		{
			NewProp = NewFProperty<FByteProperty, FBytePropertyParams>(Outer, *PropBase);
		}
		break;

		case EPropertyGenFlags::Int8:
		{
			NewProp = NewFProperty<FInt8Property, FInt8PropertyParams>(Outer, *PropBase);
		}
		break;
            //........................一堆case
const UECodeGen_Private::FFloatPropertyParams Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Speed = { "Speed", nullptr, (EPropertyFlags)0x0010000000000000, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(AReflectTestActor, Speed), METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_Speed_MetaData), NewProp_Speed_MetaData) };
const UECodeGen_Private::FFloatPropertyParams Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Health = { "Health", nullptr, (EPropertyFlags)0x0010000000000020, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(AReflectTestActor, Health), METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_Health_MetaData), NewProp_Health_MetaData) };
const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_AReflectTestActor_Statics::PropPointers[] = {
	(const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Speed,
	(const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Health,
};
static_assert(UE_ARRAY_COUNT(Z_Construct_UClass_AReflectTestActor_Statics::PropPointers) < 2048);

本文例子生存的FProperty相关的反射信息

NewFProperty最终会来到FProperty构造函数中
image-20250523220230810

FProperty::FProperty(FFieldVariant InOwner, const UECodeGen_Private::FPropertyParamsBaseWithOffset& Prop, EPropertyFlags AdditionalPropertyFlags /*= CPF_None*/)
	: FField(InOwner, UTF8_TO_TCHAR(Prop.NameUTF8), Prop.ObjectFlags)
	, ArrayDim(1)
	, ElementSize(0)
	, PropertyFlags(Prop.PropertyFlags | AdditionalPropertyFlags)
	, RepIndex(0)
	, BlueprintReplicationCondition(COND_None)
	, Offset_Internal(0)
	, PropertyLinkNext(nullptr)
	, NextRef(nullptr)
	, DestructorLinkNext(nullptr)
	, PostConstructLinkNext(nullptr)
{
	this->Offset_Internal = Prop.Offset;
//这里就是用反射生成的STRUCT_OFFSET(AReflectTestActor, Health)算出的一个Property的Offset
//只有FPropertyParamsBaseWithOffset类型才会设置offset,
//	struct FGenericPropertyParams // : FPropertyParamsBaseWithOffset float、int使用的都是FGenericPropertyParams的别名
//FGenericPropertyParams就是FPropertyParamsBaseWithOffset

	Init();
}

FProperty::FProperty(FFieldVariant InOwner, const UECodeGen_Private::FPropertyParamsBaseWithoutOffset& Prop, EPropertyFlags AdditionalPropertyFlags /*= CPF_None*/)
	: FField(InOwner, UTF8_TO_TCHAR(Prop.NameUTF8), Prop.ObjectFlags)
	, ArrayDim(1)
	, ElementSize(0)
	, PropertyFlags(Prop.PropertyFlags | AdditionalPropertyFlags)
	, RepIndex(0)
	, BlueprintReplicationCondition(COND_None)
	, Offset_Internal(0)
	, PropertyLinkNext(nullptr)
	, NextRef(nullptr)
	, DestructorLinkNext(nullptr)
	, PostConstructLinkNext(nullptr)
{
	Init();
}

void FProperty::Init()
{
#if !WITH_EDITORONLY_DATA
	//@todo.COOKER/PACKAGER: Until we have a cooker/packager step, this can fire when WITH_EDITORONLY_DATA is not defined!
	//	checkSlow(!HasAnyPropertyFlags(CPF_EditorOnly));
#endif // WITH_EDITORONLY_DATA
	checkSlow(GetOwnerUField()->HasAllFlags(RF_Transient));
	checkSlow(HasAllFlags(RF_Transient));

	if (GetOwner<UObject>())
	{
		UField* OwnerField = GetOwnerChecked<UField>();
		OwnerField->AddCppProperty(this);
	}
	else
	{
		FField* OwnerField = GetOwnerChecked<FField>();
		OwnerField->AddCppProperty(this);
	}
}
//重载AddCppProperty
//Property是如何加入UStruct链表的:
void UStruct::AddCppProperty(FProperty* Property)
{
	Property->Next = ChildProperties;
	ChildProperties = Property;
}
void FArrayProperty::AddCppProperty(FProperty* Property)
{
    Inner = Property;   //元素属性
}
void FMapProperty::AddCppProperty(FProperty* Property)
{
    if (!KeyProp) {KeyProp = Property;}//第一个是键属性
    else {ValueProp = Property;}//第二个是值属性
}
void FSetProperty::AddCppProperty(FProperty* Property)
{
    ElementProp = Property;//元素属性
}

void FEnumProperty::AddCppProperty(FProperty* Inner)
{
    UnderlyingProp = CastChecked<UNumericProperty>(Inner);//依靠的整数属性
}


image-20250408163645991

// Offset of a struct member.
#ifdef __clang__
#define STRUCT_OFFSET( struc, member )	__builtin_offsetof(struc, member)
#else
#define STRUCT_OFFSET( struc, member )	offsetof(struc, member)
#endif

	#define offsetof(s,m) ((::size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
//这个offsetof的解释:
/* 
	其基本可以等同于 ((size_t)&((s*)0)->m)
	原理就是把0地址转为s*然后让其指向m对象,然后取地址,这样就得到了m对象对于s开头的offset(偏移量)
*/

下面是.gen.cpp中生成的Z_Construct_UClass_AReflectTestActor相关内容

	static const UECodeGen_Private::FFloatPropertyParams NewProp_Speed;
	static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[];
	static UObject* (*const DependentSingletons[])();
	static constexpr FClassFunctionLinkInfo FuncInfo[] = {
		{ &Z_Construct_UFunction_AReflectTestActor_AddSpeed, "AddSpeed" }, // 2567349281
	};
	static_assert(UE_ARRAY_COUNT(FuncInfo) < 2048);
	static constexpr FCppClassTypeInfoStatic StaticCppClassTypeInfo = {
		TCppClassTypeTraits<AReflectTestActor>::IsAbstract,
	};
	static const UECodeGen_Private::FClassParams ClassParams;
};
const UECodeGen_Private::FFloatPropertyParams Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Speed = { "Speed", nullptr, (EPropertyFlags)0x0010000000000000, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(AReflectTestActor, Speed), METADATA_PARAMS(UE_ARRAY_COUNT(NewProp_Speed_MetaData), NewProp_Speed_MetaData) };
const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UClass_AReflectTestActor_Statics::PropPointers[] = {
	(const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UClass_AReflectTestActor_Statics::NewProp_Speed,
};
static_assert(UE_ARRAY_COUNT(Z_Construct_UClass_AReflectTestActor_Statics::PropPointers) < 2048);
UObject* (*const Z_Construct_UClass_AReflectTestActor_Statics::DependentSingletons[])() = {
	(UObject* (*)())Z_Construct_UClass_AActor,
	(UObject* (*)())Z_Construct_UPackage__Script_ActionRPG,
};
static_assert(UE_ARRAY_COUNT(Z_Construct_UClass_AReflectTestActor_Statics::DependentSingletons) < 16);
//---------------------这里补上定义-------------------
	struct FClassParams
	{
		UClass*                                   (*ClassNoRegisterFunc)();
//&AReflectTestActor::StaticClass,
		const char*                                 ClassConfigNameUTF8;
		const FCppClassTypeInfoStatic*              CppClassInfo;
		UObject*                           (*const *DependencySingletonFuncArray)();
		const FClassFunctionLinkInfo*               FunctionLinkArray;
		const FPropertyParamsBase* const*           PropertyArray;
		const FImplementedInterfaceParams*          ImplementedInterfaceArray;
		uint32                                      NumDependencySingletons : 4;
		uint32                                      NumFunctions : 11;
		uint32                                      NumProperties : 11;
		uint32                                      NumImplementedInterfaces : 6;
		uint32                                      ClassFlags; // EClassFlags
#if WITH_METADATA
		uint16                                      NumMetaData;
		const FMetaDataPairParam*                   MetaDataArray;
#endif
	};
//------------------------------------------------
const UECodeGen_Private::FClassParams Z_Construct_UClass_AReflectTestActor_Statics::ClassParams = {
	&AReflectTestActor::StaticClass,
	"Engine",
	&StaticCppClassTypeInfo,
	DependentSingletons,
	FuncInfo,
	Z_Construct_UClass_AReflectTestActor_Statics::PropPointers,
	nullptr,
	UE_ARRAY_COUNT(DependentSingletons),
	UE_ARRAY_COUNT(FuncInfo),
	UE_ARRAY_COUNT(Z_Construct_UClass_AReflectTestActor_Statics::PropPointers),
	0,
	0x009000A4u,
	METADATA_PARAMS(UE_ARRAY_COUNT(Z_Construct_UClass_AReflectTestActor_Statics::Class_MetaDataParams), Z_Construct_UClass_AReflectTestActor_Statics::Class_MetaDataParams)
};
UClass* Z_Construct_UClass_AReflectTestActor()
{
	if (!Z_Registration_Info_UClass_AReflectTestActor.OuterSingleton)
	{
	UECodeGen_Private::ConstructUClass(Z_Registration_Info_UClass_AReflectTestActor.OuterSingleton, Z_Construct_UClass_AReflectTestActor_Statics::ClassParams);
	}
	return Z_Registration_Info_UClass_AReflectTestActor.OuterSingleton;
}
struct Z_CompiledInDeferFile_FID_Unreal_Projects_ActionRPG_Source_ActionRPG_ReflectTestActor_h_Statics
{
//Z_Construct_UClass_AReflectTestActor就是OuterRegister
	static constexpr FClassRegisterCompiledInInfo ClassInfo[] = {
		{ Z_Construct_UClass_AReflectTestActor, AReflectTestActor::StaticClass, TEXT("AReflectTestActor"), &Z_Registration_Info_UClass_AReflectTestActor, CONSTRUCT_RELOAD_VERSION_INFO(FClassReloadVersionInfo, sizeof(AReflectTestActor), 2785921082U) },
	};
};

Function相关:

// Begin Class AReflectTestActor Function AddSpeed
struct Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics
{
	struct ReflectTestActor_eventAddSpeed_Parms
	{
		float InSpeed;
	};
#if WITH_METADATA
	static constexpr UECodeGen_Private::FMetaDataPairParam Function_MetaDataParams[] = {
		{ "ModuleRelativePath", "ReflectTestActor.h" },
	};
#endif // WITH_METADATA
	static const UECodeGen_Private::FFloatPropertyParams NewProp_InSpeed;
	static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[];
	static const UECodeGen_Private::FFunctionParams FuncParams;
};
const UECodeGen_Private::FFloatPropertyParams Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::NewProp_InSpeed = { "InSpeed", nullptr, (EPropertyFlags)0x0010000000000080, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(ReflectTestActor_eventAddSpeed_Parms, InSpeed), METADATA_PARAMS(0, nullptr) };
const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::PropPointers[] = {
	(const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::NewProp_InSpeed,
};
static_assert(UE_ARRAY_COUNT(Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::PropPointers) < 2048);
const UECodeGen_Private::FFunctionParams Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::FuncParams = { (UObject*(*)())Z_Construct_UClass_AReflectTestActor, nullptr, "AddSpeed", nullptr, nullptr, Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::PropPointers, UE_ARRAY_COUNT(Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::PropPointers), sizeof(Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::ReflectTestActor_eventAddSpeed_Parms), RF_Public|RF_Transient|RF_MarkAsNative, (EFunctionFlags)0x00020401, 0, 0, METADATA_PARAMS(UE_ARRAY_COUNT(Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::Function_MetaDataParams), Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::Function_MetaDataParams) };
static_assert(sizeof(Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::ReflectTestActor_eventAddSpeed_Parms) < MAX_uint16);
UFunction* Z_Construct_UFunction_AReflectTestActor_AddSpeed()
{
	static UFunction* ReturnFunction = nullptr;
	if (!ReturnFunction)
	{
		UECodeGen_Private::ConstructUFunction(&ReturnFunction, Z_Construct_UFunction_AReflectTestActor_AddSpeed_Statics::FuncParams);
	}
	return ReturnFunction;
}
DEFINE_FUNCTION(AReflectTestActor::execAddSpeed)
{
	P_GET_PROPERTY(FFloatProperty,Z_Param_InSpeed);
	P_FINISH;
	P_NATIVE_BEGIN;
	P_THIS->AddSpeed(Z_Param_InSpeed);
	P_NATIVE_END;
}
// End Class AReflectTestActor Function AddSpeed

// Begin Class AReflectTestActor Function RPC_Test
struct ReflectTestActor_eventRPC_Test_Parms
{
	float InDamage;
};
static FName NAME_AReflectTestActor_RPC_Test = FName(TEXT("RPC_Test"));
void AReflectTestActor::RPC_Test(float InDamage)
{
	ReflectTestActor_eventRPC_Test_Parms Parms;
	Parms.InDamage=InDamage;
	ProcessEvent(FindFunctionChecked(NAME_AReflectTestActor_RPC_Test),&Parms);
}
struct Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics
{
#if WITH_METADATA
	static constexpr UECodeGen_Private::FMetaDataPairParam Function_MetaDataParams[] = {
		{ "ModuleRelativePath", "ReflectTestActor.h" },
	};
#endif // WITH_METADATA
	static const UECodeGen_Private::FFloatPropertyParams NewProp_InDamage;
	static const UECodeGen_Private::FPropertyParamsBase* const PropPointers[];
	static const UECodeGen_Private::FFunctionParams FuncParams;
};
const UECodeGen_Private::FFloatPropertyParams Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::NewProp_InDamage = { "InDamage", nullptr, (EPropertyFlags)0x0010000000000080, UECodeGen_Private::EPropertyGenFlags::Float, RF_Public|RF_Transient|RF_MarkAsNative, nullptr, nullptr, 1, STRUCT_OFFSET(ReflectTestActor_eventRPC_Test_Parms, InDamage), METADATA_PARAMS(0, nullptr) };
const UECodeGen_Private::FPropertyParamsBase* const Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::PropPointers[] = {
	(const UECodeGen_Private::FPropertyParamsBase*)&Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::NewProp_InDamage,
};
static_assert(UE_ARRAY_COUNT(Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::PropPointers) < 2048);
const UECodeGen_Private::FFunctionParams Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::FuncParams = { (UObject*(*)())Z_Construct_UClass_AReflectTestActor, nullptr, "RPC_Test", nullptr, nullptr, Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::PropPointers, UE_ARRAY_COUNT(Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::PropPointers), sizeof(ReflectTestActor_eventRPC_Test_Parms), RF_Public|RF_Transient|RF_MarkAsNative, (EFunctionFlags)0x00220CC0, 0, 0, METADATA_PARAMS(UE_ARRAY_COUNT(Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::Function_MetaDataParams), Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::Function_MetaDataParams) };
static_assert(sizeof(ReflectTestActor_eventRPC_Test_Parms) < MAX_uint16);
UFunction* Z_Construct_UFunction_AReflectTestActor_RPC_Test()
{
	static UFunction* ReturnFunction = nullptr;
	if (!ReturnFunction)
	{
		UECodeGen_Private::ConstructUFunction(&ReturnFunction, Z_Construct_UFunction_AReflectTestActor_RPC_Test_Statics::FuncParams);
	}
	return ReturnFunction;
}
DEFINE_FUNCTION(AReflectTestActor::execRPC_Test)
{
	P_GET_PROPERTY(FFloatProperty,Z_Param_InDamage);
	P_FINISH;
	P_NATIVE_BEGIN;
	P_THIS->RPC_Test_Implementation(Z_Param_InDamage);
	P_NATIVE_END;
}
// End Class AReflectTestActor Function RPC_Test

下面给出重要结构体的定义:
image-20250523220724474

	struct FGenericPropertyParams // : FPropertyParamsBaseWithOffset
	{
		const char*      NameUTF8;
		const char*       RepNotifyFuncUTF8;
		EPropertyFlags    PropertyFlags;
		EPropertyGenFlags Flags;
		EObjectFlags     ObjectFlags;
		SetterFuncPtr  SetterFunc;
		GetterFuncPtr  GetterFunc;
		uint16           ArrayDim;
		uint16           Offset;
#if WITH_METADATA
		uint16                              NumMetaData;
		const FMetaDataPairParam*           MetaDataArray;
#endif
	};	


// This is not a base class but is just a common initial sequence of all of the F*PropertyParams types below.
	// We don't want to use actual inheritance because we want to construct aggregated compile-time tables of these things.
	struct FPropertyParamsBase
	{
		const char*    NameUTF8;
		const char*       RepNotifyFuncUTF8;
		EPropertyFlags    PropertyFlags;
		EPropertyGenFlags Flags;
		EObjectFlags   ObjectFlags;
		SetterFuncPtr  SetterFunc;
		GetterFuncPtr  GetterFunc;
		uint16         ArrayDim;
	};

	struct FPropertyParamsBaseWithoutOffset // : FPropertyParamsBase
	{
		const char*		NameUTF8;
		const char* 	  RepNotifyFuncUTF8;
		EPropertyFlags    PropertyFlags;
		EPropertyGenFlags Flags;
		EObjectFlags   ObjectFlags;
		SetterFuncPtr  SetterFunc;
		GetterFuncPtr  GetterFunc;
		uint16         ArrayDim;
	};
	struct FFunctionParams
	{
		UObject*                          (*OuterFunc)();
		UFunction*                        (*SuperFunc)();
		const char*                         NameUTF8;
		const char*                         OwningClassName;
		const char*                         DelegateName;
		const FPropertyParamsBase* const*   PropertyArray;
		uint16                              NumProperties;
		uint16                              StructureSize;
		EObjectFlags                        ObjectFlags;
		EFunctionFlags                      FunctionFlags;
		uint16                              RPCId;
		uint16                              RPCResponseId;
#if WITH_METADATA
		uint16                              NumMetaData;
		const FMetaDataPairParam*           MetaDataArray;
#endif
	};
struct FFunctionParams
{
	UObject* (*OuterFunc)();				// 拥有该函数的对象的ConstructXXXX函数,如果不存在这个对象就原地构造。
	UFunction* (*SuperFunc)();				// 不必多言,父函数。
	const char* NameUTF8;					// 函数名。
	const char* OwningClassName;				// 拥有该函数的函数名?
	const char* DelegateName;				// 如果这是个委托函数,就有委托名。
	const FPropertyParamsBase* const* PropertyArray;	// 字面意思参数数组。
	uint16                              NumProperties;	// 数量。
	uint16                              StructureSize;	// 结构体大小,用于序列化。
	EObjectFlags                        ObjectFlags;	// 比如是否是抽象类的这些的元数据。
	EFunctionFlags                      FunctionFlags;	// 函数特性,是否纯虚这些。
	uint16                              RPCId;		// 那几个RPC函数的标志。
	uint16                              RPCResponseId;	// 识别网络请求响应,比如URL这些啥的,我也不甚了解。
};

FFunctionParams_ref:

  • 重点:StaticLink( ):这里做的事情就是对前文放入ChildProperties的每个Property进行Link,其实就是设定他们大小、Flag,到下面再分门别类,比如包含对象引用的ObjectPtr..、对象析构后需要再析构的、需要内部再次初始化的属性,便于后面日后的序列化、GC、初始化的时候使用

    void UStruct::Link(FArchive& Ar, bool bRelinkExistingProperties)
    {
    	if (bRelinkExistingProperties)
    	{
    		//为Flase不会被调用,这里只会在Relink的时候调用
    	}
    	else
    	{
    		for (FField* Field = ChildProperties; (Field != NULL) && (Field->GetOwner<UObject>() == this); Field = Field->Next)
    		{
    			if (FProperty* Property = CastField<FProperty>(Field))
    			{
    				Property->LinkWithoutChangingOffset(Ar);//这里会调用内部的LinkInternal虚函数,所以每个不同的Property都会调用对应的虚函数
                    /*
                    下面给出例子:
    				TProperty的LinkInternal,什么Int、FLoat都继承的这个,且都没重写,所以最后都调用的这个
                    virtual void LinkInternal(FArchive& Ar) override
                    {
                        SetElementSize();
                        this->PropertyFlags |= TTypeFundamentals::GetComputedFlagsPropertyFlags();
    
                    }
                    */
    			}
    		}
    	}
    
     	
    	// Link the references, structs, and arrays for optimized cleanup.
    	// Note: Could optimize further by adding FProperty::NeedsDynamicRefCleanup, excluding things like arrays of ints.
    	FProperty** PropertyLinkPtr = &PropertyLink;
    	FProperty** DestructorLinkPtr = &DestructorLink;
    	FProperty** RefLinkPtr = (FProperty**)&RefLink;
    	FProperty** PostConstructLinkPtr = &PostConstructLink;
    
    	TArray<const FStructProperty*> EncounteredStructProps;
    	for (TFieldIterator<FProperty> It(this); It; ++It)
    	{
    		FProperty* Property = *It;
    
    		// Ref link contains any properties which contain object references including types with user-defined serializers which don't explicitly specify whether they 
    		// contain object references
    		if (Property->ContainsObjectReference(EncounteredStructProps, EPropertyObjectReferenceType::Any))
    		{
    			*RefLinkPtr = Property;//包含对象引用的属性
    			RefLinkPtr = &(*RefLinkPtr)->NextRef;
    		}
    
    		const UClass* OwnerClass = Property->GetOwnerClass();
    		bool bOwnedByNativeClass = OwnerClass && OwnerClass->HasAnyClassFlags(CLASS_Native | CLASS_Intrinsic);
    
    		if (!Property->HasAnyPropertyFlags(CPF_IsPlainOldData | CPF_NoDestructor) &&
    			!bOwnedByNativeClass) // these would be covered by the native destructor
    		{	
    			// things in a struct that need a destructor will still be in here, even though in many cases they will also be destroyed by a native destructor on the whole struct
    			*DestructorLinkPtr = Property;//在对象析构的时候需要额外析构的属性
    			DestructorLinkPtr = &(*DestructorLinkPtr)->DestructorLinkNext;
    		}
    
    		// Link references to properties that require their values to be initialized and/or copied from CDO post-construction. Note that this includes all non-native-class-owned properties.
    		if (OwnerClass && (!bOwnedByNativeClass || (Property->HasAnyPropertyFlags(CPF_Config) && !OwnerClass->HasAnyClassFlags(CLASS_PerObjectConfig))))
    		{
    			*PostConstructLinkPtr = Property;//需要被初始化或者从CDO Post Construction复制来的属性,比如TArray里面的Property
    			PostConstructLinkPtr = &(*PostConstructLinkPtr)->PostConstructLinkNext;
    		}
    
    #if WITH_EDITORONLY_DATA
    		// Set the bHasAssetRegistrySearchableProperties flag.
    		// Note that we're also iterating over super class properties here so this flag is being automatically inherited
    		bHasAssetRegistrySearchableProperties |= Property->HasAnyPropertyFlags(CPF_AssetRegistrySearchable);
    #endif
    
    		*PropertyLinkPtr = Property;//所有Property都要链接到这里
    		PropertyLinkPtr = &(*PropertyLinkPtr)->PropertyLinkNext;
    	}
    	
        //链表尾部设为Nullptr
    	*PropertyLinkPtr = nullptr;
    	*DestructorLinkPtr = nullptr;
    	*RefLinkPtr = nullptr;
    	*PostConstructLinkPtr = nullptr;
    
        //后面是GC相关的
    	{
    		// Now collect all references from FProperties to UObjects and store them in GC-exposed array for fast access
    		CollectPropertyReferencedObjects(MutableView(ScriptAndPropertyObjectReferences));
    
    #if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
    		// The old (non-EDL) FLinkerLoad code paths create placeholder objects
    		// for classes and functions. We have to babysit these, just as we do
    		// for bytecode references (reusing the AddReferencingScriptExpr fn).
    		// Long term we should not use placeholder objects like this:
    		for(int32 ReferenceIndex = ScriptAndPropertyObjectReferences.Num() - 1; ReferenceIndex >= 0; --ReferenceIndex)
    		{
    			if (ScriptAndPropertyObjectReferences[ReferenceIndex])
    			{
    				if (ULinkerPlaceholderClass* PlaceholderObj = Cast<ULinkerPlaceholderClass>(ScriptAndPropertyObjectReferences[ReferenceIndex]))
    				{
    					// let the placeholder track the reference to it:
    					PlaceholderObj->AddReferencingScriptExpr(reinterpret_cast<UClass**>(&ScriptAndPropertyObjectReferences[ReferenceIndex]));
    				}
    				// I don't currently see how placeholder functions could be present in this list, but that's
    				// a dangerous assumption.
    				ensure(!(ScriptAndPropertyObjectReferences[ReferenceIndex]->IsA<ULinkerPlaceholderFunction>()));
    			}
    			else
    			{
    				// It's possible that in the process of recompilation one of the refernces got GC'd leaving a null ptr in the array
    				ScriptAndPropertyObjectReferences.RemoveAt(ReferenceIndex);
    			}
    		}
    #endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
    	}
    
    #if WITH_EDITORONLY_DATA
    	// Discard old wrapper objects used by property grids
    	for (UPropertyWrapper* Wrapper : PropertyWrappers)
    	{
    		Wrapper->Rename(nullptr, GetTransientPackage(), REN_ForceNoResetLoaders | REN_DoNotDirty | REN_DontCreateRedirectors | REN_NonTransactional);
    		Wrapper->RemoveFromRoot();
    	}
    	PropertyWrappers.Empty();
    #endif
    }
    
    virtual void LinkInternal(FArchive& Ar) override
    {
        SetElementSize();
        this->PropertyFlags |= TTypeFundamentals::GetComputedFlagsPropertyFlags();
    
    }
    //这里获取其类型大小
    	FORCEINLINE void SetElementSize()
    	{
    		this->ElementSize = TTypeFundamentals::CPPSize;
    	}
            /** Type of the CPP property **/
            typedef InTCppType TCppType;
            enum
            {
                CPPSize = sizeof(TCppType),
                CPPAlignment = alignof(TCppType)
            };
    //这一步设置属性的PropertyFlags,用TypeTriats在计算其属性,比如是不是POD、是不是Tirvall、是不是0构造、能否哈希,然后
    	/** Get the property flags corresponding to this C++ type, from the C++ type traits system */
    	static FORCEINLINE EPropertyFlags GetComputedFlagsPropertyFlags()
    	{
    		return 
    			(TIsPODType<TCppType>::Value ? CPF_IsPlainOldData : CPF_None) 
    			| (TIsTriviallyDestructible<TCppType>::Value ? CPF_NoDestructor : CPF_None) 
    			| (TIsZeroConstructType<TCppType>::Value ? CPF_ZeroConstructor : CPF_None)
    			| (TModels_V<CGetTypeHashable, TCppType> ? CPF_HasGetValueTypeHash : CPF_None);
    
    	}
    

    至此,StaticClass构造完成

GetDefaultObject:梦开始的地方,创建CDO

/**
 * Get the default object from the class
 * @param	bCreateIfNeeded if true (default) then the CDO is created if it is null
 * @return		the CDO for this class
 */
UObject* GetDefaultObject(bool bCreateIfNeeded = true) const
{
    if (ClassDefaultObject == nullptr && bCreateIfNeeded)
    {
        InternalCreateDefaultObjectWrapper();
    }

    return ClassDefaultObject;
}
void UClass::InternalCreateDefaultObjectWrapper() const
{
	UE_TRACK_REFERENCING_PACKAGE_SCOPED(this, PackageAccessTrackingOps::NAME_CreateDefaultObject);
	const_cast<UClass*>(this)->CreateDefaultObject();
}

经过上面两层的调用,来到真正创建CDO的地方:

UObject* UClass::CreateDefaultObject()
{
	if ( ClassDefaultObject == NULL )//第一次构造的时候进来,后面就直接返回了
	{
		ensureMsgf(!bLayoutChanging, TEXT("Class named %s creating its CDO while changing its layout"), *GetName());

		UClass* ParentClass = GetSuperClass();//
		UObject* ParentDefaultObject = NULL;
		if ( ParentClass != NULL )//先初始化Parent的CDO
		{
			UObjectForceRegistration(ParentClass);//之前注册过的,现在不需要
			ParentDefaultObject = ParentClass->GetDefaultObject(); // Force the default object to be constructed if it isn't already
			check(GConfig);
			if (GEventDrivenLoaderEnabled && EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME)
			{ 
				check(ParentDefaultObject && !ParentDefaultObject->HasAnyFlags(RF_NeedLoad));
			}
		}

		if ( (ParentDefaultObject != NULL) || (this == UObject::StaticClass()) )
		{
			// If this is a class that can be regenerated, it is potentially not completely loaded.  Preload and Link here to ensure we properly zero memory and read in properties for the CDO
			//蓝图调用的部分
            if( HasAnyClassFlags(CLASS_CompiledFromBlueprint) && (PropertyLink == NULL) && !GIsDuplicatingClassForReinstancing)
			{
				auto ClassLinker = GetLinker();
				if (ClassLinker)
				{
					if (!GEventDrivenLoaderEnabled)
					{
						UField* FieldIt = Children;
						while (FieldIt && (FieldIt->GetOuter() == this))
						{
							// If we've had cyclic dependencies between classes here, we might need to preload to ensure that we load the rest of the property chain
							if (FieldIt->HasAnyFlags(RF_NeedLoad))
							{
								ClassLinker->Preload(FieldIt);
							}
							FieldIt = FieldIt->Next;
						}
					}
					
					StaticLink(true);
				}
			}

			// in the case of cyclic dependencies, the above Preload() calls could end up 
			// invoking this method themselves... that means that once we're done with  
			// all the Preload() calls we have to make sure ClassDefaultObject is still 
			// NULL (so we don't invalidate one that has already been setup)
			if (ClassDefaultObject == NULL)
			{
				// RF_ArchetypeObject flag is often redundant to RF_ClassDefaultObject, but we need to tag
				// the CDO as RF_ArchetypeObject in order to propagate that flag to any default sub objects.
				//这里只是申请了内存,还未构造,并且标记RF_Public|RF_ClassDefaultObject|RF_ArchetypeObject这三个Flag
				ClassDefaultObject = StaticAllocateObject(this, GetOuter(), NAME_None, EObjectFlags(RF_Public|RF_ClassDefaultObject|RF_ArchetypeObject));
				check(ClassDefaultObject);
                //下面是稀疏委托相关:
				// Register the offsets of any sparse delegates this class introduces with the sparse delegate storage
				for (TFieldIterator<FMulticastSparseDelegateProperty> SparseDelegateIt(this, EFieldIteratorFlags::ExcludeSuper, EFieldIteratorFlags::ExcludeDeprecated); SparseDelegateIt; ++SparseDelegateIt)
				{
					const FSparseDelegate& SparseDelegate = SparseDelegateIt->GetPropertyValue_InContainer(ClassDefaultObject);
					USparseDelegateFunction* SparseDelegateFunction = CastChecked<USparseDelegateFunction>(SparseDelegateIt->SignatureFunction);
					FSparseDelegateStorage::RegisterDelegateOffset(ClassDefaultObject, SparseDelegateFunction->DelegateName, (size_t)&SparseDelegate - (size_t)ClassDefaultObject.Get());
				}
				EObjectInitializerOptions InitOptions = EObjectInitializerOptions::None;
				if (!HasAnyClassFlags(CLASS_Native | CLASS_Intrinsic))
				{
					// Blueprint CDOs have their properties always initialized.
					InitOptions |= EObjectInitializerOptions::InitializeProperties;
				}
                //真正调用构造函数构造CDO,这里的构造函数就是我们在StaticClass中构造UClass中传入的,	ClassConstructor		( InClassConstructor )
				//    static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())TClass; }
				(*ClassConstructor)(FObjectInitializer(ClassDefaultObject, ParentDefaultObject, InitOptions));
				
				//这里构造完广播一下	
				if (GetOutermost()->HasAnyPackageFlags(PKG_CompiledIn) && !GetOutermost()->HasAnyPackageFlags(PKG_RuntimeGenerated))
				{
					TCHAR PackageName[FName::StringBufferSize];
					TCHAR CDOName[FName::StringBufferSize];
					GetOutermost()->GetFName().ToString(PackageName);
					GetDefaultObjectName().ToString(CDOName);
					NotifyRegistrationEvent(PackageName, CDOName, ENotifyRegistrationType::NRT_ClassCDO, ENotifyRegistrationPhase::NRP_Finished, nullptr, false, ClassDefaultObject);
				}
				ClassDefaultObject->PostCDOContruct();//可以用户重写的地方,默认为空
			}
		}
	}
	return ClassDefaultObject;
}

至此,CDO构造完成

总结:

  1. CLass Default Object(CDO)的构造需要一个类的构造函数,但是C++的构造函数不能是静态函数,所以我们使用反射生成的静态函数__DefaultConstructor来包装我们的构造函数,并且依靠UClass这个反射类的构造将__DefaultConstructor传入到ClassConstructor中,所以理论上来说,我们在UClass初步构造(UClassRegisterAllCompiledInClasses)这个时候就能构造我们的CDO
  2. 但是在UObjectLoadAllCompiledInDefaultProperties后,UClass构造完毕,这里是收集他们的地方,正好适合做一些统一的工作,CDO的构造也就被放到了这里(猜的)

暂时不知道分类在哪的部分:

ClassWithin是如何做到限制其只能被声明在该Class的?

StaicAllocateObject在CDO构造第一步分配内存中被使用来分配内存,这里有一个check(InOuter->IsA(InClass->ClassWithin))

这里大概能做到限制

ref:https://zhuanlan.zhihu.com/p/672911428

Metadata

metadata从哪里来的:除了我们自己在属性的前加上metadata specifier之外,还有些自动生成的metadata,这些来源暂时不知道

image-20250615202010568

反射生成的metadata信息如何收集:在前文有详细解释反射生成的信息如何收集的

接着就是如何收集这些metadata:前文略过了着部分内容,这里说个大概,metadata是存储在UPackage中的,在构造UClass的最后调用了AddMetaData,因为前面其UPackage已经创建了好了,这里就往里面填充metadata就可以了

class COREUOBJECT_API UMetaData : public UObject
{
public:
    TMap< FWeakObjectPtr, TMap<FName, FString> > ObjectMetaDataMap;//对象关联的键值对
    TMap< FName, FString > RootMetaDataMap;//包本身的键值对
};

const FString& UField::GetMetaData(const FName& Key) const
{
    UPackage* Package = GetOutermost();
    UMetaData* MetaData = Package->GetMetaData();
    const FString& MetaDataString = MetaData->GetValue(this, Key);
    return MetaDataString;
}
image-20250615203043237

image-20250615202028661

image-20250615202053606

下面是MetaData的序列化的一个例子,和分析Object初始化流程的用到的例子一样,都是S_Actor这个SpriteTexture的反序列化

我们可以看到MetaData就是跟着Package存储的,这样虽然使用起来麻烦,但是肯定是比存储在UObject上好的,因为他是非Game Runtime的结构,只用于Editor

 	UnrealEditor-CoreUObject.dll!UStruct::SerializeVersionedTaggedProperties(FStructuredArchiveSlot Slot, unsigned char * Data, UStruct * DefaultsStruct, unsigned char * Defaults, const UObject * BreakRecursionIfFullyLoad) 行 1440	C++
 	UnrealEditor-CoreUObject.dll!UStruct::SerializeTaggedProperties(FStructuredArchiveSlot Slot, unsigned char * Data, UStruct * DefaultsStruct, unsigned char * Defaults, const UObject * BreakRecursionIfFullyLoad) 行 1334	C++
 	UnrealEditor-CoreUObject.dll!UObject::SerializeScriptProperties(FStructuredArchiveSlot Slot) 行 1880	C++
 	UnrealEditor-CoreUObject.dll!UObject::Serialize(FStructuredArchiveRecord Record) 行 1661	C++
 	UnrealEditor-CoreUObject.dll!UMetaData::Serialize(FStructuredArchiveRecord Record) 行 124	C++
 	UnrealEditor-CoreUObject.dll!UMetaData::Serialize(FArchive & Ar) 行 116	C++
 	UnrealEditor-CoreUObject.dll!FLinkerLoad::Preload(UObject * Object) 行 4761	C++
>	UnrealEditor-CoreUObject.dll!EndLoad(FUObjectSerializeContext * LoadContext, TArray<UPackage *,TSizedDefaultAllocator<32>> * OutLoadedPackages) 行 2199	C++
 	UnrealEditor-CoreUObject.dll!LoadPackageInternal::__l110::<lambda_2>::operator()() 行 1810	C++
 	UnrealEditor-CoreUObject.dll!LoadPackageInternal(UPackage * InOuter, const FPackagePath & PackagePath, unsigned int LoadFlags, FLinkerLoad * ImportLinker, FArchive * InReaderOverride, const FLinkerInstancingContext * InstancingContext, const FPackagePath * DiffPackagePath) 行 1912	C++
 	UnrealEditor-CoreUObject.dll!LoadPackage(UPackage * InOuter, const FPackagePath & PackagePath, unsigned int LoadFlags, FArchive * InReaderOverride, const FLinkerInstancingContext * InstancingContext, const FPackagePath * DiffPackagePath) 行 2068	C++
 	UnrealEditor-CoreUObject.dll!LoadPackage(UPackage * InOuter, const wchar_t * InLongPackageNameOrFilename, unsigned int LoadFlags, FArchive * InReaderOverride, const FLinkerInstancingContext * InstancingContext) 行 2044	C++
 	UnrealEditor-CoreUObject.dll!ResolveName(UObject * & InPackage, FString & InOutName, bool Create, bool Throw, unsigned int LoadFlags, const FLinkerInstancingContext * InstancingContext) 行 1246	C++
 	UnrealEditor-CoreUObject.dll!StaticLoadObjectInternal(UClass * ObjectClass, UObject * InOuter, const wchar_t * InName, const wchar_t * Filename, unsigned int LoadFlags, UPackageMap * Sandbox, bool bAllowObjectReconciliation, const FLinkerInstancingContext * InstancingContext) 行 1356	C++
 	UnrealEditor-CoreUObject.dll!StaticLoadObject(UClass * ObjectClass, UObject * InOuter, const wchar_t * InName, const wchar_t * Filename, unsigned int LoadFlags, UPackageMap * Sandbox, bool bAllowObjectReconciliation, const FLinkerInstancingContext * InstancingContext) 行 1430	C++
 	[内联框架] UnrealEditor-Engine.dll!LoadObject(UObject *) 行 1959	C++
 	UnrealEditor-Engine.dll!ConstructorHelpersInternal::FindOrLoadObject<UTexture2D>(FString & PathName, unsigned int LoadFlags) 行 39	C++
 	[内联框架] UnrealEditor-Engine.dll!ConstructorHelpers::FObjectFinder<UTexture2D>::{ctor}(const wchar_t *) 行 90	C++
 	[内联框架] UnrealEditor-Engine.dll!UBillboardComponent::{ctor}::__l2::FConstructorStatics::{ctor}() 行 266	C++
 	UnrealEditor-Engine.dll!UBillboardComponent::UBillboardComponent(const FObjectInitializer & ObjectInitializer) 行 273	C++
 	UnrealEditor-CoreUObject.dll!UClass::CreateDefaultObject() 行 4586	C++
 	UnrealEditor-CoreUObject.dll!UClass::InternalCreateDefaultObjectWrapper() 行 5190	C++
 	[内联框架] UnrealEditor-CoreUObject.dll!UClass::GetDefaultObject(bool) 行 3239	C++
 	UnrealEditor-CoreUObject.dll!FObjectInitializer::CreateDefaultSubobject(UObject * Outer, FName SubobjectFName, const UClass * ReturnType, const UClass * ClassToCreateByDefault, bool bIsRequired, bool bIsTransient) 行 5427	C++
 	UnrealEditor-CoreUObject.dll!FObjectInitializer::CreateEditorOnlyDefaultSubobject(UObject * Outer, FName SubobjectName, const UClass * ReturnType, bool bTransient) 行 5495	C++
 	UnrealEditor-CoreUObject.dll!UObject::CreateEditorOnlyDefaultSubobjectImpl(FName SubobjectName, UClass * ReturnType, bool bTransient) 行 171	C++
 	[内联框架] UnrealEditor-Engine.dll!UObject::CreateEditorOnlyDefaultSubobject(FName) 行 134	C++
 	UnrealEditor-Engine.dll!AReflectionCapture::AReflectionCapture(const FObjectInitializer & ObjectInitializer) 行 154	C++
 	UnrealEditor-CoreUObject.dll!UClass::CreateDefaultObject() 行 4586	C++
 	UnrealEditor-CoreUObject.dll!UClass::InternalCreateDefaultObjectWrapper() 行 5190	C++
 	[内联框架] UnrealEditor-CoreUObject.dll!UClass::GetDefaultObject(bool) 行 3239	C++
 	UnrealEditor-CoreUObject.dll!UClass::CreateDefaultObject() 行 4529	C++
 	UnrealEditor-CoreUObject.dll!UClass::InternalCreateDefaultObjectWrapper() 行 5190	C++
 	[内联框架] UnrealEditor-CoreUObject.dll!UClass::GetDefaultObject(bool) 行 3239	C++
 	UnrealEditor-CoreUObject.dll!UObjectLoadAllCompiledInDefaultProperties(TArray<UClass *,TSizedDefaultAllocator<32>> & OutAllNewClasses) 行 800	C++
 	UnrealEditor-CoreUObject.dll!ProcessNewlyLoadedUObjects(FName Package, bool bCanProcessNewlyLoadedObjects) 行 894	C++
 	UnrealEditor.exe!FEngineLoop::PreInitPostStartupScreen(const wchar_t * CmdLine) 行 3803	C++
 	[内联框架] UnrealEditor.exe!FEngineLoop::PreInit(const wchar_t *) 行 4483	C++
 	[内联框架] UnrealEditor.exe!EnginePreInit(const wchar_t *) 行 41	C++
 	UnrealEditor.exe!GuardedMain(const wchar_t * CmdLine) 行 136	C++
 	UnrealEditor.exe!LaunchWindowsStartup(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * __formal, int nCmdShow, const wchar_t * CmdLine) 行 247	C++
 	UnrealEditor.exe!WinMain(HINSTANCE__ * hInInstance, HINSTANCE__ * hPrevInstance, char * pCmdLine, int nCmdShow) 行 298	C++
 	[内联框架] UnrealEditor.exe!invoke_main() 行 102	C++
 	UnrealEditor.exe!__scrt_common_main_seh() 行 288	C++
 	kernel32.dll!00007ff8aa3d7374()	未知
 	ntdll.dll!00007ff8abedcc91()	未知

void UMetaData::Serialize(FStructuredArchive::FRecord Record)
{
	FArchive& UnderlyingArchive = Record.GetUnderlyingArchive();

	Super::Serialize(Record);

	UnderlyingArchive.UsingCustomVersion(FEditorObjectVersion::GUID);

	if( UnderlyingArchive.IsSaving() )
	{
		// Remove entries belonging to destructed objects
		for (TMap< FWeakObjectPtr, TMap<FName, FString> >::TIterator It(ObjectMetaDataMap); It; ++It)
		{
			if (!It.Key().IsValid())
			{
				It.RemoveCurrent();
			}
		}
	}
	
	if (!UnderlyingArchive.IsLoading())
	{
		Record << SA_VALUE(TEXT("ObjectMetaDataMap"), ObjectMetaDataMap);
		Record << SA_VALUE(TEXT("RootMetaDataMap"), RootMetaDataMap);
	}
	else
	{
		{
			TMap< FWeakObjectPtr, TMap<FName, FString> > TempMap;
			Record << SA_VALUE(TEXT("ObjectMetaDataMap"), TempMap);

			const bool bLoadFromLinker = (NULL != UnderlyingArchive.GetLinker());
			if (bLoadFromLinker && HasAnyFlags(RF_LoadCompleted))
			{
				UE_LOG(LogMetaData, Verbose, TEXT("Metadata was already loaded by linker. %s"), *GetFullName());
			}
			else
			{
				if (bLoadFromLinker && ObjectMetaDataMap.Num())
				{
					UE_LOG(LogMetaData, Verbose, TEXT("Metadata: Some values, filled while serialization, may be lost. %s"), *GetFullName());
				}
				Swap(ObjectMetaDataMap, TempMap);
			}
		}

		if (UnderlyingArchive.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::RootMetaDataSupport)
		{
			TMap<FName, FString> TempMap;
			Record << SA_VALUE(TEXT("RootMetaDataMap"), TempMap);

			const bool bLoadFromLinker = (NULL != UnderlyingArchive.GetLinker());
			if (bLoadFromLinker && HasAnyFlags(RF_LoadCompleted))
			{
				UE_LOG(LogMetaData, Verbose, TEXT("Root metadata was already loaded by linker. %s"), *GetFullName());
			}
			else
			{
				if (bLoadFromLinker && RootMetaDataMap.Num())
				{
					UE_LOG(LogMetaData, Verbose, TEXT("Metadata: Some root values, filled while serialization, may be lost. %s"), *GetFullName());
				}
				Swap(RootMetaDataMap, TempMap);
			}
		}

		// Run redirects on loaded keys
		InitializeRedirectMap();

		for (TMap< FWeakObjectPtr, TMap<FName, FString> >::TIterator ObjectIt(ObjectMetaDataMap); ObjectIt; ++ObjectIt)
		{
			TMap<FName, FString>& CurrentMap = ObjectIt.Value();
			for (TMap<FName, FString>::TIterator PairIt(CurrentMap); PairIt; ++PairIt)
			{
				const FName OldKey = PairIt.Key();
				const FName NewKey = KeyRedirectMap.FindRef(OldKey);
				if (NewKey != NAME_None)
				{
					const FString Value = PairIt.Value();

					PairIt.RemoveCurrent();
					CurrentMap.Add(NewKey, Value);

					UE_LOG(LogMetaData, Verbose, TEXT("Remapping old metadata key '%s' to new key '%s' on object '%s'."), *OldKey.ToString(), *NewKey.ToString(), *ObjectIt.Key().Get()->GetPathName());
				}
			}
		}

		for (TMap<FName, FString>::TIterator PairIt(RootMetaDataMap); PairIt; ++PairIt)
		{
			const FName OldKey = PairIt.Key();
			const FName NewKey = KeyRedirectMap.FindRef(OldKey);
			if (NewKey != NAME_None)
			{
				const FString Value = PairIt.Value();

				PairIt.RemoveCurrent();
				RootMetaDataMap.Add(NewKey, Value);

				UE_LOG(LogMetaData, Verbose, TEXT("Remapping old metadata key '%s' to new key '%s' on root."), *OldKey.ToString(), *NewKey.ToString());
			}
		}
	}

#if 0 && WITH_EDITOR
	FMetaDataUtilities::DumpMetaData(this);
#endif
}

CoreUObject系统的初始化

上面的整个分析流程,都是其他模块(DLL)中的反射信息(UClass、UScriptStruct)的构建流程,但是CoreUObject这个模块,作为一切的基础,比如说GUObjectAllocator,这个是UObject分配内存的来源,所有UObject构造的过程中,一定会用到GUObjectAllocator分配内存,甚至包括UClass。

我们可以看出来,在引擎初始化的阶段的PreInitPreStartupScreen,我们会先加载CoreUObjectModule,在这个module的StartupModule中,会调用一次UClassRegisterAllCompiledInClasses,接着他会将initUObject加入到Appinit中,接着在CoreUObjectModule后面就会调用这个initUObject,initUObject里面会完成对GUObjectAllocator和GUObjectArray中的内存池进行初始化,接着标记UObject系统初始化完毕,然后调用UObjectProcessRegistrants

对CoreUobject这个模块初始化的过程,我们可以看到,他用的方法和其他模块的是一样的,都是UClassRegisterAllCompiledInClasses对静态收集的信息进行收集到一个地方,并完成初步的UClass的构造,然后在UObjectProcessRegistrants中完成对CLassPrivate和OuterPrivate的赋值,然后放入全局的GUObjectArray和GUObjectHashtables中。

这里的分步骤的意义在于,第一步的时候,我们还不能正确构造UObject(因为还没有调用initUObject),而UPackage是UObject,所以这些UClass的Outer都没法赋值,而且

image-20250807195846319

image-20250807195904564

image-20250807195509921

image-20250807195832076

image-20250807200214378

// Note initialized.
Internal::GetUObjectSubsystemInitialised() = true;

UObjectProcessRegistrants();

Flags

还有一个东西是有点略过的,就是各种Flags的枚举。UE利用这些枚举标志来判断对象的状态和特征。 重要的有:

  • EObjectFlags:对象本身的标志。
  • EInternalObjectFlags:对象存储的标志,GC的时候用来检查可达性。
  • EObjectMark:用来额外标记对象特征的标志,用在序列化过程中标识状态。
  • EClassFlags:类的标志,定义了一个类的特征。
  • EClassCastFlags:类之间的转换,可以快速的测试一个类是否可以转换成某种类型。
  • EStructFlags:结构的特征标志。
  • EFunctionFlags:函数的特征标志。
  • EPropertyFlags:属性的特征标志。

具体的请读者们自己去查看定义了,太多了就不一一解释了。这也是一种常用的C++惯用法,枚举标志来表示叠加的特征。

作者:大钊
链接:https://zhuanlan.zhihu.com/p/60291730
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

实验性功能:

SparseClassData 稀疏类数据: 是一个UClass的一个实验性新功能,如果一些属性不会在实例化后更改,比如他是一个ReadOnly的,那么就可以放在这里,类似一个运行时的常量,可以做类似字符串的短字符串优化(所有类实例共用一个这些数据的实例),这样就可以减少内存的使用

References:InsideUE4UE4中的反射之一:编译阶段UE5 UObject类型系统和反射

Yuerer的UE5反射代码生成与注册凌泽的UOBJECT系列李嘉图的UE5反射UECOREDOCUMENTATION-github

posted @ 2025-08-11 14:53  orance03  阅读(61)  评论(0)    收藏  举报