美文网首页
UE4对象系统_UObject&UClass

UE4对象系统_UObject&UClass

作者: 蛋求疼 | 来源:发表于2017-08-21 15:19 被阅读0次

    UObject

    UObject为对象系统的基类。类层次为:

    UObjectBase
         UObjectBaseUtility
              UObject
    

    UObjectBase和UObjectBaseUtility为辅助类,所有对象需要从UObject继承。

    • UObjectBase类
    class COREUOBJECT_API UObjectBase
    {
        friend class UObjectBaseUtility;
        friend COREUOBJECT_API class UClass* Z_Construct_UClass_UObject();
        friend class FUObjectArray; // for access to InternalIndex without revealing it to anyone else
        friend class FUObjectAllocator; // for access to destructor without revealing it to anyone else
        friend COREUOBJECT_API void UObjectForceRegistration(UObjectBase* Object);
        friend COREUOBJECT_API void InitializePrivateStaticClass(
            class UClass* TClass_Super_StaticClass,
            class UClass* TClass_PrivateStaticClass,
            class UClass* TClass_WithinClass_StaticClass,
            const TCHAR* PackageName,
            const TCHAR* Name
            );
    protected:
        UObjectBase() :
             NamePrivate(NoInit)  // screwy, but the name was already set and we don't want to set it again
        {
        }
        /**
         * Constructor used for bootstrapping
         * @param   InFlags         RF_Flags to assign
         */
        UObjectBase( EObjectFlags InFlags );
    public:
        /**
         * Constructor used by StaticAllocateObject
         * @param   InClass             non NULL, this gives the class of the new object, if known at this time
         * @param   InFlags             RF_Flags to assign
         * @param   InInternalFlags EInternalObjectFlags to assign
         * @param   InOuter             outer for this object
         * @param   InName              name of the new object
         */
        UObjectBase( UClass* InClass, EObjectFlags InFlags, EInternalObjectFlags InInternalFlags, UObject *InOuter, FName InName );
    
        /**
         * Final destructor, removes the object from the object array, and indirectly, from any annotations
         **/
        virtual ~UObjectBase();
    
        /**
         * Emit GC tokens for UObjectBase, this might be UObject::StaticClass or Default__Class
         **/
        static void EmitBaseReferences(UClass *RootClass);
    
    protected:
        /**
         * Just change the FName and Outer and rehash into name hash tables. For use by higher level rename functions.
         *
         * @param NewName   new name for this object
         * @param NewOuter  new outer for this object, if NULL, outer will be unchanged
         */
        void LowLevelRename(FName NewName,UObject *NewOuter = NULL);
    
        /** Force any base classes to be registered first */
        virtual void RegisterDependencies() {}
    
        /** Enqueue the registration for this object. */
        void Register(const TCHAR* PackageName,const TCHAR* Name);
        
        /**
         * Convert a boot-strap registered class into a real one, add to uobject array, etc
         *
         * @param UClassStaticClass Now that it is known, fill in UClass::StaticClass() as the class
         */
        virtual void DeferredRegister(UClass *UClassStaticClass,const TCHAR* PackageName,const TCHAR* Name);
    
    private:
        /**
         * Add a newly created object to the name hash tables and the object array
         *
         * @param Name name to assign to this uobject
         * @param InSetInternalFlags Internal object flags to be set on the object once it's been added to the array
         */
        void AddObject(FName Name, EInternalObjectFlags InSetInternalFlags);
    public:
        /**
         * Checks to see if the object appears to be valid
         * @return true if this appears to be a valid object
         */
        bool IsValidLowLevel() const;
    
        /**
         * Faster version of IsValidLowLevel.
         * Checks to see if the object appears to be valid by checking pointers and their alignment.
         * Name and InternalIndex checks are less accurate than IsValidLowLevel.
         * @param bRecursive true if the Class pointer should be checked with IsValidLowLevelFast
         * @return true if this appears to be a valid object
         */
        bool IsValidLowLevelFast(bool bRecursive = true) const;
    
        /** 
         * Returns the unique ID of the object...these are reused so it is only unique while the object is alive.
         * Useful as a tag.
        **/
        FORCEINLINE uint32 GetUniqueID() const
        {
            return (uint32)InternalIndex;
        }
        FORCEINLINE UClass* GetClass() const  // 获取该对象所属的类
        {
            return ClassPrivate;
        }
        FORCEINLINE UObject* GetOuter() const // 获取对象的Outer
        {
            return OuterPrivate;
        }
        FORCEINLINE FName GetFName() const
        {
            return NamePrivate;
        }
    
    protected:
        /**
         * Set the object flags directly
         *
         **/
        FORCEINLINE void SetFlagsTo( EObjectFlags NewFlags )
        {
            checkfSlow((NewFlags & ~RF_AllFlags) == 0, TEXT("%s flagged as 0x%x but is trying to set flags to RF_AllFlags"), *GetFName().ToString(), (int)ObjectFlags);
            ObjectFlags = NewFlags;
        }
    public:
        /**
         * Retrieve the object flags directly
         *
         * @return Flags for this object
         **/
        FORCEINLINE EObjectFlags GetFlags() const
        {
            checkfSlow((ObjectFlags & ~RF_AllFlags) == 0, TEXT("%s flagged as RF_AllFlags"), *GetFName().ToString());
            return ObjectFlags;
        }
    
        /**
         *  Atomically adds the specified flags.
         *  Do not use unless you know what you are doing.
         *  Designed to be used only by parallel GC and UObject loading thread.
         */
        FORCENOINLINE void AtomicallySetFlags( EObjectFlags FlagsToAdd )
        {
            int32 OldFlags = 0;
            int32 NewFlags = 0;
            do 
            {
                OldFlags = ObjectFlags;
                NewFlags = OldFlags | FlagsToAdd;
            }
            while( FPlatformAtomics::InterlockedCompareExchange( (int32*)&ObjectFlags, NewFlags, OldFlags) != OldFlags );
        }
    
        /**
         *  Atomically clears the specified flags.
         *  Do not use unless you know what you are doing.
         *  Designed to be used only by parallel GC and UObject loading thread.
         */
        FORCENOINLINE void AtomicallyClearFlags( EObjectFlags FlagsToClear )
        {
            int32 OldFlags = 0;
            int32 NewFlags = 0;
            do 
            {
                OldFlags = ObjectFlags;
                NewFlags = OldFlags & ~FlagsToClear;
            }
            while( FPlatformAtomics::InterlockedCompareExchange( (int32*)&ObjectFlags, NewFlags, OldFlags) != OldFlags );
        }
    
    private:
    
        /** Flags used to track and report various object states. This needs to be 8 byte aligned on 32-bit
            platforms to reduce memory waste 对象标记*/
        EObjectFlags                    ObjectFlags;
    
        /** Index into GObjectArray...very private.  全局对象数组中的索引*/
        int32                               InternalIndex;
    
        /** Class the object belongs to. */
        UClass*                         ClassPrivate;
    
        /** Name of this object */
        FName                           NamePrivate;
    
        /** Object this object resides in. */
        UObject*                        OuterPrivate;
    
        // This is used by the reinstancer to re-class and re-archetype the current instances of a class before recompiling
        friend class FBlueprintCompileReinstancer;
        void SetClass(UClass* NewClass);
    
    #if HACK_HEADER_GENERATOR
        // Required by UHT makefiles for internal data serialization.
        friend struct FObjectBaseArchiveProxy;
    #endif // HACK_HEADER_GENERATOR
    };
    

    该类主要作用是存放对象的名字、标记信息(ObjectFlags)、类型信息(ClassPrivate)、Outer对象和在对象管理数组中的索引。EInternalObjectFlags标记存放在全局对象管理数组的元素中(这是为了提高Cache命中率)。
    对象标记(ObjectFlags)很重要,它被引擎用于表示对象加载、保存、编辑、垃圾回收和对象作用标识时使用,我们需要了解这边标记的意义。

    /** 
     * Flags describing an object instance
     */
    enum EObjectFlags
    {
        // Do not add new flags unless they truly belong here. There are alternatives.
        // if you change any the bit of any of the RF_Load flags, then you will need legacy serialization
        RF_NoFlags                      = 0x00000000,   ///< No flags, used to avoid a cast
    
        // This first group of flags mostly has to do with what kind of object it is. Other than transient, these are the persistent object flags.
        // The garbage collector also tends to look at these.
        RF_Public                   =0x00000001,    ///< Object is visible outside its package.对象可以被其它包中对象引用
        RF_Standalone               =0x00000002,    ///< Keep object around for editing even if unreferenced. 在编辑器中,该对象即便没有被引用也不会被GC掉
        RF_MarkAsNative                 =0x00000004,    ///< Object (UField) will be marked as native on construction (DO NOT USE THIS FLAG in HasAnyFlags() etc)
        RF_Transactional            =0x00000008,    ///< Object is transactional.
        RF_ClassDefaultObject       =0x00000010,    ///< This object is its class's default object 每个类都有一个DefaultObject
        RF_ArchetypeObject          =0x00000020,    ///< This object is a template for another object - treat like a class default object  该对象作为模板,其它对象可克隆它
        RF_Transient                =0x00000040,    ///< Don't save object.  临时对象,不会被序列化
    
        // This group of flags is primarily concerned with garbage collection.
        RF_MarkAsRootSet                    =0x00000080,    ///< Object will be marked as root set on construction and not be garbage collected, even if unreferenced (DO NOT USE THIS FLAG in HasAnyFlags() etc)
        RF_TagGarbageTemp           =0x00000100,    ///< This is a temp user flag for various utilities that need to use the garbage collector. The garbage collector itself does not interpret it.
    
        // The group of flags tracks the stages of the lifetime of a uobject
        RF_NeedInitialization       =0x00000200,    ///< This object has not completed its initialization process. Cleared when ~FObjectInitializer completes
        RF_NeedLoad                 =0x00000400,    ///< During load, indicates object needs loading.
        RF_KeepForCooker            =0x00000800,    ///< Keep this object during garbage collection because it's still being used by the cooker
        RF_NeedPostLoad             =0x00001000,    ///< Object needs to be postloaded.
        RF_NeedPostLoadSubobjects   =0x00002000,    ///< During load, indicates that the object still needs to instance subobjects and fixup serialized component references
        RF_NewerVersionExists       =0x00004000,    ///< Object has been consigned to oblivion due to its owner package being reloaded, and a newer version currently exists
        RF_BeginDestroyed           =0x00008000,    ///< BeginDestroy has been called on the object.
        RF_FinishDestroyed          =0x00010000,    ///< FinishDestroy has been called on the object.
    
        // Misc. Flags
        RF_BeingRegenerated         =0x00020000,    ///< Flagged on UObjects that are used to create UClasses (e.g. Blueprints) while they are regenerating their UClass on load (See FLinkerLoad::CreateExport())
        RF_DefaultSubObject         =0x00040000,    ///< Flagged on subobjects that are defaults
        RF_WasLoaded                =0x00080000,    ///< Flagged on UObjects that were loaded
        RF_TextExportTransient      =0x00100000,    ///< Do not export object to text form (e.g. copy/paste). Generally used for sub-objects that can be regenerated from data in their parent object.
        RF_LoadCompleted            =0x00200000,    ///< Object has been completely serialized by linkerload at least once. DO NOT USE THIS FLAG, It should be replaced with RF_WasLoaded.
        RF_InheritableComponentTemplate = 0x00400000, ///< Archetype of the object can be in its super class
        RF_DuplicateTransient = 0x00800000, ///< Object should not be included in any type of duplication (copy/paste, binary duplication, etc.)
        RF_StrongRefOnFrame         = 0x01000000,   ///< References to this object from persistent function frame are handled as strong ones.
        RF_NonPIEDuplicateTransient     = 0x02000000,  ///< Object should not be included for duplication unless it's being duplicated for a PIE session
        RF_Dynamic = 0x04000000, // Field Only. Dynamic field - doesn't get constructed during static initialization, can be constructed multiple times
    };
    
        // Special all and none masks
    #define RF_AllFlags             (EObjectFlags)0x07ffffff    ///< All flags, used mainly for error checking
    
        // Predefined groups of the above
    #define RF_Load                     ((EObjectFlags)(RF_Public | RF_Standalone | RF_Transactional | RF_ClassDefaultObject | RF_ArchetypeObject | RF_DefaultSubObject | RF_TextExportTransient | RF_InheritableComponentTemplate | RF_DuplicateTransient | RF_NonPIEDuplicateTransient)) // Flags to load from Unrealfiles.
    #define RF_PropagateToSubObjects    ((EObjectFlags)(RF_Public | RF_ArchetypeObject | RF_Transactional | RF_Transient))      // Sub-objects will inherit these flags from their SuperObject.
    
    /** Objects flags for internal use (GC, low level UObject code) */
    enum class EInternalObjectFlags : int32
    {
        None = 0,
        // All the other bits are reserved, DO NOT ADD NEW FLAGS HERE!
        ReachableInCluster = 1 << 23, /// External reference to object in cluster exists
        ClusterRoot = 1 << 24, ///< Root of a cluster
        Native = 1 << 25, ///< Native (UClass only).
        Async = 1 << 26, ///< Object exists only on a different thread than the game thread.
        AsyncLoading = 1 << 27, ///< Object is being asynchronously loaded.
        Unreachable = 1 << 28, ///< Object is not reachable on the object graph.
        PendingKill = 1 << 29, ///< Objects that are pending destruction (invalid for gameplay but valid objects)
        RootSet = 1 << 30, ///< Object will not be garbage collected, even if unreferenced.
        NoStrongReference = 1 << 31, ///< The object is not referenced by any strong reference. The flag is used by GC.
    
        GarbageCollectionKeepFlags = Native | Async | AsyncLoading,
        // Make sure this is up to date!
        AllFlags = ReachableInCluster | ClusterRoot | Native | Async | AsyncLoading | Unreachable | PendingKill | RootSet | NoStrongReference
    };
    ENUM_CLASS_FLAGS(EInternalObjectFlags);
    
    • UObjectBaseUtility类
      提供一些辅助函数: Flag设置和查询、Mark设置与查询、Class查询、名字查询、Linker信息(Linker为uasset加载器)。下面摘抄部分代码。
    class COREUOBJECT_API UObjectBaseUtility : public UObjectBase
    {
    public:
        /***********************/
        /******** Flags ********/
        /***********************/
    
        /***********************/
        /******** Marks *******  UObjectMarks.cpp */
        /***********************/
    
        /***********************/
        /******** Names ********/
        /***********************/
    
        /**
         * Returns the fully qualified pathname for this object as well as the name of the class, in the format:
         * 'ClassName Outermost[.Outer].Name'.
         *
         * @param   StopOuter   if specified, indicates that the output string should be relative to this object.  if StopOuter
         *                      does not exist in this object's Outer chain, the result would be the same as passing NULL.
         *
         * @note    safe to call on NULL object pointers!
         */
        FString GetFullName( const UObject* StopOuter=NULL ) const;
    
        /**
         * Returns the fully qualified pathname for this object, in the format:
         * 'Outermost[.Outer].Name'
         *
         * @param   StopOuter   if specified, indicates that the output string should be relative to this object.  if StopOuter
         *                      does not exist in this object's Outer chain, the result would be the same as passing NULL.
         *
         * @note    safe to call on NULL object pointers!
         */
        FString GetPathName( const UObject* StopOuter=NULL ) const;
    
    public:
        /**
         * Walks up the chain of packages until it reaches the top level, which it ignores.
         *
         * @param   bStartWithOuter     whether to include this object's name in the returned string
         * @return  string containing the path name for this object, minus the outermost-package's name
         */
        FString GetFullGroupName( bool bStartWithOuter ) const;
    
        /**
         * Returns the name of this object (with no path information)
         * 
         * @return Name of the object.
         */
        FORCEINLINE FString GetName() const
        {
            return GetFName().ToString();
        }
    
        /***********************/
        /******** Outer ********/
        /***********************/
    
        /** 
         * Walks up the list of outers until it finds the highest one.
         *
         * @return outermost non NULL Outer.   所有对象必须在某个包中(Package),UPackage对象除外。
         */
        UPackage* GetOutermost() const;
    
        /** 
         * Finds the outermost package and marks it dirty. 
         * The editor suppresses this behavior during load as it is against policy to dirty packages simply by loading them.
         *
         * @return false if the request to mark the package dirty was suppressed by the editor and true otherwise.
         */
        bool MarkPackageDirty() const;
    
        /***********************/
        /******** Class ********/
        /***********************/
    
        /***********************/
        /******** Linker ****  UObjectLinker.cpp */
        /***********************/
    
        /**
         * Returns the linker for this object.
         *
         * @return  a pointer to the linker for this object, or NULL if this object has no linker
         */
        class FLinkerLoad* GetLinker() const;
        /**
         * Returns this object's LinkerIndex.
         *
         * @return  the index into my linker's ExportMap for the FObjectExport
         *          corresponding to this object.
         */
        int32 GetLinkerIndex() const;
    };
    
    • UObject类
      提供如下功能:
      • 创建子对象(SubObject)
      • 构函数之后的调用
      • 对象Destroy相关事件处理
      • 对象编辑相关事件处理
      • 序列化
      • 执行脚本
      • 从config文件读取或保存成员变量配置.
        该类接口较多,请参考源文件Engine\Source\Runtime\CoreUObject\Public\UObject\Object.h

    UClass

    C++语言不像C#,Java那样提供完整的反射功能,我们需要定义一个数据结构(UClass)来描述C++中的类信息,这个数据结构也称为类的元数据。当然在UE4中UClass实例不仅仅用于描述C++(Native)类,也用来描述Blueprint生成的类。
    源码路径Engine\Source\Runtime\CoreUObject\Public\UObject\Class.h
    类继承层次:

    UObject
       UField
          UEnum
          UProperty
             UBoolProperty
             UEnumProperty
             UNumericProperty
             UObjectProperty
             ... 
          UStruct
             UClass
             UFunction
             UScriptStruct   
    

    这块类的命名很有意思, 为什么叫UField呢参考Field In Java,类的成员变量、函数参数称为Field可以理解,但是UEunm, UStruct,UClass,UFunction也称为Field就有点不直观了,我估计是Enum,Struct,Class也是可以在类体中进行定义的原因。UFunction从UStruct继承也是有道理的,因为Function里有局部变量和参数这些Field。

    • UStruct类
    /**
     * Base class for all UObject types that contain fields.
     */
    class COREUOBJECT_API UStruct : public UField
    {
        DECLARE_CASTED_CLASS_INTRINSIC(UStruct, UField, 0, TEXT("/Script/CoreUObject"), CASTCLASS_UStruct)
    
        // Variables.
    protected:
        friend COREUOBJECT_API UClass* Z_Construct_UClass_UStruct();
    private:
        UStruct* SuperStruct;   // 父类, UE4对象系统只允许单继承关系
    public:
        UField* Children;          // 拥有的成员变量和Function等其它Filed
        int32 PropertiesSize;    // 对象占用的内存大小
    
        int32 MinAlignment;      // 内存地址对齐要求
        
        TArray<uint8> Script;    // 脚本字节码,  UE4脚本是面向对象的脚本系统。 
    
        /** In memory only: Linked list of properties from most-derived to base **/
        UProperty* PropertyLink;   // 属性列表
        /** In memory only: Linked list of object reference properties from most-derived to base **/
        UProperty* RefLink;  // 对象引用的属性列表
        /** In memory only: Linked list of properties requiring destruction. Note this does not include things that will be destroyed byt he native destructor **/
        UProperty* DestructorLink;  // 需要析构的属性列表
        /** In memory only: Linked list of properties requiring post constructor initialization.**/
        UProperty* PostConstructLink;
    
        /** Array of object references embedded in script code. Mirrored for easy access by realtime garbage collection code */
        TArray<UObject*> ScriptObjectReferences;  // 脚本字节码中引用的对象列表
    
        /** Map of Class Name to Map of Old Property Name to New Property Name */
        static TMap<FName,TMap<FName,FName> > TaggedPropertyRedirects;
        static void InitTaggedPropertyRedirectsMap();
    
    public:
        // Constructors.
        UStruct( EStaticConstructor, int32 InSize, EObjectFlags InFlags );
        explicit UStruct(UStruct* InSuperStruct, SIZE_T ParamsSize = 0, SIZE_T Alignment = 0);
        explicit UStruct(const FObjectInitializer& ObjectInitializer, UStruct* InSuperStruct, SIZE_T ParamsSize = 0, SIZE_T Alignment = 0 );
    
        // UObject interface.
        virtual void Serialize(FArchive& Ar) override;
        virtual void FinishDestroy() override;
        virtual void RegisterDependencies() override;
        static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
        virtual void GetPreloadDependencies(TArray<UObject*>& OutDeps) override;
    
        // UField interface.
        virtual void AddCppProperty(UProperty* Property) override;
    
        UProperty* FindPropertyByName(FName InName) const;
    
        /**
         * Creates new copies of components
         * 
         * @param   Data                        pointer to the address of the subobject referenced by this UProperty
         * @param   DefaultData                 pointer to the address of the default value of the subbject referenced by this UProperty
         * @param   DefaultStruct               the struct corresponding to the buffer pointed to by DefaultData
         * @param   Owner                       the object that contains the component currently located at Data
         * @param   InstanceGraph               contains the mappings of instanced objects and components to their templates
         */
        void InstanceSubobjectTemplates( void* Data, void const* DefaultData, UStruct* DefaultStruct, UObject* Owner, FObjectInstancingGraph* InstanceGraph );
    
        //
        virtual UStruct* GetInheritanceSuper() const {return GetSuperStruct();}
    
        //
        void StaticLink(bool bRelinkExistingProperties = false);
    
        //
        virtual void Link(FArchive& Ar, bool bRelinkExistingProperties);
    
        virtual void SerializeBin( FArchive& Ar, void* Data ) const;
    
        /**
         * Serializes the class properties that reside in Data if they differ from the corresponding values in DefaultData
         *
         * @param   Ar              the archive to use for serialization
         * @param   Data            pointer to the location of the beginning of the property data
         * @param   DefaultData     pointer to the location of the beginning of the data that should be compared against
         * @param   DefaultStruct   the struct corresponding to the block of memory located at DefaultData 
         */
        void SerializeBinEx( FArchive& Ar, void* Data, void const* DefaultData, UStruct* DefaultStruct ) const;
    
        virtual void SerializeTaggedProperties( FArchive& Ar, uint8* Data, UStruct* DefaultsStruct, uint8* Defaults, const UObject* BreakRecursionIfFullyLoad=NULL) const;
    
        /**
         * Initialize a struct over uninitialized memory. This may be done by calling the native constructor or individually initializing properties
         *
         * @param   Dest        Pointer to memory to initialize
         * @param   ArrayDim    Number of elements in the array
         * @param   Stride      Stride of the array, If this default (0), then we will pull the size from the struct
         */
        virtual void InitializeStruct(void* Dest, int32 ArrayDim = 1) const;
        /**
         * Destroy a struct in memory. This may be done by calling the native destructor and then the constructor or individually reinitializing properties
         *
         * @param   Dest        Pointer to memory to destory
         * @param   ArrayDim    Number of elements in the array
         * @param   Stride      Stride of the array. If this default (0), then we will pull the size from the struct
         */
        virtual void DestroyStruct(void* Dest, int32 ArrayDim = 1) const;
    
    #if WITH_EDITOR
    public:
        virtual UProperty* CustomFindProperty(const FName InName) const { return NULL; };
    #endif // WITH_EDITOR
    public:
        virtual EExprToken SerializeExpr(int32& iCode, FArchive& Ar);
        virtual void TagSubobjects(EObjectFlags NewFlags) override;
    
        /**
         * Returns the struct/ class prefix used for the C++ declaration of this struct/ class.
         *
         * @return Prefix character used for C++ declaration of this struct/ class.
         */
        virtual const TCHAR* GetPrefixCPP() const { return TEXT("F"); }
    
        FORCEINLINE int32 GetPropertiesSize() const
        {
            return PropertiesSize;
        }
    
        FORCEINLINE int32 GetMinAlignment() const
        {
            return MinAlignment;
        }
    
        FORCEINLINE int32 GetStructureSize() const
        {
            return Align(PropertiesSize,MinAlignment);
        }
    
        void SetPropertiesSize( int32 NewSize )
        {
            PropertiesSize = NewSize;
        }
    
        template<class T>
        bool IsChildOf() const
        {
            return IsChildOf(T::StaticClass());
        }
    
        bool IsChildOf( const UStruct* SomeBase ) const
        {
            for (const UStruct* Struct = this; Struct; Struct = Struct->GetSuperStruct())
            {
                if (Struct == SomeBase)
                    return true;
            }
    
            return false;
        }
    
        UStruct* GetSuperStruct() const
        {
            return SuperStruct;
        }
    
        /**
         * Sets the super struct pointer and updates hash information as necessary.
         * Note that this is not sufficient to actually reparent a struct, it simply sets a pointer.
         */
        virtual void SetSuperStruct(UStruct* NewSuperStruct);
    
        /**
         * Serializes the SuperStruct pointer.
         */
        virtual void SerializeSuperStruct(FArchive& Ar);
    
        void LinkChild(UField* Child)
        {
            Child->Next = Children;
            Children = Child;
        }
    
        virtual FString PropertyNameToDisplayName(FName InName) const 
        { 
            return InName.ToString();
        }
    
    #if WITH_EDITOR
        /** Try and find boolean metadata with the given key. If not found on this class, work up hierarchy looking for it. */
        bool GetBoolMetaDataHierarchical(const FName& Key) const;
    
        /** Try and find string metadata with the given key. If not found on this class, work up hierarchy looking for it. */
        bool GetStringMetaDataHierarchical(const FName& Key, FString* OutValue = nullptr) const;
    
        /**
        * Determines if the struct or any of its super structs has any metadata associated with the provided key
        *
        * @param Key The key to lookup in the metadata
        * @return pointer to the UStruct that has associated metadata, nullptr if Key is not associated with any UStruct in the hierarchy
        */
        const UStruct* HasMetaDataHierarchical(const FName& Key) const;
    #endif
    
    #if HACK_HEADER_GENERATOR
        // Required by UHT makefiles for internal data serialization.
        friend struct FStructArchiveProxy;
    #endif // HACK_HEADER_GENERATOR
    
    protected:
    
        /** Returns the property name from the guid */
        virtual FName FindPropertyNameFromGuid(const FGuid& PropertyGuid) const { return NAME_None; }
    
        /** Find property guid */
        virtual FGuid FindPropertyGuidFromName(const FName InName) const { return FGuid(); }
    
        /** Returns if we have access to property guids */
        virtual bool ArePropertyGuidsAvailable() const { return false; }
    
    };
    
    • UClass类
      UClass实例描述了C++类和脚本类的反射信息,部分代码如下:
    /**
     * An object class.
     */
    class COREUOBJECT_API UClass : public UStruct
    #if UCLASS_FAST_ISA_IMPL == UCLASS_ISA_INDEXTREE
        , private FFastIndexingClassTreeRegistrar
    #elif UCLASS_FAST_ISA_IMPL == UCLASS_ISA_CLASSARRAY
        , private FClassBaseChain
    #endif
    {
        DECLARE_CASTED_CLASS_INTRINSIC_NO_CTOR(UClass, UStruct, 0, TEXT("/Script/CoreUObject"), CASTCLASS_UClass, NO_API)
        DECLARE_WITHIN(UPackage)
    
    public:
    
        typedef void        (*ClassConstructorType)             (const FObjectInitializer&);
    #if WITH_HOT_RELOAD_CTORS
        typedef UObject*    (*ClassVTableHelperCtorCallerType)  (FVTableHelper& Helper);
    #endif // WITH_HOT_RELOAD_CTORS
        typedef void        (*ClassAddReferencedObjectsType)    (UObject*, class FReferenceCollector&);
        typedef UClass* (*StaticClassFunctionType)();
    
        ClassConstructorType ClassConstructor;   // 所反射的类的构造函数
    #if WITH_HOT_RELOAD_CTORS
        ClassVTableHelperCtorCallerType ClassVTableHelperCtorCaller;
    #endif // WITH_HOT_RELOAD_CTORS
        /** Pointer to a static AddReferencedObjects method. */
        ClassAddReferencedObjectsType ClassAddReferencedObjects;  // 在GC时这个有用
    
        // Class pseudo-unique counter; used to accelerate unique instance name generation
        int32 ClassUnique;
    
        // Class flags; See EClassFlags for more information, 类的标记
        uint32 ClassFlags;  
    
        // Cast flags used to accelerate dynamic_cast<T*> on objects of this type for common T
        EClassCastFlags ClassCastFlags;
    
        // The required type for the outer of instances of this class. 该类型的实例的Outer必须是ClassWithin的类实例
        UClass* ClassWithin;
    
        // This is the blueprint that caused the generation of this class, or NULL if it is a native compiled-in class
        UObject* ClassGeneratedBy; // 该UClass实例是谁创建的,  注意: Blueprint是只是个资源(类似C++源文件), 编译出来的才是UClass实例。
    
    
        //
        FName ClassConfigName;
    
        // Used to check if the class was cooked or not.
        bool bCooked;
    
        // List of replication records, 网络replicated需要的信息
        TArray<FRepRecord> ClassReps;
    
        // List of network relevant fields (properties and functions) 需要网络replicated的域
        TArray<UField*> NetFields;   
    
        virtual bool IsNameStableForNetworking() const override { return true; }        // For now, assume all classes have stable net names
    
        /**
         * Calls AddReferencedObjects static method on the specified object.
         *
         * @param This Object to call ARO on.
         * @param Collector Reference collector.
         */
        FORCEINLINE void CallAddReferencedObjects(UObject* This, FReferenceCollector& Collector) const
        {
            // The object must of this class type.
            check(This->IsA(this)); 
            // This is should always be set to something, at the very least to UObject::ARO
            check(ClassAddReferencedObjects != NULL); 
            ClassAddReferencedObjects(This, Collector);
        }
    
        // The class default object; used for delta serialization and object initialization
        UObject* ClassDefaultObject;
    
        /**
        * Assemble reference token streams for all classes if they haven't had it assembled already. 每个类都会生成一个引用token流,这个给GC使用。
        */
        static void AssembleReferenceTokenStreams();
    
    private:
            // ==================== 函数相关信息 ======================
        /** Map of all functions by name contained in this class */
        TMap<FName, UFunction*> FuncMap;
    
        /** A cache of all functions by name that exist in a parent context */
        mutable TMap<FName, UFunction*> ParentFuncMap;
    
        /** A cache of all functions by name that exist in an interface context */
        mutable TMap<FName, UFunction*> InterfaceFuncMap;
    
    public:
        /**
         * The list of interfaces which this class implements, along with the pointer property that is located at the offset of the interface's vtable.
         * If the interface class isn't native, the property will be NULL.
         **/
        TArray<FImplementedInterface> Interfaces;
    
        /**
         * Prepends reference token stream with super class's stream.
         *
         * @param SuperClass Super class to prepend stream with.
         */
        void PrependStreamWithSuperClass(UClass& SuperClass);
    
        /** Reference token stream used by realtime garbage collector, finalized in AssembleReferenceTokenStream */
        FGCReferenceTokenStream ReferenceTokenStream;
        /** CS for the token stream. Token stream can assemble code can sometimes be called from two threads throuh a web of async loading calls. */
        FCriticalSection ReferenceTokenStreamCritical;
    
    #if !(UE_BUILD_TEST || UE_BUILD_SHIPPING)
        /* TokenIndex map to look-up token stream index origin. */
        FGCDebugReferenceTokenMap DebugTokenMap;
    #endif
    
        
    
        /** This class's native functions. */
        TArray<FNativeFunctionLookup> NativeFunctionLookupTable;
    
    public:
        /**
         * Add a native function to the internal native function table
         * @param   InName                          name of the function
         * @param   InPointer                       pointer to the function
         **/
        void AddNativeFunction(const ANSICHAR* InName, Native InPointer);
    
        /**
         * Add a native function to the internal native function table, but with a unicode name. Used when generating code from blueprints, 
         * which can have unicode identifiers for functions and properties.
         * @param   InName                          name of the function
         * @param   InPointer                       pointer to the function
         **/
        void AddNativeFunction(const WIDECHAR* InName, Native InPointer);
    
        // Add a function to the function map
        void AddFunctionToFunctionMap(UFunction* NewFunction)
        {
            FuncMap.Add(NewFunction->GetFName(), NewFunction);
        }
    
        // This is used by the code generator, which instantiates UFunctions with a name that is later overridden. Overridden names
        // are needed to support generated versions of blueprint classes, properties of which do not have the same naming 
        // restrictions as native C++ properties.
        void AddFunctionToFunctionMapWithOverriddenName(UFunction* NewFunction, FName OverriddenName)
        {
            FuncMap.Add(OverriddenName, NewFunction);
        }
    
        // Remove a function from the function map
        void RemoveFunctionFromFunctionMap(UFunction* Function)
        {
            FuncMap.Remove(Function->GetFName());
        }
    
        void ClearFunctionMapsCaches()
        {
            ParentFuncMap.Empty();
            InterfaceFuncMap.Empty();
        }
    
        UFunction* FindFunctionByName(FName InName, EIncludeSuperFlag::Type IncludeSuper = EIncludeSuperFlag::IncludeSuper) const;
    
        // UField interface.
        virtual void Bind() override;
        virtual const TCHAR* GetPrefixCPP() const override;
        // End of UField interface.
    
        // UStruct interface.
        virtual void Link(FArchive& Ar, bool bRelinkExistingProperties) override;
        virtual void SetSuperStruct(UStruct* NewSuperStruct) override;
        virtual void SerializeSuperStruct(FArchive& Ar) override;
        // End of UStruct interface.
        
        /**
         * Translates the hardcoded script config names (engine, editor, input and 
         * game) to their global pendants and otherwise uses config(myini) name to
         * look for a game specific implementation and creates one based on the
         * default if it doesn't exist yet.
         *
         * @return  name of the class specific ini file
         */
        const FString GetConfigName() const;
    
        UClass* GetSuperClass() const
        {
            return (UClass*)GetSuperStruct();
        }
    
        /** Feedback context for default property import **/
        static class FFeedbackContext& GetDefaultPropertiesFeedbackContext();
    
        int32 GetDefaultsCount()
        {
            return ClassDefaultObject != NULL ? GetPropertiesSize() : 0;
        }
    
        /**
          * Get the default object from the class,  每个类都有一个CDO
          * @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)
        {
            if (ClassDefaultObject == NULL && bCreateIfNeeded)
            {
                CreateDefaultObject();
            }
    
            return ClassDefaultObject;
        }
    
        /**
        * Get the name of the CDO for the this class
        * @return The name of the CDO
        */
        FName GetDefaultObjectName();
    
        /** Searches for the default instanced object (often a component) by name **/
        UObject* GetDefaultSubobjectByName(FName ToFind);
    
        /** Adds a new default instance map item **/
        void AddDefaultSubobject(UObject* NewSubobject, UClass* BaseClass)
        {
            // this compoonent must be a derived class of the base class
            check(NewSubobject->IsA(BaseClass));
            // the outer of the component must be of my class or some superclass of me
            check(IsChildOf(NewSubobject->GetOuter()->GetClass()));
        }
    
        /**
         * Gets all default instanced objects (often components).
         *
         * @param OutDefaultSubobjects An array to be filled with default subobjects.
         */
        void GetDefaultObjectSubobjects(TArray<UObject*>& OutDefaultSubobjects);
    
        /** 
         * Purges out the properties of this class in preparation for it to be regenerated
         * @param bRecompilingOnLoad - true if we are recompiling on load
         */
        virtual void PurgeClass(bool bRecompilingOnLoad);
    
        virtual UObject* FindArchetype(UClass* ArchetypeClass, const FName ArchetypeName) const { return nullptr; }
    
        // This signature intentionally hides the method declared in UObject to make it private.
        // Call FindFunctionByName instead; This method will search for a function declared in UClass instead of the class it was called on
        UFunction* FindFunction(FName InName) const
        {
            return UObject::FindFunction(InName);
        }
    };
    

    StaticClass()

    在Engine\Source\Runtime\CoreUObject\Public\UObject\ObjectMacros.h定义了DECLARE_CLASS, IMPLEMENT_CLASS等关于class的宏。

    /*-----------------------------------------------------------------------------
    Class declaration macros.
    -----------------------------------------------------------------------------*/
    
    #define DECLARE_CLASS( TClass, TSuperClass, TStaticFlags, TStaticCastFlags, TPackage, TRequiredAPI  ) \
    private: \
        TClass& operator=(TClass&&);   \
        TClass& operator=(const TClass&);   \
        TRequiredAPI static UClass* GetPrivateStaticClass(const TCHAR* Package); \
    public: \
        /** Bitwise union of #EClassFlags pertaining to this class.*/ \
        enum {StaticClassFlags=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(TPackage); \
        } \
        /** Returns the StaticClassFlags for this class */ \
        inline static EClassCastFlags StaticClassCastFlags() \
        { \
            return TStaticCastFlags; \
        } \
        DEPRECATED(4.7, "operator new has been deprecated for UObjects - please use NewObject or NewNamedObject instead") \
        inline void* operator new( const size_t InSize, 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 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; \
        }
    
    // Register a class at startup time.
    #define IMPLEMENT_CLASS(TClass, TClassCrc) \
        static TClassCompiledInDefer<TClass> AutoInitialize##TClass(TEXT(#TClass), sizeof(TClass), TClassCrc); \
           // 获取UClass实例
        UClass* TClass::GetPrivateStaticClass(const TCHAR* Package) \
        { \
            static UClass* PrivateStaticClass = NULL; \
            if (!PrivateStaticClass) \
            { \
                /* this could be handled with templates, but we want it external to avoid code bloat */ \
                GetPrivateStaticClassBody( \
                    Package, \
                    (TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), \
                    PrivateStaticClass, \
                    StaticRegisterNatives##TClass, \
                    sizeof(TClass), \
                    TClass::StaticClassFlags, \
                    TClass::StaticClassCastFlags(), \
                    TClass::StaticConfigName(), \
                    (UClass::ClassConstructorType)InternalConstructor<TClass>, \
                    (UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<TClass>, \
                    &TClass::AddReferencedObjects, \
                    &TClass::Super::StaticClass, \
                    &TClass::WithinClass::StaticClass \
                ); \
            } \
            return PrivateStaticClass; \
        }
    
    // Used for intrinsics, this sets up the boiler plate, plus an initialization singleton, which can create properties and GC tokens
    #define IMPLEMENT_INTRINSIC_CLASS(TClass, TRequiredAPI, TSuperClass, TSuperRequiredAPI, InitCode) \
        IMPLEMENT_CLASS(TClass, 0) \
        TRequiredAPI UClass* Z_Construct_UClass_##TClass(); \
        UClass* Z_Construct_UClass_##TClass() \
        { \
            static UClass* Class = NULL; \
            if (!Class) \
            { \
                extern TSuperRequiredAPI UClass* Z_Construct_UClass_##TSuperClass(); \
                UClass* SuperClass = Z_Construct_UClass_##TSuperClass(); \
                Class = TClass::StaticClass(); \
                UObjectForceRegistration(Class); \
                check(Class->GetSuperClass() == SuperClass); \
                InitCode \
                Class->StaticLink(); \
            } \
            check(Class->GetClass()); \
            return Class; \
        } \
        static FCompiledInDefer Z_CompiledInDefer_UClass_##TClass(Z_Construct_UClass_##TClass, &TClass::StaticClass, TEXT(#TClass), false);
    

    其中静态成员函数StaticClass()返回一个UClass实例。主要工作在GetPrivateStaticClassBody()中。

    void GetPrivateStaticClassBody(
        const TCHAR* PackageName,   // 包名
        const TCHAR* Name,   // Class名称
        UClass*& ReturnClass,
        void(*RegisterNativeFunc)(),
        uint32 InSize,
        uint32 InClassFlags,
        EClassCastFlags InClassCastFlags,
        const TCHAR* InConfigName,
        UClass::ClassConstructorType InClassConstructor,
        UClass::ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,
        UClass::ClassAddReferencedObjectsType InClassAddReferencedObjects,
        UClass::StaticClassFunctionType InSuperClassFn,
        UClass::StaticClassFunctionType InWithinClassFn,
        bool bIsDynamic /*= false*/
        )
    {
    #if WITH_HOT_RELOAD
          // ...  Hot Reload情况
    #endif
    
        if (!bIsDynamic)
        {
            ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UClass), ALIGNOF(UClass), true);
            ReturnClass = ::new (ReturnClass)
                UClass
                (
                EC_StaticConstructor,
                Name,
                InSize,
                InClassFlags,
                InClassCastFlags,
                InConfigName,
                EObjectFlags(RF_Public | RF_Standalone | RF_Transient | RF_MarkAsNative | RF_MarkAsRootSet),
                InClassConstructor,
    #if WITH_HOT_RELOAD_CTORS
                InClassVTableHelperCtorCaller,
    #endif // WITH_HOT_RELOAD_CTORS
                InClassAddReferencedObjects
                );
            check(ReturnClass);
        }
        else
        {
            ReturnClass = (UClass*)GUObjectAllocator.AllocateUObject(sizeof(UDynamicClass), ALIGNOF(UDynamicClass), GIsInitialLoad);
            ReturnClass = ::new (ReturnClass)
                UDynamicClass
                (
                EC_StaticConstructor,
                Name,
                InSize,
                InClassFlags,
                InClassCastFlags,
                InConfigName,
                EObjectFlags(RF_Public | RF_Standalone | RF_Transient | RF_Dynamic | (GIsInitialLoad ? RF_MarkAsRootSet : RF_NoFlags)),
                InClassConstructor,
    #if WITH_HOT_RELOAD_CTORS
                InClassVTableHelperCtorCaller,
    #endif // WITH_HOT_RELOAD_CTORS
                InClassAddReferencedObjects
                );
            check(ReturnClass);
        }
        InitializePrivateStaticClass(
            InSuperClassFn(),
            ReturnClass,
            InWithinClassFn(),
            PackageName,
            Name
            );
    
        // Register the class's native functions(C++导出给bp用的函数).
        RegisterNativeFunc();
    }
    

    案例分析

    本节分析一个自定义类,查看下与反射信息相关的代码。该例子是UE4的FPS Example。

    Paste_Image.png

    FirstPersonCharacter.h源码:

    // Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
    #pragma once
    #include "GameFramework/Character.h"
    #include "FirstPersonCharacter.generated.h"   // 由UnrealHeaderTool生成的头文件,定义一些与反射相关的宏,在FirstPerson\Intermediate\Build\Win64\UE4Editor\Inc\FirstPerson中
    
    class UInputComponent;
    
    UCLASS(config=Game) // 类的附加的meta-data定义
    class AFirstPersonCharacter : public ACharacter
    {
        GENERATED_BODY()        // 定义类反射宏
    
            // UPROPERTY宏的作用是告诉UHT, 这个成员变量需要加到反射里
        /** Pawn mesh: 1st person view (arms; seen only by self) */
        UPROPERTY(VisibleDefaultsOnly, Category=Mesh)
        class USkeletalMeshComponent* Mesh1P;
    
        /** Gun mesh: 1st person view (seen only by self) */
        UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
        class USkeletalMeshComponent* FP_Gun;
    
        /** Location on gun mesh where projectiles should spawn. */
        UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
        class USceneComponent* FP_MuzzleLocation;
    
        /** Gun mesh: VR view (attached to the VR controller directly, no arm, just the actual gun) */
        UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
        class USkeletalMeshComponent* VR_Gun;
    
        /** Location on VR gun mesh where projectiles should spawn. */
        UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
        class USceneComponent* VR_MuzzleLocation;
    
        /** First person camera */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
        class UCameraComponent* FirstPersonCameraComponent;
    
        /** Motion controller (right hand) */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
        class UMotionControllerComponent* R_MotionController;
    
        /** Motion controller (left hand) */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
        class UMotionControllerComponent* L_MotionController;
    
    public:
        AFirstPersonCharacter();
    
    protected:
        virtual void BeginPlay();
    
    public:
        /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
        float BaseTurnRate;
    
        /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
        float BaseLookUpRate;
    
        /** Gun muzzle's offset from the characters location */
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
        FVector GunOffset;
    
        /** Projectile class to spawn */
        UPROPERTY(EditDefaultsOnly, Category=Projectile)
        TSubclassOf<class AFirstPersonProjectile> ProjectileClass;
    
        /** Sound to play each time we fire */
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
        class USoundBase* FireSound;
    
        /** AnimMontage to play each time we fire */
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
        class UAnimMontage* FireAnimation;
    
        /** Whether to use motion controller location for aiming. */
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
        uint32 bUsingMotionControllers : 1;
    
            UFUNCTION(BlueprintCallable)  // UFUNCTION告知UHT,需要反射该函数信息
        void BlueprintInvokeMe(bool bSuccess);
    
            //  .... 其它代码略去
    };
    

    UHT会扫描C++ .h文件,然后生成胶水层代码。一般是每个模块生成的代码放在一个文件中,本例放在
    FirstPerson\Intermediate\Build\Win64\UE4Editor\Inc\FirstPerson\FirstPerson.generated.cpp中。

            // 针对每个函数创建一个UFunction对象。
        UFunction* Z_Construct_UFunction_AFirstPersonCharacter_BlueprintInvokeMe()
        {
            struct FirstPersonCharacter_eventBlueprintInvokeMe_Parms
            {
                bool bSuccess;
            };
            UObject* Outer=Z_Construct_UClass_AFirstPersonCharacter();
            static UFunction* ReturnFunction = NULL;
            if (!ReturnFunction)
            {
                ReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT("BlueprintInvokeMe"), RF_Public|RF_Transient|RF_MarkAsNative) UFunction(FObjectInitializer(), NULL, 0x04040401, 65535, sizeof(FirstPersonCharacter_eventBlueprintInvokeMe_Parms));
                CPP_BOOL_PROPERTY_BITMASK_STRUCT(bSuccess, FirstPersonCharacter_eventBlueprintInvokeMe_Parms, bool);
                UProperty* NewProp_bSuccess = new(EC_InternalUseOnlyConstructor, ReturnFunction, TEXT("bSuccess"), RF_Public|RF_Transient|RF_MarkAsNative) UBoolProperty(FObjectInitializer(), EC_CppProperty, CPP_BOOL_PROPERTY_OFFSET(bSuccess, FirstPersonCharacter_eventBlueprintInvokeMe_Parms), 0x0010000000000080, CPP_BOOL_PROPERTY_BITMASK(bSuccess, FirstPersonCharacter_eventBlueprintInvokeMe_Parms), sizeof(bool), true);
                ReturnFunction->Bind();
                ReturnFunction->StaticLink();
    #if WITH_METADATA
                UMetaData* MetaData = ReturnFunction->GetOutermost()->GetMetaData();
                MetaData->SetValue(ReturnFunction, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                MetaData->SetValue(ReturnFunction, TEXT("ToolTip"), TEXT("Set whether this actor's movement replicates to network clients."));
    #endif
            }
            return ReturnFunction;
        }
        UClass* Z_Construct_UClass_AFirstPersonCharacter_NoRegister()
        {
            return AFirstPersonCharacter::StaticClass();
        }
            // 针对AFirstPersonCharacter类创建一个UClass对象。
        UClass* Z_Construct_UClass_AFirstPersonCharacter()
        {
            static UClass* OuterClass = NULL;
            if (!OuterClass)
            {
                Z_Construct_UClass_ACharacter();
                Z_Construct_UPackage__Script_FirstPerson();
                OuterClass = AFirstPersonCharacter::StaticClass();
                if (!(OuterClass->ClassFlags & CLASS_Constructed))
                {
                    UObjectForceRegistration(OuterClass);
                    OuterClass->ClassFlags |= 0x20800080;
    
                    OuterClass->LinkChild(Z_Construct_UFunction_AFirstPersonCharacter_BlueprintInvokeMe());
    // 针对每个成员变量,创建相应类型的UProperty实例。
    PRAGMA_DISABLE_DEPRECATION_WARNINGS
                    CPP_BOOL_PROPERTY_BITMASK_STRUCT(bUsingMotionControllers, AFirstPersonCharacter, uint8);
                    UProperty* NewProp_bUsingMotionControllers = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("bUsingMotionControllers"), RF_Public|RF_Transient|RF_MarkAsNative) UBoolProperty(FObjectInitializer(), EC_CppProperty, CPP_BOOL_PROPERTY_OFFSET(bUsingMotionControllers, AFirstPersonCharacter), 0x0010000000000005, CPP_BOOL_PROPERTY_BITMASK(bUsingMotionControllers, AFirstPersonCharacter), sizeof(uint8), false);
                    UProperty* NewProp_FireAnimation = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("FireAnimation"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(FireAnimation, AFirstPersonCharacter), 0x0010000000000005, Z_Construct_UClass_UAnimMontage_NoRegister());
                    UProperty* NewProp_FireSound = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("FireSound"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(FireSound, AFirstPersonCharacter), 0x0010000000000005, Z_Construct_UClass_USoundBase_NoRegister());
                    UProperty* NewProp_ProjectileClass = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("ProjectileClass"), RF_Public|RF_Transient|RF_MarkAsNative) UClassProperty(CPP_PROPERTY_BASE(ProjectileClass, AFirstPersonCharacter), 0x0014000000010001, Z_Construct_UClass_AFirstPersonProjectile_NoRegister(), UClass::StaticClass());
                    UProperty* NewProp_GunOffset = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("GunOffset"), RF_Public|RF_Transient|RF_MarkAsNative) UStructProperty(CPP_PROPERTY_BASE(GunOffset, AFirstPersonCharacter), 0x0010000000000005, Z_Construct_UScriptStruct_FVector());
                    UProperty* NewProp_BaseLookUpRate = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("BaseLookUpRate"), RF_Public|RF_Transient|RF_MarkAsNative) UFloatProperty(CPP_PROPERTY_BASE(BaseLookUpRate, AFirstPersonCharacter), 0x0010000000020015);
                    UProperty* NewProp_BaseTurnRate = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("BaseTurnRate"), RF_Public|RF_Transient|RF_MarkAsNative) UFloatProperty(CPP_PROPERTY_BASE(BaseTurnRate, AFirstPersonCharacter), 0x0010000000020015);
                    UProperty* NewProp_L_MotionController = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("L_MotionController"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(L_MotionController, AFirstPersonCharacter), 0x00400000000a001d, Z_Construct_UClass_UMotionControllerComponent_NoRegister());
                    UProperty* NewProp_R_MotionController = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("R_MotionController"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(R_MotionController, AFirstPersonCharacter), 0x00400000000a001d, Z_Construct_UClass_UMotionControllerComponent_NoRegister());
                    UProperty* NewProp_FirstPersonCameraComponent = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("FirstPersonCameraComponent"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(FirstPersonCameraComponent, AFirstPersonCharacter), 0x00400000000a001d, Z_Construct_UClass_UCameraComponent_NoRegister());
                    UProperty* NewProp_VR_MuzzleLocation = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("VR_MuzzleLocation"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(VR_MuzzleLocation, AFirstPersonCharacter), 0x00400000000b0009, Z_Construct_UClass_USceneComponent_NoRegister());
                    UProperty* NewProp_VR_Gun = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("VR_Gun"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(VR_Gun, AFirstPersonCharacter), 0x00400000000b0009, Z_Construct_UClass_USkeletalMeshComponent_NoRegister());
                    UProperty* NewProp_FP_MuzzleLocation = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("FP_MuzzleLocation"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(FP_MuzzleLocation, AFirstPersonCharacter), 0x00400000000b0009, Z_Construct_UClass_USceneComponent_NoRegister());
                    UProperty* NewProp_FP_Gun = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("FP_Gun"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(FP_Gun, AFirstPersonCharacter), 0x00400000000b0009, Z_Construct_UClass_USkeletalMeshComponent_NoRegister());
                    UProperty* NewProp_Mesh1P = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("Mesh1P"), RF_Public|RF_Transient|RF_MarkAsNative) UObjectProperty(CPP_PROPERTY_BASE(Mesh1P, AFirstPersonCharacter), 0x00400000000b0009, Z_Construct_UClass_USkeletalMeshComponent_NoRegister());
    PRAGMA_ENABLE_DEPRECATION_WARNINGS
                    OuterClass->AddFunctionToFunctionMapWithOverriddenName(Z_Construct_UFunction_AFirstPersonCharacter_BlueprintInvokeMe(), "BlueprintInvokeMe"); // 3698909481
                    OuterClass->ClassConfigName = FName(TEXT("Game"));
                    OuterClass->StaticLink();
    #if WITH_METADATA
                    UMetaData* MetaData = OuterClass->GetOutermost()->GetMetaData();
                    MetaData->SetValue(OuterClass, TEXT("HideCategories"), TEXT("Navigation"));
                    MetaData->SetValue(OuterClass, TEXT("IncludePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(OuterClass, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_bUsingMotionControllers, TEXT("Category"), TEXT("Gameplay"));
                    MetaData->SetValue(NewProp_bUsingMotionControllers, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_bUsingMotionControllers, TEXT("ToolTip"), TEXT("Whether to use motion controller location for aiming."));
                    MetaData->SetValue(NewProp_FireAnimation, TEXT("Category"), TEXT("Gameplay"));
                    MetaData->SetValue(NewProp_FireAnimation, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_FireAnimation, TEXT("ToolTip"), TEXT("AnimMontage to play each time we fire"));
                    MetaData->SetValue(NewProp_FireSound, TEXT("Category"), TEXT("Gameplay"));
                    MetaData->SetValue(NewProp_FireSound, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_FireSound, TEXT("ToolTip"), TEXT("Sound to play each time we fire"));
                    MetaData->SetValue(NewProp_ProjectileClass, TEXT("Category"), TEXT("Projectile"));
                    MetaData->SetValue(NewProp_ProjectileClass, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_ProjectileClass, TEXT("ToolTip"), TEXT("Projectile class to spawn"));
                    MetaData->SetValue(NewProp_GunOffset, TEXT("Category"), TEXT("Gameplay"));
                    MetaData->SetValue(NewProp_GunOffset, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_GunOffset, TEXT("ToolTip"), TEXT("Gun muzzle's offset from the characters location"));
                    MetaData->SetValue(NewProp_BaseLookUpRate, TEXT("Category"), TEXT("Camera"));
                    MetaData->SetValue(NewProp_BaseLookUpRate, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_BaseLookUpRate, TEXT("ToolTip"), TEXT("Base look up/down rate, in deg/sec. Other scaling may affect final rate."));
                    MetaData->SetValue(NewProp_BaseTurnRate, TEXT("Category"), TEXT("Camera"));
                    MetaData->SetValue(NewProp_BaseTurnRate, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_BaseTurnRate, TEXT("ToolTip"), TEXT("Base turn rate, in deg/sec. Other scaling may affect final turn rate."));
                    MetaData->SetValue(NewProp_L_MotionController, TEXT("AllowPrivateAccess"), TEXT("true"));
                    MetaData->SetValue(NewProp_L_MotionController, TEXT("Category"), TEXT("FirstPersonCharacter"));
                    MetaData->SetValue(NewProp_L_MotionController, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_L_MotionController, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_L_MotionController, TEXT("ToolTip"), TEXT("Motion controller (left hand)"));
                    MetaData->SetValue(NewProp_R_MotionController, TEXT("AllowPrivateAccess"), TEXT("true"));
                    MetaData->SetValue(NewProp_R_MotionController, TEXT("Category"), TEXT("FirstPersonCharacter"));
                    MetaData->SetValue(NewProp_R_MotionController, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_R_MotionController, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_R_MotionController, TEXT("ToolTip"), TEXT("Motion controller (right hand)"));
                    MetaData->SetValue(NewProp_FirstPersonCameraComponent, TEXT("AllowPrivateAccess"), TEXT("true"));
                    MetaData->SetValue(NewProp_FirstPersonCameraComponent, TEXT("Category"), TEXT("Camera"));
                    MetaData->SetValue(NewProp_FirstPersonCameraComponent, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_FirstPersonCameraComponent, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_FirstPersonCameraComponent, TEXT("ToolTip"), TEXT("First person camera"));
                    MetaData->SetValue(NewProp_VR_MuzzleLocation, TEXT("Category"), TEXT("Mesh"));
                    MetaData->SetValue(NewProp_VR_MuzzleLocation, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_VR_MuzzleLocation, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_VR_MuzzleLocation, TEXT("ToolTip"), TEXT("Location on VR gun mesh where projectiles should spawn."));
                    MetaData->SetValue(NewProp_VR_Gun, TEXT("Category"), TEXT("Mesh"));
                    MetaData->SetValue(NewProp_VR_Gun, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_VR_Gun, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_VR_Gun, TEXT("ToolTip"), TEXT("Gun mesh: VR view (attached to the VR controller directly, no arm, just the actual gun)"));
                    MetaData->SetValue(NewProp_FP_MuzzleLocation, TEXT("Category"), TEXT("Mesh"));
                    MetaData->SetValue(NewProp_FP_MuzzleLocation, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_FP_MuzzleLocation, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_FP_MuzzleLocation, TEXT("ToolTip"), TEXT("Location on gun mesh where projectiles should spawn."));
                    MetaData->SetValue(NewProp_FP_Gun, TEXT("Category"), TEXT("Mesh"));
                    MetaData->SetValue(NewProp_FP_Gun, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_FP_Gun, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_FP_Gun, TEXT("ToolTip"), TEXT("Gun mesh: 1st person view (seen only by self)"));
                    MetaData->SetValue(NewProp_Mesh1P, TEXT("Category"), TEXT("Mesh"));
                    MetaData->SetValue(NewProp_Mesh1P, TEXT("EditInline"), TEXT("true"));
                    MetaData->SetValue(NewProp_Mesh1P, TEXT("ModuleRelativePath"), TEXT("FirstPersonCharacter.h"));
                    MetaData->SetValue(NewProp_Mesh1P, TEXT("ToolTip"), TEXT("Pawn mesh: 1st person view (arms; seen only by self)"));
    #endif
                }
            }
            check(OuterClass->GetClass());
            return OuterClass;
        }
            // 通过定义全局辅助FCompiledInDefer对象, 登记Class注册信息。
        static FCompiledInDefer Z_CompiledInDefer_UClass_AFirstPersonCharacter(Z_Construct_UClass_AFirstPersonCharacter, &AFirstPersonCharacter::StaticClass, TEXT("AFirstPersonCharacter"), false, nullptr, nullptr, nullptr);
        DEFINE_VTABLE_PTR_HELPER_CTOR(AFirstPersonCharacter);
    

    备注:UProperty描述了成员变量的在类内存布局中的偏移量、占据的字节大小、类型、维度等信息,详情请参阅源码。

    类注册调用堆栈(我用的是从UnrealLauncher下载的UE4, generated.cpp没法下断点):

    UClass_Register.jpg

    这里的机制是,在加载FirstPerson模块时(DLL),模块内的FCompiledInDefer全局变量会先执行初始化(构造函数中会进行登记),然后引擎对这些登记进行执行(例如执行Z_Construct_UClass_AFirstPersonCharacter()函数)。

    总结

    最后简单用下图描述UObject对象体系类与UClass的关系:

    UE4_Relection_Diagram.jpg

    相关文章

      网友评论

          本文标题:UE4对象系统_UObject&UClass

          本文链接:https://www.haomeiwen.com/subject/jefqdxtx.html