参考虚幻引擎UObjectBase类源代码定义出自己的 UObject对象成员函数偏移量

源代码路径:

Engine\Source\Runtime\CoreUObject\Public\UObject\UObjectBase.h

   // 0 ++ VTable                                        0x0 + 0x8
	/** 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; 	    // 0x8 + 0x4 =0xC

	/** Index into GObjectArray...very private. */
	int32								InternalIndex;  // 0xC +4 = 0x10
	/** Class the object belongs to. */
	UClass*							ClassPrivate;       // 0x10 +8 = 0x18 

	/** Name of this object */
	FName							NamePrivate; 		// 0x18 + 4 = 0x1C

	/** Object this object resides in. */
	UObject*						OuterPrivate; 		//0x1C + 8

定义UObject偏移量为:

  struct {
    int  VTablePtr64 = 0x0;
    int ObjectFlags = 0x8;
    int Index = 0xC;  // 前面有虚表指针和ObjectFlags
    int  Class = 0x10;
    int FName = 0x18;
    int Outer = 0x20;
  } 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
	{
		return OuterPrivate;
	}
	FORCEINLINE FName GetFName() const
	{
		return NamePrivate;
	}

	/** 
	 * Returns the stat ID of the object...
	**/
	FORCEINLINE TStatId GetStatID(bool bForDeferredUse = false) const
	{
#if STATS
		// this is done to avoid even registering stats for a disabled group (unless we plan on using it later)
		if (bForDeferredUse || FThreadStats::IsCollectingData(GET_STATID(STAT_UObjectsStatGroupTester)))
		{
			if (!StatID.IsValidStat())
			{
				CreateStatID();
			}
			return StatID;
		}
#endif
		return TStatId(); // not doing stats at the moment, or ever
	}

	
private:

	/** 
	 * Creates this stat ID for the object...and handle a null this pointer
	**/
#if STATS
	void CreateStatID() const;
#endif

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:

   // 0 ++++VTable                                        0x0 + 0x8
	/** 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; 	    // 0x8 + 0x4 =0xC

	/** Index into GObjectArray...very private. */
	int32								InternalIndex;  // 0xC +4 = 0x10
	/** Class the object belongs to. */
	UClass*							ClassPrivate;       // 0x10 +8 = 0x18 

	/** Name of this object */
	FName							NamePrivate; 		// 0x18 + 4 = 0x1C

	/** Object this object resides in. */
	UObject*						OuterPrivate; 		//0x1C + 8


	/** Stat id of this object, 0 if nobody asked for it yet */
	STAT(mutable TStatId				StatID;)

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

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐