菜单

花色系统代码生成注册免费送38元体验金

2019年3月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化1个指针。不然的话,照旧后者尤为简明和平安。

UHT代码生成

在C++程序中的预处理是用来对源代码进行宏展开,预编写翻译指令处理,注释删除等操作。同样的,一旦大家采纳了宏标记的主意,不管是怎么个记号语法,大家都需求展开简短或复杂的词法分析,提取出有用的音讯,然后生成所须要的代码。在发动机里创立一个空C++项目命名为Hello,然后创设个不继续的MyClass类。编写翻译,UHT就会为大家转移以下陆个文本(位于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的生成代码剖析

先从3个最简便的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

该文件都是宏定义,因为宏定义是有前后相继的,由此大家从尾向前看,请读者此时和上文的代码对照着看。
先是最上面是CU汉兰达RENT_FILE_ID的定义

进而是八个上文说过的GENERATED_BODY定义,先从最简便的构造起始,不管这几个PLANDIVATE_PROPERTY_OFFSET和PROLOG,今后会日趋介绍到。那四个宏接着包涵了五个注明在上边的别样宏。如今来说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_CONSTRUCTO奥迪Q3S的宏,借使读者仔细翻看对照的话,会意识两者只差了“:
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); }

宣称定义了贰个构造函数包装器。要求那样做的由来是,在依照名字反射创立对象的时候,要求调用该类的构造函数。然而类的构造函数并不可能用函数指针指向,因而那里就用3个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项目会转变2个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的开始展览也是洞察,就不再赘述了。

UINTE奥迪Q3FACE的变更代码剖析

UE对Interface也有协助,借使说FStruct正是多少个纯数据的POD容器,那么UInterface则是2个只好带方法的纯接口,比C++里的抽象类要基于的纯粹一些。当然那里谈的都只关乎到用UPROPE汉兰达TY和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以提供2个暗中同意的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为它丰裕了把函数注册进程序内部存款和储蓄器的操作。
一个函数的UFunction*转移,即使它们的调用情势暗淡无光,不过变化的代码的点子却是结构同样的,差别的只是分裂的EFunctionFlags值。由此得以猜度出,更加多的差异应该是在蓝图虚拟机的有的完结的,该有的文化现在介绍蓝图的时候再谈谈。
最后,把一个特性和二个点子添加进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);就会简洁的多。

变动代码即便非常被人读,不过在局地动静下添加脚本绑定,也许本人扩充功效,有1个分明美貌的代码生成样式,无疑能大大裁减领悟费用。

引用

UE4.14.3


搜狐专栏:InsideUE4
UE4深远学习QQ群:456247757(非新手入门群,请先读书完官方文书档案和录像教程)
微信公众号:aboutue,关于UE的方方面面信息资源新闻、技巧问答、小说表露,欢迎关心。
民用原创,未经授权,谢绝转载!

相关文章

发表评论

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

网站地图xml地图