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。
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没法下断点):
这里的机制是,在加载FirstPerson模块时(DLL),模块内的FCompiledInDefer全局变量会先执行初始化(构造函数中会进行登记),然后引擎对这些登记进行执行(例如执行Z_Construct_UClass_AFirstPersonCharacter()函数)。
总结
最后简单用下图描述UObject对象体系类与UClass的关系: