菜单

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

2019年3月18日 - 注册免费送38元体验金

您想要啊?想要你就说出来嘛,你不说小编怎么精晓您想要呢?

引言

上文讲到了UE的项目系统结构,以及UHT分析源码的一部分宏标记设定。在已经拓展了花色系统完整的统一筹划之后,本文将起来谈论接下去的手续。权且不探讨UHT的细节,借使UHT已经分析得到了丰裕的体系元数据消息,下一步便是使用这几个新闻在程序内部存款和储蓄器中营造起前文的类型系统结构,这几个进度大家誉为注册。同一般程序的营造流程供给通过预处理、编写翻译、汇编、链接一样,UE为了在内部存款和储蓄器中模拟构建的历程,在概念上也供给以下多少个级次:生成,收集,注册,链接。总体的流水生产线比较混乱,由此本文首先起首介绍第2等级,生成。在扭转阶段,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++程序中的预处理是用来对源代码进行宏展开,预编译指令处理,注释删除等操作。同样的,一旦我们接纳了宏标记的方式,不管是怎么个记号语法,大家都供给开始展览简短或复杂的词法分析,提取出有用的音讯,然后生成所须要的代码。在发动机里创设3个空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的变迁代码剖析

先从一个最简便易行的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_注册免费送38元体验金,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猎豹CS6RENT_FILE_ID的定义

进而是四个上文说过的GENERATED_BODY定义,先从最简便易行的组织开始,不管那贰个P奥迪Q7IVATE_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奇骏S的宏,假若读者仔细查看对照的话,会意识相互只差了“:
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里用3个函数指针里保存起来。见引擎里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是最重点的1个声称,对照着定义: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的展开也是了如指掌,就不再赘言了。

UINTESportageFACE的变迁代码剖析

UE对Interface也有支撑,假诺说FStruct就是2个纯数据的POD容器,那么UInterface则是三个只能带方法的纯接口,比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替换过后的功用也同等,因为并不必要那么3个构造函数,所以用四个都得以。
生成的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值。由此得以测算出,更加多的歧异应该是在蓝图虚拟机的一对落成的,该部分文化以往介绍蓝图的时候再斟酌。
末段,把1性情格和2个办法添加进UClass中,齐活收工。

总结

本篇篇幅较长,大家花了大气的叙述演讲UHT生成的代码的体制。首先从1个最简便易行的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深刻学习QQ群:456247757(非新手入门群,请先读书完官方文书档案和录像教程)
微信公众号:aboutue,关于UE的整套音讯资源音信、技巧问答、小说表露,欢迎关注。
个人原创,未经授权,谢绝转发!

相关文章

发表评论

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

网站地图xml地图