当前位置: 首页 > wzjs >正文

日志网站系统营销技巧美剧

日志网站系统,营销技巧美剧,微信小程序怎么做会员卡,网站建设网店名字UE5反射系统分析(一)generated.h GENERATED_BODYenumstructclassinterface总结Reference UE5的反射系统代码相比于UE4有不少改动。最近在阅读UE4反射系统分析的相关文章的同时,参照UE5的代码,分析UE5的反射系统实现,正…

UE5反射系统分析(一)generated.h

  • GENERATED_BODY
  • enum
  • struct
  • class
  • interface
  • 总结
  • Reference

UE5的反射系统代码相比于UE4有不少改动。最近在阅读UE4反射系统分析的相关文章的同时,参照UE5的代码,分析UE5的反射系统实现,正好也能进一步消化和理解这一套框架的思想。
我们先把最常用的几种类型,以最简单的形式,放在一个文件MyClass.h里。

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "MyClass.generated.h"UENUM()
enum class EMyEnum : uint8
{MY_Dance,MY_Rain,MY_Song
};USTRUCT()
struct REFLECTION_API FMyStruct
{GENERATED_BODY()
};UCLASS()
class REFLECTION_API UMyClass : public UObject
{GENERATED_BODY()
};UINTERFACE()
class UMyInterface : public UInterface
{GENERATED_BODY()
};class REFLECTION_API IMyInterface
{GENERATED_BODY()
};

众所周知,UE会根据代码中的宏,自动生成反射代码,可以在项目的Intermediate\Build\Win64\UnrealEditor\Inc\Reflection\UHT目录下找到生成的文件,可以看到有两个文件,分别是MyClass.genertated.hMyClass.gen.cpp。这两个文件中的代码很多,我们先不急着看,先从我们自己写的MyClass.h看起,再一路顺藤摸瓜。

GENERATED_BODY

GENERATED_BODY()宏通常放在类的定义中,表示该类需要参与UE的反射系统。这个宏定义在ObjectMacros.h中:

// This pair of macros is used to help implement GENERATED_BODY() and GENERATED_USTRUCT_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);

可以看出,这个宏的作用就是将CURRENT_FILE_ID,当前文件的ID,和当前行号__LINE__以及后缀_GENERATED_BODY组合成一个唯一的标识符。这个标识符在生成的代码中会被用来区分不同的类型。既然是文件ID了,那么它的值应该在MyClass.generated.h中就能找到。

#undef CURRENT_FILE_ID
#define CURRENT_FILE_ID FID_Projects_Reflection_Source_Reflection_MyClass_h

MyClass.h中有4个GENERATED_BODY()宏,分别在FMyStructUMyClassUMyInterfaceIMyInterface中。在MyClass.generated.h中可以看到这四个宏被替换成了:

#define FID_Projects_Reflection_Source_Reflection_MyClass_h_20_GENERATED_BODY
#define FID_Projects_Reflection_Source_Reflection_MyClass_h_26_GENERATED_BODY
#define FID_Projects_Reflection_Source_Reflection_MyClass_h_32_GENERATED_BODY
#define FID_Projects_Reflection_Source_Reflection_MyClass_h_37_GENERATED_BODY

而且,这4个宏的定义还不太一样:

#define FID_Projects_Reflection_Source_Reflection_MyClass_h_20_GENERATED_BODY \friend struct Z_Construct_UScriptStruct_FMyStruct_Statics; \static class UScriptStruct* StaticStruct();#define FID_Projects_Reflection_Source_Reflection_MyClass_h_26_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \FID_Projects_Reflection_Source_Reflection_MyClass_h_26_INCLASS_NO_PURE_DECLS \FID_Projects_Reflection_Source_Reflection_MyClass_h_26_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS#define FID_Projects_Reflection_Source_Reflection_MyClass_h_32_GENERATED_BODY \PRAGMA_DISABLE_DEPRECATION_WARNINGS \FID_Projects_Reflection_Source_Reflection_MyClass_h_32_GENERATED_UINTERFACE_BODY() \FID_Projects_Reflection_Source_Reflection_MyClass_h_32_ENHANCED_CONSTRUCTORS \
private: \PRAGMA_ENABLE_DEPRECATION_WARNINGS#define FID_Projects_Reflection_Source_Reflection_MyClass_h_37_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \FID_Projects_Reflection_Source_Reflection_MyClass_h_32_INCLASS_IINTERFACE_NO_PURE_DECLS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGS

可见,反射系统需要先在头文件中插入一些生成代码,才能辅助UE得到各种类型的反射信息。不过enum似乎是一个例外,enum类型并不需要GENERATED_BODY()宏。那么enum类型应该是最简单得到,就先从它开始分析。

enum

MyClass.generated.h的结尾处,可以找到与enum相关的几行代码:

#define FOREACH_ENUM_EMYENUM(op) \op(EMyEnum::MY_Dance) \op(EMyEnum::MY_Rain) \op(EMyEnum::MY_Song) enum class EMyEnum : uint8;
template<> struct TIsUEnumClass<EMyEnum> { enum { Value = true }; };
template<> REFLECTION_API UEnum* StaticEnum<EMyEnum>();

FOREACH_ENUM_XXX是一个UE生成的辅助宏,用于遍历枚举类型的所有值。它的参数op是一个宏参数,表示对每个枚举值执行的操作。在UE源代码中也可以找到这个宏的实际用例:

// Texture.cpp
#ifndef CASE_ENUM_TO_TEXT
#define CASE_ENUM_TO_TEXT(txt) case txt: return TEXT(#txt);
#endifconst TCHAR* UTexture::GetTextureGroupString(TextureGroup InGroup)
{switch (InGroup){FOREACH_ENUM_TEXTUREGROUP(CASE_ENUM_TO_TEXT)}return TEXT("TEXTUREGROUP_World");
}

通过该宏可以方便地把enum的名称转换为字符串。

TIsUEnumClass就是一个模板类,用于判断一个类型是否是UE的枚举类型。它的Value成员变量为true表示是枚举类型。
StaticEnum就是负责获取enum类型反射信息的最终函数,它的实现在MyClass.gen.cpp中:

static FEnumRegistrationInfo Z_Registration_Info_UEnum_EMyEnum;
static UEnum* EMyEnum_StaticEnum()
{if (!Z_Registration_Info_UEnum_EMyEnum.OuterSingleton){Z_Registration_Info_UEnum_EMyEnum.OuterSingleton = GetStaticEnum(Z_Construct_UEnum_Reflection_EMyEnum, (UObject*)Z_Construct_UPackage__Script_Reflection(), TEXT("EMyEnum"));}return Z_Registration_Info_UEnum_EMyEnum.OuterSingleton;
}
template<> REFLECTION_API UEnum* StaticEnum<EMyEnum>()
{return EMyEnum_StaticEnum();
}

可以看到,StaticEnum函数会调用GetStaticEnum函数来获取枚举类型的反射信息,这个函数内部是一个static变量的惰性初始化,只有第一次调用时会创建一个UEnum对象,并将其存储在OuterSingleton中。之后的调用就直接返回这个对象。具体UEnum对象的创建流程,我们先放到后面再说。

struct

MyClass.generated.h中与FMyStruct相关的代码如下:

#define FID_Projects_Reflection_Source_Reflection_MyClass_h_20_GENERATED_BODY \friend struct Z_Construct_UScriptStruct_FMyStruct_Statics; \static class UScriptStruct* StaticStruct();template<> REFLECTION_API UScriptStruct* StaticStruct<struct FMyStruct>();

相较于enum,UE还为struct生成了成员函数版本的StaticStruct,在MyClass.gen.cpp中可以看到模板函数的版本实际上调用的也是成员函数版本:

static FStructRegistrationInfo Z_Registration_Info_UScriptStruct_MyStruct;
class UScriptStruct* FMyStruct::StaticStruct()
{if (!Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton){Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton = GetStaticStruct(Z_Construct_UScriptStruct_FMyStruct, (UObject*)Z_Construct_UPackage__Script_Reflection(), TEXT("MyStruct"));}return Z_Registration_Info_UScriptStruct_MyStruct.OuterSingleton;
}
template<> REFLECTION_API UScriptStruct* StaticStruct<FMyStruct>()
{return FMyStruct::StaticStruct();
}

StaticStruct的实现与StaticEnum类似,也是通过GetStaticStruct函数来获取结构体的反射信息。这个函数同样是一个static变量的惰性初始化,第一次调用时会创建一个UScriptStruct对象,并将其存储在OuterSingleton中。

class

UMyClass相关的代码就比较多了:

#define FID_Projects_Reflection_Source_Reflection_MyClass_h_26_INCLASS_NO_PURE_DECLS \
private: \static void StaticRegisterNativesUMyClass(); \friend struct Z_Construct_UClass_UMyClass_Statics; \
public: \DECLARE_CLASS(UMyClass, UObject, COMPILED_IN_FLAGS(0), CASTCLASS_None, TEXT("/Script/Reflection"), NO_API) \DECLARE_SERIALIZER(UMyClass)#define FID_Projects_Reflection_Source_Reflection_MyClass_h_26_ENHANCED_CONSTRUCTORS \/** Standard constructor, called after all reflected properties have been initialized */ \NO_API UMyClass(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \
private: \/** Private move- and copy-constructors, should never be used */ \UMyClass(UMyClass&&); \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) \NO_API virtual ~UMyClass();#define FID_Projects_Reflection_Source_Reflection_MyClass_h_23_PROLOG
#define FID_Projects_Reflection_Source_Reflection_MyClass_h_26_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \FID_Projects_Reflection_Source_Reflection_MyClass_h_26_INCLASS_NO_PURE_DECLS \FID_Projects_Reflection_Source_Reflection_MyClass_h_26_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGStemplate<> REFLECTION_API UClass* StaticClass<class UMyClass>();

对于class类型,UE生成的代码包含了更多的宏定义。首先是StaticRegisterNativesUMyClass,这个函数在MyClass.gen.cpp中实现:

void UMyClass::StaticRegisterNativesUMyClass()
{
}

这里似乎很奇怪,它居然是一个空函数,不过其实这个函数是负责注册类的成员函数,由于这里的class是空类,所以才是空函数。
接下来的DECLARE_CLASSDECLARE_SERIALIZER是UE定义在引擎中的宏。DECLARE_CLASS宏定义了类的各种信息,最常用到的StaticClass就在其中,而DECLARE_SERIALIZER宏则用于定义该类的序列化支持。

StaticClass的实现同样也是利用了惰性初始化,只不过这次是存储在InnerSingleton中:

#define IMPLEMENT_CLASS_NO_AUTO_REGISTRATION(TClass) \FClassRegistrationInfo Z_Registration_Info_UClass_##TClass; \UClass* TClass::GetPrivateStaticClass() \{ \if (!Z_Registration_Info_UClass_##TClass.InnerSingleton) \{ \/* this could be handled with templates, but we want it external to avoid code bloat */ \GetPrivateStaticClassBody( \StaticPackage(), \(TCHAR*)TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0), \Z_Registration_Info_UClass_##TClass.InnerSingleton, \StaticRegisterNatives##TClass, \sizeof(TClass), \alignof(TClass), \TClass::StaticClassFlags, \TClass::StaticClassCastFlags(), \TClass::StaticConfigName(), \(UClass::ClassConstructorType)InternalConstructor<TClass>, \(UClass::ClassVTableHelperCtorCallerType)InternalVTableHelperCtorCaller<TClass>, \UOBJECT_CPPCLASS_STATICFUNCTIONS_FORCLASS(TClass), \&TClass::Super::StaticClass, \&TClass::WithinClass::StaticClass \); \} \return Z_Registration_Info_UClass_##TClass.InnerSingleton; \}

再往下,就是和构造函数相关的宏了。首先,纳入UE反射系统的类默认构造函数和拷贝构造函数都是private的,只有一个public的接受const FObjectInitializer&参数的构造函数。这个函数的实现就是调用了基类的构造函数:

UMyClass::UMyClass(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {}

也就是说,如果使用的是GENERATED_BODY,我们没有办法实现对象的构造函数,也就没办法调用自定义的逻辑。

interface

与class类似,interface的生成代码也比较多:

#define FID_Projects_Reflection_Source_Reflection_MyClass_h_32_ENHANCED_CONSTRUCTORS \/** Standard constructor, called after all reflected properties have been initialized */ \NO_API UMyInterface(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); \
private: \/** Private move- and copy-constructors, should never be used */ \UMyInterface(UMyInterface&&); \UMyInterface(const UMyInterface&); \
public: \DECLARE_VTABLE_PTR_HELPER_CTOR(NO_API, UMyInterface); \DEFINE_VTABLE_PTR_HELPER_CTOR_CALLER(UMyInterface); \DEFINE_ABSTRACT_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(UMyInterface) \NO_API virtual ~UMyInterface();#define FID_Projects_Reflection_Source_Reflection_MyClass_h_32_GENERATED_UINTERFACE_BODY() \
private: \static void StaticRegisterNativesUMyInterface(); \friend struct Z_Construct_UClass_UMyInterface_Statics; \
public: \DECLARE_CLASS(UMyInterface, UInterface, COMPILED_IN_FLAGS(CLASS_Abstract | CLASS_Interface), CASTCLASS_None, TEXT("/Script/Reflection"), NO_API) \DECLARE_SERIALIZER(UMyInterface)#define FID_Projects_Reflection_Source_Reflection_MyClass_h_32_GENERATED_BODY \PRAGMA_DISABLE_DEPRECATION_WARNINGS \FID_Projects_Reflection_Source_Reflection_MyClass_h_32_GENERATED_UINTERFACE_BODY() \FID_Projects_Reflection_Source_Reflection_MyClass_h_32_ENHANCED_CONSTRUCTORS \
private: \PRAGMA_ENABLE_DEPRECATION_WARNINGS#define FID_Projects_Reflection_Source_Reflection_MyClass_h_32_INCLASS_IINTERFACE_NO_PURE_DECLS \
protected: \virtual ~IMyInterface() {} \
public: \typedef UMyInterface UClassType; \typedef IMyInterface ThisClass; \virtual UObject* _getUObject() const { return nullptr; }#define FID_Projects_Reflection_Source_Reflection_MyClass_h_29_PROLOG
#define FID_Projects_Reflection_Source_Reflection_MyClass_h_37_GENERATED_BODY \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \FID_Projects_Reflection_Source_Reflection_MyClass_h_32_INCLASS_IINTERFACE_NO_PURE_DECLS \
private: \
PRAGMA_ENABLE_DEPRECATION_WARNINGStemplate<> REFLECTION_API UClass* StaticClass<class UMyInterface>();

大部分内容和class差不多,我们从DECLARE_CLASS的传参中可以推断出一些参数的含义,例如第二个参数UInterface表示它是UMyInterface的基类,而第三个参数COMPILED_IN_FLAGS(CLASS_Abstract | CLASS_Interface)则表示这是一个抽象类和接口类。

总结

我们大致分析了generated.h中的生成代码,对代码中的不同宏和函数有了一个初步的了解。接下来,我们需要深入到MyClass.gen.cpp中,看看它们的具体实现,以及在反射系统中的用途,和调用的时机。

Reference

[1] 《InsideUE4》UObject(三)类型系统设定和结构

[2] UE5反射系统笔记(一)

[3] 深入研究虚幻4反射系统实现原理(一)

[4] UE 反射实现分析:反射代码生成(一)

[5] UObject 的 FObjectInitializer 构造函数的调用

http://www.dtcms.com/wzjs/106960.html

相关文章:

  • 网站改版做301是啥意思 换域名广告软文代理平台
  • 宁波做微信网站郑州网站seo
  • 网站建设需要学些什么百度付费问答平台
  • 湖州市住房和城乡建设局官方网站学seo推广
  • 淮安建设网站制作泰州网站排名seo
  • 建设一个网站的技术可行性研究营销活动有哪些
  • 赣榆区城乡建设局网站汽车网站建设方案
  • 网站开发会计科目百度地图关键词排名优化
  • 网站开发众包平台对搜索引擎优化的认识
  • wordpress多站点建站开鲁seo服务
  • 网站建设电话营销百度百家
  • 网站开发一般采用什么框架网站seo诊断优化方案
  • 电商网站的在线客服怎么做seo优化排名方法
  • 即墨网站建设即墨seo优化推广
  • 如何增加网站反链百度推广时间段在哪里设置
  • 徐州做网站的公司哪家好百度在线客服中心
  • 免费自制安卓app软件百度地图关键词排名优化
  • 南昌网站建设公司排行榜前十企业网络的组网方案
  • 自己做的网站 360不兼容seo网络推广技术
  • 新河网站建设最有效的app推广方式有哪些
  • 专门做照片的网站信息流广告加盟代理
  • 网站建设的切片是什么危机公关处理
  • 画品展现手机网站广州百度推广客服电话多少
  • 天津做网站的公司有哪些上海最新疫情
  • 网站的原型图互联网优化是什么意思
  • 1 建设网站目的2022百度收录越来越难了
  • 仿珠宝首饰网站开发关键词优化策略有哪些
  • 做网站的设计尺寸百度建立自己的网站
  • 腾讯云10g数字盘做网站够么搜索引擎 磁力吧
  • wordpress配适手机seo sem