StaticClass 实现分析

StaticClass 和 GetClass 的区别

StaticClass 是继承自 UObject 类的 static 函数,GetClassUObjectBase 的成员函数。

UObjectBaseGetClass 获取到的 UClass 就是在 NewObject 时传递进来的 UClass.(代码在 UObject\UObjectGlobal.cpp 中)

用途不一样,StaticClass是在获取具体类型的 UClass,而 GetClass 是获取到当前对象的真实 UClass。

StaticClass 是如何定义的

在 UE 中可以对 UObject 的类执行 UXXX::StaticClass 方法来获取到它的 UClass 对象。

但是它是如何定义的?首先要看我们声明对象的 MyActor.generated.h 中(以 AMyActor 类为例):

1
template<> MICROEND_423_API UClass* StaticClass<class AMyActor>();

为 AMyActor 类特化了 StaticClass 的版本。再去 MyActor.gen.cpp 中找以下它的实现:

1
2
3
4
5
IMPLEMENT_CLASS(AMyActor, 31943282);
template<> MICROEND_423_API UClass* StaticClass<AMyActor>()
{
return AMyActor::StaticClass();
}

从这里看也就只是转发调用而已,但是关键点隐藏在其他地方。
首先 AMyActor::StaticClass 类的定义是在 AMyActor.generated.hDECLARE_CLASS宏中(该宏定义在 ObjectMacros.h#L1524),返回的是GetPrivateStaticClass 的调用。

GetPrivateStaticClass 则在 AMyAcotr.gen.cpp 中的 IMPLEMENT_CLASS 实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Runtime/CoreUObject/Public/UObject/ObjectMacros.h
// Register a class at startup time.
#define IMPLEMENT_CLASS(TClass, TClassCrc) \
static TClassCompiledInDefer<TClass> AutoInitialize###TClass(TEXT(#TClass), sizeof(TClass), TClassCrc); \
UClass* TClass::GetPrivateStaticClass() \
{ \
static UClass* PrivateStaticClass = NULL; \
if (!PrivateStaticClass) \
{ \
/* this could be handled with templates, but we want it external to avoid code bloat */ \
GetPrivateStaticClassBody(\
StaticPackage(), \
(TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), \
PrivateStaticClass, \
StaticRegisterNatives###TClass, \
sizeof(TClass), \
alignof(TClass), \
(EClassFlags)TClass::StaticClassFlags, \
TClass::StaticClassCastFlags(), \
TClass::StaticConfigName(), \
(UClass::ClassConstructorType)InternalConstructor<TClass>, \
(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<TClass>, \
&TClass::AddReferencedObjects, \
&TClass::Super::StaticClass, \
&TClass::WithinClass::StaticClass \
); \
} \
return PrivateStaticClass; \
}

可以看到 GetPrivateStaticClass 其实就是通过这些元数据构造出 UClass 的。

如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
IMPLEMENT_CLASS(AMyActor, 3240835608);

// 宏展开之后
static TClassCompiledInDefer < AMyActor > AutoInitializeAMyActor(TEXT("AMyActor"), sizeof(AMyActor), 3240835608);
UClass * AMyActor::GetPrivateStaticClass() {
static UClass * PrivateStaticClass = NULL;
if (!PrivateStaticClass) {
GetPrivateStaticClassBody(
StaticPackage(),
(TCHAR*)TEXT("AMyActor") + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0),
PrivateStaticClass,
StaticRegisterNativesAMyActor,
sizeof(AMyActor),
alignof(AMyActor),
(EClassFlags) AMyActor::StaticClassFlags,
AMyActor::StaticClassCastFlags(),
AMyActor::StaticConfigName(),
(UClass::ClassConstructorType) InternalConstructor<AMyActor>,
(UClass::ClassVTableHelperCtorCallerType) InternalVTableHelperCtorCaller<AMyActor>,
&AMyActor::AddReferencedObjects,
&AMyActor::Super::StaticClass,
&AMyActor::WithinClass::StaticClass
);
}
return PrivateStaticClass;
};

UClass 中的函数指针

上面代码中比较关键的点为:

1
2
(UClass::ClassConstructorType)InternalConstructor<TClass>, \
(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<TClass>, \

这两行是模板实例化出了两个函数并转换成函数指针传递给GetPrivateStaticClassBody

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// class.h

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

// Helper template to call the vtable ctor caller for a class
template<class T>
UObject* InternalVTableHelperCtorCaller(FVTableHelper& Helper)
{
return T::__VTableCtorCaller(Helper);
}

就是对 __DefaultConstructor 这样函数的的转发调用。

UClass::ClassConstructorTypeUClass::ClassVTableHelperCtorCallerType 这两个 typedef 为:

1
2
typedef void		(*ClassConstructorType)				(const FObjectInitializer&);
typedef UObject* (*ClassVTableHelperCtorCallerType) (FVTableHelper& Helper);

GetPrivateStaticClassBody

其中的 GetPrivateStaticClassBody 函数是定义在 Runtime\CoreUObject\Private\UObject\Class.cpp 中的。

原型为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void GetPrivateStaticClassBody(
const TCHAR* PackageName,
const TCHAR* Name,
UClass*& ReturnClass,
void(*RegisterNativeFunc)(),
uint32 InSize,
uint32 InAlignment,
EClassFlags InClassFlags,
EClassCastFlags InClassCastFlags,
const TCHAR* InConfigName,
UClass::ClassConstructorType InClassConstructor,
UClass::ClassVTableHelperCtorCallerType InClassVTableHelperCtorCaller,
UClass::ClassAddReferencedObjectsType InClassAddReferencedObjects,
UClass::StaticClassFunctionType InSuperClassFn,
UClass::StaticClassFunctionType InWithinClassFn,
bool bIsDynamic /*= false*/
);

其中第四个参数是传入注册 Native 函数的函数指针,该函数在 MyActor.gen.cpp 中生成,也可以通过在 UFUNCTION 中添加 CustomThunk 函数来自己实现,UnLua 的覆写 C++ 函数就是基于替换 thunk 函数做的。

GetPrivateStaticClassBody中通过 (UClass*)GUObjectAllocator.AllocateUObject 来分配出 UClass 的内存,因为所有的 UClass 结构都一致。

1
2
3
4
5
6
7
8
9
10
// MyActor.gen.cpp
void AMyActor::StaticRegisterNativesAMyActor()
{
UClass* Class = AMyActor::StaticClass();
static const FNameNativePtrPair Funcs[] = {
{ "ReceiveBytes", &AMyActor::execReceiveBytes },
{ "TESTFUNC", &AMyActor::execTESTFUNC },
};
FNativeFunctionRegistrar::RegisterFunctions(Class, Funcs, ARRAY_COUNT(Funcs));
}

其实就是把 Native 的函数通过 AddNativeFunction 添加到 UClass 中:

1
2
3
4
5
6
7
8
// Runtime\CoreUObject\Private\UObject\Class.cpp 
void FNativeFunctionRegistrar::RegisterFunctions(class UClass* Class, const FNameNativePtrPair* InArray, int32 NumFunctions)
{
for (; NumFunctions; ++InArray, --NumFunctions)
{
Class->AddNativeFunction(UTF8_TO_TCHAR(InArray->NameUTF8), InArray->Pointer);
}
}