菜单

注册免费送38元体验金《InsideUE4》UObject(四)类型系统代码生成

2018年11月13日 - 注册免费送38元体验金

卿想要啊?想使你不怕说出去嘛,你免说自怎么亮乃想如果吗?

引言

上文说到了UE的品种系统结构,以及UHT分析源码的一部分宏标记设定。在就展开了花色系统一体化的筹划后,本文将启幕谈论接下去的步骤。暂时不讨论UHT的底细,假而UHT已经分析得到了足的型元数据信息,下同样步就是是采用这消息于先后外存中构建起前文的类别系统结构,这个过程我们叫注册。同一般程序的构建流程需要经预处理、编译、汇编、链接一样,UE为了在内存中模拟构建的进程,在概念上为得以下几个阶段:生成,收集,注册,链接。总体的流程比较乱,因此本文首先开始介绍第一阶段,生成。在变化无常等,UHT分析我们的代码,并生成类型系统的系代码。

Note1:生成的代码和登记的进程会为HotReload功能的敞开也有些不平等,因此为最简化流程阐述,我们事先关HotReload,关闭的方式是在Hello.Build.cs里增长一行:Definitions.Add(“WITH_HOT_RELOAD_CTORS=0”);
Note2:本文开始与后续会略的牵线部分施用的C++基础知识,但只是是点至竣工,不做深入探讨。

C++ Static Lazy初始化模式

一样种我们常常因此,也是UE中常用的单个懒惰初始化模式是:

Hello* StaticGetHello()
{
    static Hello* obj=nullptr;
    if(!obj)
    {
        obj=...
    }
    return obj;
}
或者
Hello& StaticGetHello()
{
    static Hello obj(...);
    return obj;
}

前端非常简单,也绝非考虑多线程安全,但是于单线程环境下足用了。用指针的缘由是,有一对景,这些目标的生命周期是出于别的地方来治本之,比如UE里的GC,因此这里只static化一个指南针。否则的话,还是后者尤为从简和安全。

UHT代码生成

在C++程序中之先期处理是用来对源代码进行宏展开,预编译指令处理,注释删除等操作。同样的,一旦我们利用了宏标记之方式,不管是怎个记语法,我们都得开展简要或复杂的词法分析,提取出有因此的信息,然后转所待的代码。在发动机里创建一个空C++项目命名吧Hello,然后创建个不继续的MyClass类。编译,UHT就会为咱转移以下4独公文(位于Hello\Intermediate\Build\Win64\Hello\Inc\Hello)

其生成的公文初看起很多生复杂,但其实比较简单,不过即使是有些宏替换而已。生成的函数大都也以Z_始于,笔者开始吧以猜想Z_前缀的缩写含义,感谢NetFly向Epic的丁作证下的回:

The ‘Z_’ prefix is not part of any official naming convention, and
it
doesn’t really mean anything. Some generated functions were named this
way
to avoid name collisions and so that these functions will appear
together at the
bottom of intelisense lists.

简易,没什么特别意义,就是简单以避免命名冲突,用Z是为着字母排序总是出现于智能感知的无比下面,尽量隐藏起来。
连通下,请读者们从我的步子,开始进行这趟剖析之一起。

UCLASS的变化代码剖析

预先由一个极端简单易行的UMyClass的起来,总览分析变化的代码结构,接着再跟着观察外UEnum、UStruct、UInterface、UProperty、UFunction的代码生成样式。

MyClass.h

先是是咱们协调编辑或者引擎帮我们转移的文书样式:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "UObject/NoExportTypes.h"
#include "MyClass.generated.h"

UCLASS()
class HELLO_API UMyClass : public UObject
{
    GENERATED_BODY()
};

第5行:#include “UObject/NoExportTypes.h”
通过查阅文件内容,发现这个文件在编译的上就是是Include了外一些更基础的条文件,比如#include
“Math/Vector.h”,因此而才能够当MyClass里不用include就引述这些看似。当然,还有部分内容是专程供UHT使用来好成蓝图类型的,现在临时未欲管。

第6行:#include
“MyClass.generated.h”,就是为了引用生成的峰文件。这里呼吁留意的是,该公文include位置于接近声明的前,之后说到宏处理的早晚会用到该消息。

第11行:GENERATED_BODY(),该宏是要,其他的UCLASS宏只是提供信息,不参与编译,而GENERATED_BODY正是把声明与初数据定义关联到一起的枢纽。继续翻看宏定义:

#define BODY_MACRO_COMBINE_INNER(A,B,C,D) A##B##C##D
#define BODY_MACRO_COMBINE(A,B,C,D) BODY_MACRO_COMBINE_INNER(A,B,C,D)
#define GENERATED_BODY(...) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_GENERATED_BODY)

会发现GENERATED_BODY最终实际仅仅是浮动另外一个宏之称呼,因为:

CURRENT_FILE_ID的定义是在MyClass.generated.h的89行:\#define CURRENT_FILE_ID Hello_Source_Hello_MyClass_h,这是UHT通过分析文件得到的信息。

__LINE__标准宏指向了该宏使用时候的的函数,这里是11。加了一个__LINE__宏的目的是为了支持在同一个文件内声明多个类,比如在MyClass.h里接着再声明UMyClass2,就可以支持生成不同的宏名称。

之所以总要转变的宏名称是Hello_Source_Hello_MyClass_h_11_GENERATED_BODY,而者宏就是概念在MyClass.generated.h的77执。值得一提的凡,如果MyClass类需要UMyClass(const
FObjectInitializer&
ObjectInitializer)的构造函数自定义实现,则要为此GENERATED_UCLASS_BODY宏来让最终生成的宏指向Hello_Source_Hello_MyClass_h_11_GENERATED_BODY_LEGACY(MyClass.generated.h的66执行),其最终进行的情会多一个构造函数的始末落实。

MyClass.generated.h

UHT分析生成的文件内容如下:

PRAGMA_DISABLE_DEPRECATION_WARNINGS
#ifdef HELLO_MyClass_generated_h
#error "MyClass.generated.h already included, missing '#pragma once' in MyClass.h"
#endif
#define HELLO_MyClass_generated_h

#define Hello_Source_Hello_MyClass_h_11_RPC_WRAPPERS    //先忽略
#define Hello_Source_Hello_MyClass_h_11_RPC_WRAPPERS_NO_PURE_DECLS  //先忽略
#define Hello_Source_Hello_MyClass_h_11_INCLASS_NO_PURE_DECLS \
    private: \
    static void StaticRegisterNativesUMyClass(); \
    friend HELLO_API class UClass* Z_Construct_UClass_UMyClass(); \
    public: \
    DECLARE_CLASS(UMyClass, UObject, COMPILED_IN_FLAGS(0), 0, TEXT("/Script/Hello"), NO_API) \
    DECLARE_SERIALIZER(UMyClass) \
    /** Indicates whether the class is compiled into the engine */ \
    enum {IsIntrinsic=COMPILED_IN_INTRINSIC};


#define Hello_Source_Hello_MyClass_h_11_INCLASS \
    private: \
    static void StaticRegisterNativesUMyClass(); \
    friend HELLO_API class UClass* Z_Construct_UClass_UMyClass(); \
    public: \
    DECLARE_CLASS(UMyClass, UObject, COMPILED_IN_FLAGS(0), 0, TEXT("/Script/Hello"), NO_API) \
    DECLARE_SERIALIZER(UMyClass) \
    /** Indicates whether the class is compiled into the engine */ \
    enum {IsIntrinsic=COMPILED_IN_INTRINSIC};


#define Hello_Source_Hello_MyClass_h_11_STANDARD_CONSTRUCTORS \
    /** Standard constructor, called after all reflected properties have been initialized */ \
    NO_API UMyClass(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \
    DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UMyClass) \
    DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UMyClass); \
DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UMyClass); \
private: \
    /** Private move- and copy-constructors, should never be used */ \
    NO_API UMyClass(UMyClass&&); \
    NO_API UMyClass(const UMyClass&); \
public:


#define Hello_Source_Hello_MyClass_h_11_ENHANCED_CONSTRUCTORS \
    /** Standard constructor, called after all reflected properties have been initialized */ \
    NO_API UMyClass(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \
private: \
    /** Private move- and copy-constructors, should never be used */ \
    NO_API UMyClass(UMyClass&&); \
    NO_API UMyClass(const UMyClass&); \
public: \
    DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UMyClass); \
DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UMyClass); \
    DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UMyClass)


#define Hello_Source_Hello_MyClass_h_11_PRIVATE_PROPERTY_OFFSET     //先忽略
#define Hello_Source_Hello_MyClass_h_8_PROLOG   //先忽略
#define Hello_Source_Hello_MyClass_h_11_GENERATED_BODY_LEGACY \ //两个重要的定义
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
    Hello_Source_Hello_MyClass_h_11_PRIVATE_PROPERTY_OFFSET \
    Hello_Source_Hello_MyClass_h_11_RPC_WRAPPERS \
    Hello_Source_Hello_MyClass_h_11_INCLASS \
    Hello_Source_Hello_MyClass_h_11_STANDARD_CONSTRUCTORS \
public: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS


#define Hello_Source_Hello_MyClass_h_11_GENERATED_BODY \    //两个重要的定义
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
    Hello_Source_Hello_MyClass_h_11_PRIVATE_PROPERTY_OFFSET \
    Hello_Source_Hello_MyClass_h_11_RPC_WRAPPERS_NO_PURE_DECLS \
    Hello_Source_Hello_MyClass_h_11_INCLASS_NO_PURE_DECLS \
    Hello_Source_Hello_MyClass_h_11_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS

#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID Hello_Source_Hello_MyClass_h    //前文说过的定义
PRAGMA_ENABLE_DEPRECATION_WARNINGS

该文件还是宏定义,因为宏定义是发出内外相继的,因此我们从尾向前看,请读者此时同上文的代码对照着看。
先是最下面是CURRENT_FILE_ID的定义

继而是鲜只上文说罢之GENERATED_BODY定义,先由不过简单易行的布局开始,不管那些PRIVATE_PROPERTY_OFFSET和PROLOG,以后会渐渐介绍至。这片个宏接着包含了4单声明在上面的其余特大。目前吧Hello_Source_Hello_MyClass_h_11_INCLASS和Hello_Source_Hello_MyClass_h_11_INCLASS_NO_PURE_DECLS的定义一模一样,而Hello_Source_Hello_MyClass_h_11_STANDARD_CONSTRUCTORS和Hello_Source_Hello_MyClass_h_11_ENHANCED_CONSTRUCTORS的庞大,如果读者仔细翻看对照的言辞,会发觉彼此只是差了“:
Super(ObjectInitializer) { }; ”构造函数的默认实现。

我们延续为上,以Hello_Source_Hello_MyClass_h_11_ENHANCED_CONSTRUCTORS为例:

#define Hello_Source_Hello_MyClass_h_11_ENHANCED_CONSTRUCTORS \
    /** Standard constructor, called after all reflected properties have been initialized */ \
    NO_API UMyClass(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \   //默认的构造函数实现
private: \  //禁止掉C++11的移动和拷贝构造
    /** Private move- and copy-constructors, should never be used */ \
    NO_API UMyClass(UMyClass&&); \
    NO_API UMyClass(const UMyClass&); \
public: \
    DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UMyClass); \     //因为WITH_HOT_RELOAD_CTORS关闭,展开是空宏
    DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UMyClass); \   //同理,空宏
    DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UMyClass)

连续查看DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL的定义:

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

声称定义了一个构造函数包装器。需要如此做的案由是,在冲名字反射创建对象的下,需要调用该类的构造函数。可是类的构造函数并无能够为此函数指针指向,因此此就因故一个static函数包装一下,变成一个”平凡”的函数指针,而且所有类的签署一致,就可当UClass里用一个函数指针里保存起来。见招擎里Class.h的声明:

class COREUOBJECT_API UClass : public UStruct
...
{
    ...
    typedef void (*ClassConstructorType) (const FObjectInitializer&);
    ClassConstructorType ClassConstructor;
    ...
}

当,如果读者需要团结实现均等效反光框架的时段也得采用双重简短的模式,采用模板实现呢是如出一辙。

template<class TClass>
void MyConstructor( const FObjectInitializer& X )
{ 
    new((EInternal*)X.GetObj())TClass(X);
}

再度累向上:

#define Hello_Source_Hello_MyClass_h_11_INCLASS \
    private: \
    static void StaticRegisterNativesUMyClass(); \  //定义在cpp中,目前都是空实现
    friend HELLO_API class UClass* Z_Construct_UClass_UMyClass(); \ //一个构造该类UClass对象的辅助函数
    public: \
    DECLARE_CLASS(UMyClass, UObject, COMPILED_IN_FLAGS(0), 0, TEXT("/Script/Hello"), NO_API) \   //声明该类的一些通用基本函数
    DECLARE_SERIALIZER(UMyClass) \  //声明序列化函数
    /** Indicates whether the class is compiled into the engine */ \
    enum {IsIntrinsic=COMPILED_IN_INTRINSIC};   //这个标记指定了该类是C++Native类,不能动态再改变,跟蓝图里构造的动态类进行区分。

可以说DECLARE_CLASS是最最重大之一个声称,对照着定义:DECLARE_CLASS(UMyClass,
UObject, COMPILED_IN_FLAGS(0), 0, TEXT(“/Script/Hello”), NO_API)

多数且是无发话自明的,这里的StaticClass就是咱无限经常以的函数,其内部调用了GetPrivateStaticClass,而其实现正是在Hello.generated.cpp里之。

Hello.generated.cpp

万一整整Hello项目会扭转一个Hello.generated.cpp

#include "Hello.h"      //包含该项目的头文件,继而包含Engine.h
#include "GeneratedCppIncludes.h"   //包含UObject模块里一些必要头文件
#include "Hello.generated.dep.h"    //引用依赖文件,继而include了MyClass.h
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCode1Hello() {}   //先忽略
    void UMyClass::StaticRegisterNativesUMyClass()  //说是静态注册,但现在都是为空,先忽略
    {
    }
    IMPLEMENT_CLASS(UMyClass, 899540749);   //重要!!!
#if USE_COMPILED_IN_NATIVES //该宏编译的时候会打开
// Cross Module References
    COREUOBJECT_API class UClass* Z_Construct_UClass_UObject(); //引用CoreUObject里的函数,主要是为了得到UObject本身对应的UClass

    HELLO_API class UClass* Z_Construct_UClass_UMyClass_NoRegister();   //构造UMyClass对应的UClass对象,区别是没有后续的注册过程
    HELLO_API class UClass* Z_Construct_UClass_UMyClass();  //构造UMyClass对应的UClass对象
    HELLO_API class UPackage* Z_Construct_UPackage__Script_Hello(); //构造Hello本身的UPackage对象
    UClass* Z_Construct_UClass_UMyClass_NoRegister()
    {
        return UMyClass::StaticClass(); //直接通过访问来获取UClass对象
    }
    UClass* Z_Construct_UClass_UMyClass()   //构造并注册
    {
        static UClass* OuterClass = NULL;   //static lazy模式
        if (!OuterClass)
        {
            Z_Construct_UClass_UObject();   //确保UObject本身的UClass已经注册生成
            Z_Construct_UPackage__Script_Hello();   //确保当前Hello项目的UPackage已经创建,因为后续在生成UMyClass的UClass*对象时需要保存在这个UPacage中
            OuterClass = UMyClass::StaticClass();   //访问获得UClass*
            if (!(OuterClass->ClassFlags & CLASS_Constructed))  //防止重复注册
            {
                UObjectForceRegistration(OuterClass);   //提取信息注册自身
                OuterClass->ClassFlags |= 0x20100080;   //增加CLASS_Constructed|CLASS_RequiredAPI标记


                OuterClass->StaticLink();   //“静态”链接,后续解释
#if WITH_METADATA   //编辑器模式下开始
                UMetaData* MetaData = OuterClass->GetOutermost()->GetMetaData();    //获取关联到的UPackage其身上的元数据映射,并增加元数据信息
                MetaData->SetValue(OuterClass, TEXT("IncludePath"), TEXT("MyClass.h"));
                MetaData->SetValue(OuterClass, TEXT("ModuleRelativePath"), TEXT("MyClass.h"));
#endif
            }
        }
        check(OuterClass->GetClass());
        return OuterClass;
    }
    static FCompiledInDefer Z_CompiledInDefer_UClass_UMyClass(Z_Construct_UClass_UMyClass, &UMyClass::StaticClass, TEXT("UMyClass"), false, nullptr, nullptr, nullptr);    //延迟注册,注入信息,在启动的时候调用
    DEFINE_VTABLE_PTR_HELPER_CTOR(UMyClass);    //HotReload相关,先忽略
    UPackage* Z_Construct_UPackage__Script_Hello()  //构造Hello的UPackage
    {
        static UPackage* ReturnPackage = NULL;
        if (!ReturnPackage)
        {
            ReturnPackage = CastChecked<UPackage>(StaticFindObjectFast(UPackage::StaticClass(), NULL, FName(TEXT("/Script/Hello")), false, false));//注意的是这里只是做一个查找,真正的CreatePackage是在UObjectBase::DeferredRegister里调用的,后续在流程里会讨论到
            ReturnPackage->SetPackageFlags(PKG_CompiledIn | 0x00000000);//设定标记和Guid
            FGuid Guid;
            Guid.A = 0x79A097CD;
            Guid.B = 0xB58D8B48;
            Guid.C = 0x00000000;
            Guid.D = 0x00000000;
            ReturnPackage->SetGuid(Guid);

        }
        return ReturnPackage;
    }
#endif

PRAGMA_ENABLE_DEPRECATION_WARNINGS

绝大多数简的都注释说明了,本文件之重中之重点在IMPLEMENT_CLASS的分析,和上文.h中的DECLARE_CLASS对应,其声称如下:
相比之下着定义IMPLEMENT_CLASS(UMyClass, 899540749);

#define IMPLEMENT_CLASS(TClass, TClassCrc) \
    static TClassCompiledInDefer<TClass> AutoInitialize##TClass(TEXT(#TClass), sizeof(TClass), TClassCrc); \   //延迟注册
    UClass* TClass::GetPrivateStaticClass(const TCHAR* Package) \   //.h里声明的实现,StaticClas()内部就是调用该函数
    { \
        static UClass* PrivateStaticClass = NULL; \ //又一次static lazy
        if (!PrivateStaticClass) \
        { \
            /* this could be handled with templates, but we want it external to avoid code bloat */ \
            GetPrivateStaticClassBody( \    //该函数就是真正创建UClass*,以后
                Package, \  //Package名字
                (TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), \//类名,+1去掉U、A、F前缀,+11去掉_Deprecated前缀
                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; \
    }

情为比较简单,就是拿该类的信息污染进给GetPrivateStaticClassBody函数。

最终进行结果

经人数肉预处理进行一下生成的公文,应该会扣押得越来越透亮一些:
MyClass.h展开

#pragma once
#include "UObject/NoExportTypes.h"

class HELLO_API UMyClass : public UObject
{
private:
    static void StaticRegisterNativesUMyClass();
    friend HELLO_API class UClass* Z_Construct_UClass_UMyClass();
private:
    UMyClass& operator=(UMyClass&&);
    UMyClass& operator=(const UMyClass&);
    NO_API static UClass* GetPrivateStaticClass(const TCHAR* Package);
public:
    /** Bitwise union of #EClassFlags pertaining to this class.*/
    enum {StaticClassFlags = CLASS_Intrinsic};
    /** Typedef for the base class ({{ typedef-type }}) */
    typedef UObject Super;
    /** Typedef for {{ typedef-type }}. */
    typedef UMyClass ThisClass;
    /** Returns a UClass object representing this class at runtime */
    inline static UClass* StaticClass()
    {
        return GetPrivateStaticClass(TEXT("/Script/Hello"));
    }
    /** Returns the StaticClassFlags for this class */
    inline static EClassCastFlags StaticClassCastFlags()
    {
        return 0;
    }
    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;
    }

    friend FArchive &operator<<(FArchive& Ar, UMyClass*& Res)
    {
        return Ar << (UObject*&)Res;
    }
    /** Indicates whether the class is compiled into the engine */
    enum { IsIntrinsic = COMPILED_IN_INTRINSIC };

    /** Standard constructor, called after all reflected properties have been initialized */
    NO_API UMyClass(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { };
private:
    /** Private move- and copy-constructors, should never be used */
    NO_API UMyClass(UMyClass&&);
    NO_API UMyClass(const UMyClass&);
public:
    static void __DefaultConstructor(const FObjectInitializer& X) { new((EInternal*)X.GetObj())UMyClass(X); }
};

Hello.generated.cpp展开

//#include "Hello.h"
#include "Engine.h" 

//#include "GeneratedCppIncludes.h"
#include "CoreUObject.h"
#include "UObject/Object.h"
#include "UObject/Class.h"
#include "UObject/Package.h"
#include "UObject/MetaData.h"
#include "UObject/UnrealType.h"

//#include "Hello.generated.dep.h"
#include "MyClass.h"

void EmptyLinkFunctionForGeneratedCode1Hello() {}
void UMyClass::StaticRegisterNativesUMyClass()
{
}
static TClassCompiledInDefer<UMyClass> AutoInitializeUMyClass(TEXT("UMyClass"), sizeof(UMyClass), 899540749);
UClass* UMyClass::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("UMyClass") + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0),
            PrivateStaticClass,
            StaticRegisterNativesUMyClass,
            sizeof(UMyClass),
            UMyClass::StaticClassFlags,
            UMyClass::StaticClassCastFlags(),
            UMyClass::StaticConfigName(),
            (UClass::ClassConstructorType)InternalConstructor<UMyClass>,
            (UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<UMyClass>,
            &UMyClass::AddReferencedObjects,
            &UMyClass::Super::StaticClass,
            &UMyClass::WithinClass::StaticClass
        );
    }
    return PrivateStaticClass;
}

// Cross Module References
COREUOBJECT_API class UClass* Z_Construct_UClass_UObject();

HELLO_API class UClass* Z_Construct_UClass_UMyClass_NoRegister();
HELLO_API class UClass* Z_Construct_UClass_UMyClass();
HELLO_API class UPackage* Z_Construct_UPackage__Script_Hello();
UClass* Z_Construct_UClass_UMyClass_NoRegister()
{
    return UMyClass::StaticClass();
}
UClass* Z_Construct_UClass_UMyClass()
{
    static UClass* OuterClass = NULL;
    if (!OuterClass)
    {
        Z_Construct_UClass_UObject();
        Z_Construct_UPackage__Script_Hello();
        OuterClass = UMyClass::StaticClass();
        if (!(OuterClass->ClassFlags & CLASS_Constructed))
        {
            UObjectForceRegistration(OuterClass);
            OuterClass->ClassFlags |= 0x20100080;


            OuterClass->StaticLink();
#if WITH_METADATA
            UMetaData* MetaData = OuterClass->GetOutermost()->GetMetaData();
            MetaData->SetValue(OuterClass, TEXT("IncludePath"), TEXT("MyClass.h"));
            MetaData->SetValue(OuterClass, TEXT("ModuleRelativePath"), TEXT("MyClass.h"));
#endif
        }
    }
    check(OuterClass->GetClass());
    return OuterClass;
}
static FCompiledInDefer Z_CompiledInDefer_UClass_UMyClass(Z_Construct_UClass_UMyClass, &UMyClass::StaticClass, TEXT("UMyClass"), false, nullptr, nullptr, nullptr);
UPackage* Z_Construct_UPackage__Script_Hello()
{
    static UPackage* ReturnPackage = NULL;
    if (!ReturnPackage)
    {
        ReturnPackage = CastChecked<UPackage>(StaticFindObjectFast(UPackage::StaticClass(), NULL, FName(TEXT("/Script/Hello")), false, false));
        ReturnPackage->SetPackageFlags(PKG_CompiledIn | 0x00000000);
        FGuid Guid;
        Guid.A = 0x79A097CD;
        Guid.B = 0xB58D8B48;
        Guid.C = 0x00000000;
        Guid.D = 0x00000000;
        ReturnPackage->SetGuid(Guid);

    }
    return ReturnPackage;
}

马上样.h的声明与.cpp的概念就是都有了。不管定义了小函数,要记注册的入口即是那么片个static对象在程序启动的时刻报信息,才出矣然后的注册。

UENUM的转移代码剖析

继之是对立简便易行的Enum,我们测试的Enum如下:

#pragma once
#include "UObject/NoExportTypes.h"
#include "MyEnum.generated.h"

UENUM(BlueprintType)
enum class EMyEnum : uint8
{
    MY_Dance    UMETA(DisplayName = "Dance"),
    MY_Rain     UMETA(DisplayName = "Rain"),
    MY_Song     UMETA(DisplayName = "Song")
};

生成的MyEnum.generated.h为:

PRAGMA_DISABLE_DEPRECATION_WARNINGS
#ifdef HELLO_MyEnum_generated_h
#error "MyEnum.generated.h already included, missing '#pragma once' in MyEnum.h"
#endif
#define HELLO_MyEnum_generated_h

#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID Hello_Source_Hello_MyEnum_h

#define FOREACH_ENUM_EMYENUM(op) \  //定义一个遍历枚举值的宏,只是为了方便使用
    op(EMyEnum::MY_Dance) \
    op(EMyEnum::MY_Rain) \
    op(EMyEnum::MY_Song) 
PRAGMA_ENABLE_DEPRECATION_WARNINGS

因而Enum也非常简单,所以发现变化的莫过于也远非呀要的音信。同样的,生成的Hello.genrated.cpp中:

#include "Hello.h"
#include "GeneratedCppIncludes.h"
#include "Hello.generated.dep.h"
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCode1Hello() {}
static class UEnum* EMyEnum_StaticEnum()    //定义一个获取UEnum便利函数,会在延迟注册的时候被用到
{
    extern HELLO_API class UPackage* Z_Construct_UPackage__Script_Hello();
    static class UEnum* Singleton = NULL;
    if (!Singleton)
    {
        extern HELLO_API class UEnum* Z_Construct_UEnum_Hello_EMyEnum();
        Singleton = GetStaticEnum(Z_Construct_UEnum_Hello_EMyEnum, Z_Construct_UPackage__Script_Hello(), TEXT("EMyEnum"));
    }
    return Singleton;
}
static FCompiledInDeferEnum Z_CompiledInDeferEnum_UEnum_EMyEnum(EMyEnum_StaticEnum, TEXT("/Script/Hello"), TEXT("EMyEnum"), false, nullptr, nullptr);   //延迟注册
#if USE_COMPILED_IN_NATIVES
    HELLO_API class UEnum* Z_Construct_UEnum_Hello_EMyEnum();
    HELLO_API class UPackage* Z_Construct_UPackage__Script_Hello();
    UEnum* Z_Construct_UEnum_Hello_EMyEnum()    //构造EMyEnum关联的UEnum*
    {
        UPackage* Outer=Z_Construct_UPackage__Script_Hello();
        extern uint32 Get_Z_Construct_UEnum_Hello_EMyEnum_CRC();
        static UEnum* ReturnEnum = FindExistingEnumIfHotReloadOrDynamic(Outer, TEXT("EMyEnum"), 0, Get_Z_Construct_UEnum_Hello_EMyEnum_CRC(), false);
        if (!ReturnEnum)
        {
            ReturnEnum = new(EC_InternalUseOnlyConstructor, Outer, TEXT("EMyEnum"), RF_Public|RF_Transient|RF_MarkAsNative) UEnum(FObjectInitializer());//直接创建该UEnum对象
            TArray<TPair<FName, uint8>> EnumNames;//设置枚举里的名字和值
            EnumNames.Add(TPairInitializer<FName, uint8>(FName(TEXT("EMyEnum::MY_Dance")), 0));
            EnumNames.Add(TPairInitializer<FName, uint8>(FName(TEXT("EMyEnum::MY_Rain")), 1));
            EnumNames.Add(TPairInitializer<FName, uint8>(FName(TEXT("EMyEnum::MY_Song")), 2));
            EnumNames.Add(TPairInitializer<FName, uint8>(FName(TEXT("EMyEnum::MY_MAX")), 3));   //添加一个默认的MAX字段
            ReturnEnum->SetEnums(EnumNames, UEnum::ECppForm::EnumClass);
            ReturnEnum->CppType = TEXT("EMyEnum");
#if WITH_METADATA   //设置元数据
            UMetaData* MetaData = ReturnEnum->GetOutermost()->GetMetaData();
            MetaData->SetValue(ReturnEnum, TEXT("BlueprintType"), TEXT("true"));
            MetaData->SetValue(ReturnEnum, TEXT("ModuleRelativePath"), TEXT("MyEnum.h"));
            MetaData->SetValue(ReturnEnum, TEXT("MY_Dance.DisplayName"), TEXT("Dance"));
            MetaData->SetValue(ReturnEnum, TEXT("MY_Rain.DisplayName"), TEXT("Rain"));
            MetaData->SetValue(ReturnEnum, TEXT("MY_Song.DisplayName"), TEXT("Song"));
#endif
        }
        return ReturnEnum;
    }
    uint32 Get_Z_Construct_UEnum_Hello_EMyEnum_CRC() { return 2000113000U; }
    UPackage* Z_Construct_UPackage__Script_Hello()  //设置Hello项目的Package属性
    {
        ...略
    }
#endif

PRAGMA_ENABLE_DEPRECATION_WARNINGS

相发现EMyEnum_StaticEnum其实并无比Z_Construct_UEnum_Hello_EMyEnum实现再次多的别样的作用。GetStaticEnum目前底兑现中也惟有是非常简单的调用Z_Construct_UEnum_Hello_EMyEnum返回结果。所以保留着是EMyEnum_StaticEnum或许才是为了和UClass的构造保持一致。

USTRUCT的转移代码剖析

盖USTRUCT标记的切近里并无能够定义函数,因此测试的Struct如下:

#pragma once
#include "UObject/NoExportTypes.h"
#include "MyStruct.generated.h"

USTRUCT(BlueprintType)
struct HELLO_API FMyStruct
{
    GENERATED_USTRUCT_BODY()

    UPROPERTY(BlueprintReadWrite)
    float Score;
};

生成的MyStruct.generated.h如下:

PRAGMA_DISABLE_DEPRECATION_WARNINGS
#ifdef HELLO_MyStruct_generated_h
#error "MyStruct.generated.h already included, missing '#pragma once' in MyStruct.h"
#endif
#define HELLO_MyStruct_generated_h

#define Hello_Source_Hello_MyStruct_h_8_GENERATED_BODY \
    friend HELLO_API class UScriptStruct* Z_Construct_UScriptStruct_FMyStruct(); \  //给予全局方法友元权限
    static class UScriptStruct* StaticStruct(); //静态函数返回UScriptStruct*
#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID Hello_Source_Hello_MyStruct_h
PRAGMA_ENABLE_DEPRECATION_WARNINGS

同理,根据GENERATED_USTRUCT_BODY的定义,最终会交替成Hello_Source_Hello_MyStruct_h_8_GENERATED_BODY宏。我们发现实际上作用只是于内部定义了一个StaticStruct函数,因为FMyStruct并无连续给UObject,所以组织为死的大概。
重新跟着是Hello.genrated.cpp:

#include "Hello.h"
#include "GeneratedCppIncludes.h"
#include "Hello.generated.dep.h"
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCode1Hello() {}
class UScriptStruct* FMyStruct::StaticStruct()//实现了静态获取UScriptStruct*
{
    extern HELLO_API class UPackage* Z_Construct_UPackage__Script_Hello();
    static class UScriptStruct* Singleton = NULL;
    if (!Singleton)
    {
        extern HELLO_API class UScriptStruct* Z_Construct_UScriptStruct_FMyStruct();
        extern HELLO_API uint32 Get_Z_Construct_UScriptStruct_FMyStruct_CRC();
        Singleton = GetStaticStruct(Z_Construct_UScriptStruct_FMyStruct, Z_Construct_UPackage__Script_Hello(), TEXT("MyStruct"), sizeof(FMyStruct), Get_Z_Construct_UScriptStruct_FMyStruct_CRC());
    }
    return Singleton;
}
static FCompiledInDeferStruct Z_CompiledInDeferStruct_UScriptStruct_FMyStruct(FMyStruct::StaticStruct, TEXT("/Script/Hello"), TEXT("MyStruct"), false, nullptr, nullptr);  //延迟注册
static struct FScriptStruct_Hello_StaticRegisterNativesFMyStruct
{
    FScriptStruct_Hello_StaticRegisterNativesFMyStruct()
    {
        UScriptStruct::DeferCppStructOps(FName(TEXT("MyStruct")),new UScriptStruct::TCppStructOps<FMyStruct>);
    }
} ScriptStruct_Hello_StaticRegisterNativesFMyStruct;    //static注册
#if USE_COMPILED_IN_NATIVES
    HELLO_API class UScriptStruct* Z_Construct_UScriptStruct_FMyStruct();
    HELLO_API class UPackage* Z_Construct_UPackage__Script_Hello();
    UScriptStruct* Z_Construct_UScriptStruct_FMyStruct()    //构造关联的UScriptStruct*
    {
        UPackage* Outer = Z_Construct_UPackage__Script_Hello();
        extern uint32 Get_Z_Construct_UScriptStruct_FMyStruct_CRC();
        static UScriptStruct* ReturnStruct = FindExistingStructIfHotReloadOrDynamic(Outer, TEXT("MyStruct"), sizeof(FMyStruct), Get_Z_Construct_UScriptStruct_FMyStruct_CRC(), false);
        if (!ReturnStruct)
        {
            ReturnStruct = new(EC_InternalUseOnlyConstructor, Outer, TEXT("MyStruct"), RF_Public|RF_Transient|RF_MarkAsNative) UScriptStruct(FObjectInitializer(), NULL, new UScriptStruct::TCppStructOps<FMyStruct>, EStructFlags(0x00000201));//直接创建UScriptStruct对象
            UProperty* NewProp_Score = new(EC_InternalUseOnlyConstructor, ReturnStruct, TEXT("Score"), RF_Public|RF_Transient|RF_MarkAsNative) UFloatProperty(CPP_PROPERTY_BASE(Score, FMyStruct), 0x0010000000000004);//直接关联相应的Property信息
            ReturnStruct->StaticLink(); //链接
#if WITH_METADATA   //元数据
            UMetaData* MetaData = ReturnStruct->GetOutermost()->GetMetaData();
            MetaData->SetValue(ReturnStruct, TEXT("BlueprintType"), TEXT("true"));
            MetaData->SetValue(ReturnStruct, TEXT("ModuleRelativePath"), TEXT("MyStruct.h"));
            MetaData->SetValue(NewProp_Score, TEXT("Category"), TEXT("MyStruct"));
            MetaData->SetValue(NewProp_Score, TEXT("ModuleRelativePath"), TEXT("MyStruct.h"));
#endif
        }
        return ReturnStruct;
    }
    uint32 Get_Z_Construct_UScriptStruct_FMyStruct_CRC() { return 2914362188U; }
    UPackage* Z_Construct_UPackage__Script_Hello()
    {
        ...略
    }
#endif

PRAGMA_ENABLE_DEPRECATION_WARNINGS

同理,会发现FMyStruct::StaticStruct内部也未会见比Z_Construct_UScriptStruct_FMyStruct更多的事情,GetStaticStruct的兑现呢只是简短的转速到Z_Construct_UScriptStruct_FMyStruct。值得一提的是概念之ScriptStruct_Hello_StaticRegisterNativesFMyStruct,会当程序一样启动就调用UScriptStruct::DeferCppStructOps向程序报该组织的CPP信息(大小,内存对齐等),和TClassCompiledInDefer<TClass>的打算相当。FMyStruct的拓展也是吃透,就不再赘述了。

UINTERFACE的更动代码剖析

UE对Interface也来支持,如果说FStruct就是一个纯数据的POD容器,那么UInterface则是一个只好带来道的纯接口,比C++里的肤浅类设根据的纯粹一些。当然这里出口的还只有关乎到用UPROPERTY和UFUNCTION宏标记的那些,如果是纯C++的字段和函数,UE并无能够不管及那有钱。
测试的MyInterface.h为:

#pragma once
#include "UObject/NoExportTypes.h"
#include "MyInterface.generated.h"

UINTERFACE(BlueprintType)
class UMyInterface : public UInterface
{
    GENERATED_UINTERFACE_BODY()    
};

class IMyInterface
{
    GENERATED_IINTERFACE_BODY()
public:
    UFUNCTION(BlueprintImplementableEvent)
    void BPFunc() const;
};

GENERATED_UINTERFACE_BODY和GENERATED_IINTERFACE_BODY都足以轮换为GENERATED_BODY因供一个默认的UMyInterface(const
FObjectInitializer&
ObjectInitializer)构造函数实现。不过GENERATED_IINTERFACE_BODY替换过后的功用呢一如既往,因为并不需要那么一个构造函数,所以用半单还足以。
生成的MyInterface.generated.h如下:

PRAGMA_DISABLE_DEPRECATION_WARNINGS
#ifdef HELLO_MyInterface_generated_h
#error "MyInterface.generated.h already included, missing '#pragma once' in MyInterface.h"
#endif
#define HELLO_MyInterface_generated_h

#define Hello_Source_Hello_MyInterface_h_8_RPC_WRAPPERS
#define Hello_Source_Hello_MyInterface_h_8_RPC_WRAPPERS_NO_PURE_DECLS
#define Hello_Source_Hello_MyInterface_h_8_EVENT_PARMS
extern HELLO_API  FName HELLO_BPFunc;   //函数的名称,在cpp中定义
#define Hello_Source_Hello_MyInterface_h_8_CALLBACK_WRAPPERS
#define Hello_Source_Hello_MyInterface_h_8_STANDARD_CONSTRUCTORS \
    /** Standard constructor, called after all reflected properties have been initialized */ \
    NO_API UMyInterface(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \
    DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UMyInterface) \
    DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UMyInterface); \
DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UMyInterface); \
private: \
    /** Private move- and copy-constructors, should never be used */ \
    NO_API UMyInterface(UMyInterface&&); \
    NO_API UMyInterface(const UMyInterface&); \
public:


#define Hello_Source_Hello_MyInterface_h_8_ENHANCED_CONSTRUCTORS \
    /** Standard constructor, called after all reflected properties have been initialized */ \
    NO_API UMyInterface(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()) : Super(ObjectInitializer) { }; \
private: \
    /** Private move- and copy-constructors, should never be used */ \
    NO_API UMyInterface(UMyInterface&&); \
    NO_API UMyInterface(const UMyInterface&); \
public: \
    DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UMyInterface); \
DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UMyInterface); \
    DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UMyInterface)


#undef GENERATED_UINTERFACE_BODY_COMMON
#define GENERATED_UINTERFACE_BODY_COMMON() \
    private: \
    static void StaticRegisterNativesUMyInterface(); \  //注册
    friend HELLO_API class UClass* Z_Construct_UClass_UMyInterface(); \ //构造UClass*的方法
public: \
    DECLARE_CLASS(UMyInterface, UInterface, COMPILED_IN_FLAGS(CLASS_Abstract | CLASS_Interface), 0, TEXT("/Script/Hello"), NO_API) \
    DECLARE_SERIALIZER(UMyInterface) \
    enum {IsIntrinsic=COMPILED_IN_INTRINSIC};


#define Hello_Source_Hello_MyInterface_h_8_GENERATED_BODY_LEGACY \
        PRAGMA_DISABLE_DEPRECATION_WARNINGS \
    GENERATED_UINTERFACE_BODY_COMMON() \
    Hello_Source_Hello_MyInterface_h_8_STANDARD_CONSTRUCTORS \
    PRAGMA_ENABLE_DEPRECATION_WARNINGS


#define Hello_Source_Hello_MyInterface_h_8_GENERATED_BODY \
    PRAGMA_DISABLE_DEPRECATION_WARNINGS \
    GENERATED_UINTERFACE_BODY_COMMON() \
    Hello_Source_Hello_MyInterface_h_8_ENHANCED_CONSTRUCTORS \
private: \
    PRAGMA_ENABLE_DEPRECATION_WARNINGS


#define Hello_Source_Hello_MyInterface_h_8_INCLASS_IINTERFACE_NO_PURE_DECLS \
protected: \
    virtual ~IMyInterface() {} \
public: \
    typedef UMyInterface UClassType; \
    static void Execute_BPFunc(const UObject* O); \
    virtual UObject* _getUObject() const = 0;


#define Hello_Source_Hello_MyInterface_h_8_INCLASS_IINTERFACE \
protected: \
    virtual ~IMyInterface() {} \
public: \
    typedef UMyInterface UClassType; \
    static void Execute_BPFunc(const UObject* O); \
    virtual UObject* _getUObject() const = 0;


#define Hello_Source_Hello_MyInterface_h_5_PROLOG \
    Hello_Source_Hello_MyInterface_h_8_EVENT_PARMS


#define Hello_Source_Hello_MyInterface_h_13_GENERATED_BODY_LEGACY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
    Hello_Source_Hello_MyInterface_h_8_RPC_WRAPPERS \
    Hello_Source_Hello_MyInterface_h_8_CALLBACK_WRAPPERS \
    Hello_Source_Hello_MyInterface_h_8_INCLASS_IINTERFACE \
public: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS


#define Hello_Source_Hello_MyInterface_h_13_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
    Hello_Source_Hello_MyInterface_h_8_RPC_WRAPPERS_NO_PURE_DECLS \
    Hello_Source_Hello_MyInterface_h_8_CALLBACK_WRAPPERS \
    Hello_Source_Hello_MyInterface_h_8_INCLASS_IINTERFACE_NO_PURE_DECLS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS


#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID Hello_Source_Hello_MyInterface_h


PRAGMA_ENABLE_DEPRECATION_WARNINGS

盖接口的概念需要因此到少单近乎,所以生成的音讯有点复杂了部分。不过以的时刻,我们的类似才是后续给IMyInterface,UMyInerface只是用作一个接口类型的载体,用以区分和寻找不同的接口。观察的时,也请小心行号的概念。
由之为上,最后两只是IMyInterface里的宏展开,细看之后,会意识_LEGACY和健康版并无差异。展开后是:

class IMyInterface
{
protected: 
    virtual ~IMyInterface() {}  //禁止用接口指针释放对象
public: 
    typedef UMyInterface UClassType;    //设定UMyInterface为关联的类型
    static void Execute_BPFunc(const UObject* O);   //蓝图调用的辅助函数
    virtual UObject* _getUObject() const = 0;   //
public:
    UFUNCTION(BlueprintImplementableEvent)
    void BPFunc() const;
};

更为上是UMyInterface的别,因为UMyInterface继承于UObject的因,所以也是由属于Object系统的一份子,所以一律用按构造函数的平整。UInterface本身其实也足以算是UClass的一律种植,所以生成的代码和UClass中的生成都差不多,区别是为此了COMPILED_IN_FLAGS(CLASS_Abstract
| CLASS_Interface)的两样标记。有趣味之读者可协调进行看下。

生成的Hello.generated.cpp:

#include "Hello.h"
#include "GeneratedCppIncludes.h"
#include "Hello.generated.dep.h"
PRAGMA_DISABLE_DEPRECATION_WARNINGS
void EmptyLinkFunctionForGeneratedCode1Hello() {}
FName HELLO_BPFunc = FName(TEXT("BPFunc")); //名字的定义
    void IMyInterface::BPFunc() const   //让编译通过,同时加上错误检测
    {
        check(0 && "Do not directly call Event functions in Interfaces. Call Execute_BPFunc instead.");
    }
    void UMyInterface::StaticRegisterNativesUMyInterface()
    {
    }
    IMPLEMENT_CLASS(UMyInterface, 4286549343);  //注册类
    void IMyInterface::Execute_BPFunc(const UObject* O) //蓝图调用方法的实现
    {
        check(O != NULL);
        check(O->GetClass()->ImplementsInterface(UMyInterface::StaticClass()));//检查是否实现了该接口
        UFunction* const Func = O->FindFunction(HELLO_BPFunc);  //通过名字找到方法
        if (Func)
        {
            const_cast<UObject*>(O)->ProcessEvent(Func, NULL);  //在该对象上调用该方法
        }
    }
#if USE_COMPILED_IN_NATIVES
    HELLO_API class UFunction* Z_Construct_UFunction_UMyInterface_BPFunc();
    HELLO_API class UClass* Z_Construct_UClass_UMyInterface_NoRegister();
    HELLO_API class UClass* Z_Construct_UClass_UMyInterface();
    HELLO_API class UPackage* Z_Construct_UPackage__Script_Hello();
    UFunction* Z_Construct_UFunction_UMyInterface_BPFunc()//构造BPFunc的UFunction
    {
        UObject* Outer=Z_Construct_UClass_UMyInterface();   //得到接口UMyInterface*对象
        static UFunction* ReturnFunction = NULL;
        if (!ReturnFunction)
        {
            ReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT("BPFunc"), RF_Public|RF_Transient|RF_MarkAsNative) UFunction(FObjectInitializer(), NULL, 0x48020800, 65535); //直接构造函数对象
            ReturnFunction->Bind(); //绑定到函数指针
            ReturnFunction->StaticLink();   //链接
#if WITH_METADATA   //元数据
            UMetaData* MetaData = ReturnFunction->GetOutermost()->GetMetaData();
            MetaData->SetValue(ReturnFunction, TEXT("ModuleRelativePath"), TEXT("MyInterface.h"));
#endif
        }
        return ReturnFunction;
    }
    UClass* Z_Construct_UClass_UMyInterface_NoRegister()
    {
        return UMyInterface::StaticClass();
    }
    UClass* Z_Construct_UClass_UMyInterface()
    {
        static UClass* OuterClass = NULL;
        if (!OuterClass)
        {
            UInterface::StaticClass();  //确保基类UInterface已经元数据构造完成
            Z_Construct_UPackage__Script_Hello();
            OuterClass = UMyInterface::StaticClass();
            if (!(OuterClass->ClassFlags & CLASS_Constructed))
            {
                UObjectForceRegistration(OuterClass);
                OuterClass->ClassFlags |= 0x20004081;//CLASS_Constructed|CLASS_Interface|CLASS_Native|CLASS_Abstract

                OuterClass->LinkChild(Z_Construct_UFunction_UMyInterface_BPFunc());//添加子字段

                OuterClass->AddFunctionToFunctionMapWithOverriddenName(Z_Construct_UFunction_UMyInterface_BPFunc(), "BPFunc"); // 1371259725 ,添加函数名字映射
                OuterClass->StaticLink();   //链接
#if WITH_METADATA   //元数据
                UMetaData* MetaData = OuterClass->GetOutermost()->GetMetaData();
                MetaData->SetValue(OuterClass, TEXT("BlueprintType"), TEXT("true"));
                MetaData->SetValue(OuterClass, TEXT("ModuleRelativePath"), TEXT("MyInterface.h"));
#endif
            }
        }
        check(OuterClass->GetClass());
        return OuterClass;
    }
    static FCompiledInDefer Z_CompiledInDefer_UClass_UMyInterface(Z_Construct_UClass_UMyInterface, &UMyInterface::StaticClass, TEXT("UMyInterface"), false, nullptr, nullptr, nullptr);    //延迟注册
    DEFINE_VTABLE_PTR_HELPER_CTOR(UMyInterface);
    UPackage* Z_Construct_UPackage__Script_Hello()
    {
        ...略
    }
#endif

PRAGMA_ENABLE_DEPRECATION_WARNINGS

骨干和UClass中之结构基本上,只是多了一些函数定义之长河与管函数添加到近似中之操作。

UClass中的字段和函数生成代码剖析

在无比初步之时光,我们就此了一个极其简便的UMyClass来阐释整体的组织。行百里者半九十,让我们一举,看看如果UMyClass里多了Property和Function之后又会于呀变动。
测试的MyClass.h如下:

#pragma once
#include "UObject/NoExportTypes.h"
#include "MyClass.generated.h"

UCLASS(BlueprintType)
class HELLO_API UMyClass : public UObject
{
    GENERATED_BODY()
public:
    UPROPERTY(BlueprintReadWrite)
    float Score;
public:
    UFUNCTION(BlueprintCallable, Category = "Hello")
    void CallableFunc();    //C++实现,蓝图调用

    UFUNCTION(BlueprintNativeEvent, Category = "Hello")
    void NativeFunc();  //C++实现默认版本,蓝图可重载实现

    UFUNCTION(BlueprintImplementableEvent, Category = "Hello")
    void ImplementableFunc();   //C++不实现,蓝图实现
};

增加了一个性能与老三个不等方式来测试。
其生成的MyClass.generated.h为(只囊括改变有):

#define Hello_Source_Hello_MyClass_h_8_RPC_WRAPPERS \
    virtual void NativeFunc_Implementation(); \ //默认实现的函数声明,我们可以自己实现
 \
    DECLARE_FUNCTION(execNativeFunc) \  //声明供蓝图调用的函数
    { \
        P_FINISH; \
        P_NATIVE_BEGIN; \
        this->NativeFunc_Implementation(); \
        P_NATIVE_END; \
    } \
 \
    DECLARE_FUNCTION(execCallableFunc) \    //声明供蓝图调用的函数
    { \
        P_FINISH; \
        P_NATIVE_BEGIN; \
        this->CallableFunc(); \
        P_NATIVE_END; \
    }


#define Hello_Source_Hello_MyClass_h_8_RPC_WRAPPERS_NO_PURE_DECLS \ //和上面重复,略

//声明函数名称
extern HELLO_API  FName HELLO_ImplementableFunc;
extern HELLO_API  FName HELLO_NativeFunc;

因为CallableFunc是C++里实现的,所以这边并不需要再定义函数体。而除此以外两独函数其实是当蓝图里定义之,就需特别生成exec前缀的函数供蓝图虚拟机调用。
俺们展开execCallableFunc后呢:

void execCallableFunc( FFrame& Stack, void*const Z_Param__Result )  //蓝图虚拟机的使用的函数接口
{
    Stack.Code += !!Stack.Code; /* increment the code ptr unless it is null */
    { 
        FBlueprintEventTimer::FScopedNativeTimer ScopedNativeCallTimer;     //蓝图的计时统计
        this->CallableFunc(); //调用我们自己的实现
    }
}

即或者非常简单的,当然根据函数签名的差会助长不同之参数传递,但是盖结构即是如此。以上之函数都是概念在UMyClass类内部的。
又来拘禁Hello.generated.cpp里之转移(只包改变一些):

//函数名字定义
FName HELLO_ImplementableFunc = FName(TEXT("ImplementableFunc"));
FName HELLO_NativeFunc = FName(TEXT("NativeFunc"));
    void UMyClass::ImplementableFunc()  //C++端的实现
    {
        ProcessEvent(FindFunctionChecked(HELLO_ImplementableFunc),NULL);
    }
    void UMyClass::NativeFunc() //C++端的实现
    {
        ProcessEvent(FindFunctionChecked(HELLO_NativeFunc),NULL);
    }
    void UMyClass::StaticRegisterNativesUMyClass()  //注册函数名字和函数指针映射
    {
        FNativeFunctionRegistrar::RegisterFunction(UMyClass::StaticClass(), "CallableFunc",(Native)&UMyClass::execCallableFunc);
        FNativeFunctionRegistrar::RegisterFunction(UMyClass::StaticClass(), "NativeFunc",(Native)&UMyClass::execNativeFunc);
    }
//...略去中间相同部分
//构造3个函数的UFunction*对象,结构一样,只是EFunctionFlags不一样
UFunction* Z_Construct_UFunction_UMyClass_CallableFunc()
    {
        UObject* Outer=Z_Construct_UClass_UMyClass();
        static UFunction* ReturnFunction = NULL;
        if (!ReturnFunction)
        {
            ReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT("CallableFunc"), RF_Public|RF_Transient|RF_MarkAsNative) UFunction(FObjectInitializer(), NULL, 0x04020401, 65535); //FUNC_BlueprintCallable|FUNC_Public|FUNC_Native|FUNC_Final
            ReturnFunction->Bind();
            ReturnFunction->StaticLink();
#if WITH_METADATA
            UMetaData* MetaData = ReturnFunction->GetOutermost()->GetMetaData();
            MetaData->SetValue(ReturnFunction, TEXT("Category"), TEXT("Hello"));
            MetaData->SetValue(ReturnFunction, TEXT("ModuleRelativePath"), TEXT("MyClass.h"));
#endif
        }
        return ReturnFunction;
    }
    UFunction* Z_Construct_UFunction_UMyClass_ImplementableFunc()
    {
        UObject* Outer=Z_Construct_UClass_UMyClass();
        static UFunction* ReturnFunction = NULL;
        if (!ReturnFunction)
        {
            ReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT("ImplementableFunc"), RF_Public|RF_Transient|RF_MarkAsNative) UFunction(FObjectInitializer(), NULL, 0x08020800, 65535); //FUNC_BlueprintEvent|FUNC_Public|FUNC_Event
            ReturnFunction->Bind();
            ReturnFunction->StaticLink();
#if WITH_METADATA
            UMetaData* MetaData = ReturnFunction->GetOutermost()->GetMetaData();
            MetaData->SetValue(ReturnFunction, TEXT("Category"), TEXT("Hello"));
            MetaData->SetValue(ReturnFunction, TEXT("ModuleRelativePath"), TEXT("MyClass.h"));
#endif
        }
        return ReturnFunction;
    }
    UFunction* Z_Construct_UFunction_UMyClass_NativeFunc()
    {
        UObject* Outer=Z_Construct_UClass_UMyClass();
        static UFunction* ReturnFunction = NULL;
        if (!ReturnFunction)
        {
            ReturnFunction = new(EC_InternalUseOnlyConstructor, Outer, TEXT("NativeFunc"), RF_Public|RF_Transient|RF_MarkAsNative) UFunction(FObjectInitializer(), NULL, 0x08020C00, 65535);//FUNC_BlueprintEvent|FUNC_Public|FUNC_Event|FUNC_Native
            ReturnFunction->Bind();
            ReturnFunction->StaticLink();
#if WITH_METADATA
            UMetaData* MetaData = ReturnFunction->GetOutermost()->GetMetaData();
            MetaData->SetValue(ReturnFunction, TEXT("Category"), TEXT("Hello"));
            MetaData->SetValue(ReturnFunction, TEXT("ModuleRelativePath"), TEXT("MyClass.h"));
#endif
        }
        return ReturnFunction;
    }
//...略去中间相同部分
UClass* Z_Construct_UClass_UMyClass()
    {
        static UClass* OuterClass = NULL;
        if (!OuterClass)
        {
            Z_Construct_UClass_UObject();
            Z_Construct_UPackage__Script_Hello();
            OuterClass = UMyClass::StaticClass();
            if (!(OuterClass->ClassFlags & CLASS_Constructed))
            {
                UObjectForceRegistration(OuterClass);
                OuterClass->ClassFlags |= 0x20100080;
                //添加子字段
                OuterClass->LinkChild(Z_Construct_UFunction_UMyClass_CallableFunc());
                OuterClass->LinkChild(Z_Construct_UFunction_UMyClass_ImplementableFunc());
                OuterClass->LinkChild(Z_Construct_UFunction_UMyClass_NativeFunc());

PRAGMA_DISABLE_DEPRECATION_WARNINGS
                UProperty* NewProp_Score = new(EC_InternalUseOnlyConstructor, OuterClass, TEXT("Score"), RF_Public|RF_Transient|RF_MarkAsNative) UFloatProperty(CPP_PROPERTY_BASE(Score, UMyClass), 0x0010000000000004);//添加属性
PRAGMA_ENABLE_DEPRECATION_WARNINGS
                //添加函数名字映射
                OuterClass->AddFunctionToFunctionMapWithOverriddenName(Z_Construct_UFunction_UMyClass_CallableFunc(), "CallableFunc"); // 774395847
                OuterClass->AddFunctionToFunctionMapWithOverriddenName(Z_Construct_UFunction_UMyClass_ImplementableFunc(), "ImplementableFunc"); // 615168156
                OuterClass->AddFunctionToFunctionMapWithOverriddenName(Z_Construct_UFunction_UMyClass_NativeFunc(), "NativeFunc"); // 3085959641
                OuterClass->StaticLink();
#if WITH_METADATA   //元数据
                UMetaData* MetaData = OuterClass->GetOutermost()->GetMetaData();
                MetaData->SetValue(OuterClass, TEXT("BlueprintType"), TEXT("true"));
                MetaData->SetValue(OuterClass, TEXT("IncludePath"), TEXT("MyClass.h"));
                MetaData->SetValue(OuterClass, TEXT("ModuleRelativePath"), TEXT("MyClass.h"));
                MetaData->SetValue(NewProp_Score, TEXT("Category"), TEXT("MyClass"));
                MetaData->SetValue(NewProp_Score, TEXT("ModuleRelativePath"), TEXT("MyClass.h"));
#endif
            }
        }
        check(OuterClass->GetClass());
        return OuterClass;
    }

足见到,对于CallableFunc这种C++实现,蓝图只是调用的法门,生成的代码只是颇成了对应的UFunction*对象。而于NativeFunc和ImplementableFunc,我们不见面以C++里写及它们的实现,因此为编译通过,也以好自C++端直接调用,就待在转的代码的时光吗如出一辙不行成一份默认实现。
以头里的简要近乎生成代码中,StaticRegisterNativesUMyClass总是拖欠的,在此地UHT为它长了拿函数注册过程序内存的操作。
3独函数的UFunction*转变,虽然她的调用方式大相径庭,但是变化的代码的艺术却是布局同样的,区别的只是不同的EFunctionFlags值。因此得以测算出,更多的差别应该是当蓝图虚拟机的一对实现之,该片段文化后介绍蓝图的时刻还议论。
末,把1独特性与3个章程上加进UClass中,齐活收工。

总结

本篇篇幅较丰富,我们花费了大气之叙述阐述UHT生成的代码的样式。首先由一个最好简便易行的UMyClass开始,观察整变代码的布局,接着推进到UMyEnum、UMyStruct、UMyInterface的代码样式,最后回到归到UMyClass在中间添加进属性和办法,观察性与章程是怎么生成代码和怎么和UClass*对象关系起来的。其实我们啊意识,这个阶段最重大之作用就是是尽量的管程序的音讯之所以代码给记录下来,对于Enum记下名字和价值;对于Struct记下每个Property的名字跟字节偏移;对于Interface记下每个函数或卷入函数的底函数指针和名字;对于Class同理都记录Property和Function。
当,我们现在只得干到片太简便的性与章程类型,目的是为读者们对转移的代码来个整体的定义,不要一下子陷入到了复杂的细节被去。观察生成的代码可知,其实就分点儿部分,一凡是各种Z_扶助方法用来布局出各种UClass*顶目标;另一样局部是还蕴涵着一两只static对象用来在程序启动的下使得登记,继而调用到前者的Z_主意,最终就注册。
当摸底及了变动的代码是怎样之后,下篇,我们就用深入到这些注册的流水线中去。

题外话

咱们啊足以充分容易之张,UHT生成的就卖代码并无是极其精简之。比如生成的简单个巨大,最终进行的结果也一样,又或很成了空宏。这一端原因虽然是盖发广大之历史遗留痕迹,另一方面也是为于贯彻UHT的时刻,为了照顾流程达到之合,并不曾改善的错过优化掉冗余的分,只是保留了下去。想法是反正UHT生成的代码,不是受开发者读之,所以乱点也不在乎了。最关键的凡It
works!所以啊便从未什么人发出失去改善的动力了。
C++的代码生成,一般还无不了索要用到大量宏之配合。读者们假如想实现好之代码生成框架,笔者之建议是拼命三郎的拿国有的一对挪移到宏定义中失去,并方便的动模板,尽量最简洁化生成代码的书道,比如在UHT中之:

FGuid Guid;
Guid.A = 0xDF4B1A6D;
Guid.B = 0x02873257;
Guid.C = 0x00000000;
Guid.D = 0x00000000;
//换成FGuid Guid(0xDF4B1A6D,0x02873257,0x00000000,0x00000000);就会简洁的多。

变动代码虽然不经常被人读,但是以部分场面下加加脚本绑定,或者自己壮大功能,有一个清晰漂亮的代码生成样式,无疑会大大减少理解成本。

引用

UE4.14.3


知乎专栏:InsideUE4
UE4注册免费送38元体验金深入学习QQ群:456247757(非新手入门群,请预修完官方文档和视频教程)
微信公众号:aboutue,关于UE的周新闻资讯、技巧问答、文章发布,欢迎关注。
个人原创,未经授权,谢绝转载!

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图