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

UE5 反射系统

UE5 反射系统详解

目录
  • UE5 反射系统详解
    • 一、什么是反射系统?
    • 二、核心机制:UHT + 宏标记
      • 2.1 UHT(Unreal Header Tool)
      • 2.2 核心宏
    • 三、运行时类型系统:UClass / UStruct / UEnum
      • 3.1 UClass
      • 3.2 CDO(Class Default Object)
    • 四、属性遍历(运行时读写属性)
    • 五、函数调用(运行时动态调用 UFUNCTION)
    • 六、类型检查与转换
    • 七、UPROPERTY 修饰符详解
    • 八、反射与垃圾回收的关系
    • 九、总结


一、什么是反射系统?

在 C++ 中,语言本身不提供运行时类型信息(RTTI)的完整支持,无法在运行时获取一个类有哪些属性、哪些方法、属性叫什么名字、类型是什么等信息。

UE5 自己实现了一套完整的运行时反射系统,核心能力包括:

  • 运行时获取类的属性、方法、类型信息
  • 支持序列化 / 反序列化(存档、网络同步)
  • 支持蓝图与 C++ 互通
  • 支持垃圾回收(GC)追踪 UObject 引用
  • 支持编辑器属性面板(Details Panel)自动显示

二、核心机制:UHT + 宏标记

UE5 反射系统的实现分两个阶段:编译前预处理运行时访问

2.1 UHT(Unreal Header Tool)

UHT 是 UE 的代码生成工具,在正式编译 C++ 之前运行。

流程如下:

你写的 .h 文件↓ UHT 扫描宏标记
生成 xxx.generated.h 和 xxx.gen.cpp↓ 一起参与 C++ 编译
最终二进制包含完整反射数据

每个启用反射的头文件末尾必须包含:

#include "MyClass.generated.h"  // UHT 生成的文件,必须是最后一个 include

2.2 核心宏

用途
UCLASS() 标记一个类参与反射
USTRUCT() 标记一个结构体参与反射
UENUM() 标记一个枚举参与反射
UPROPERTY() 标记一个成员变量参与反射
UFUNCTION() 标记一个成员函数参与反射
GENERATED_BODY() 插入 UHT 生成的模板代码(必须写在类体最开头)

示例:

UCLASS(BlueprintType, Blueprintable)
class MYGAME_API AMyActor : public AActor
{GENERATED_BODY()public:// 暴露给蓝图读写,并在编辑器面板显示UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")float Health;// 暴露给蓝图调用UFUNCTION(BlueprintCallable, Category = "Stats")void TakeDamage(float Amount);
};

三、运行时类型系统:UClass / UStruct / UEnum

UHT 生成的数据最终以 UClassUScriptStructUEnum 等对象的形式存在于内存中,这些对象本身也是 UObject

3.1 UClass

每个 UCLASS 标记的类,在运行时都对应一个 UClass 实例:

// 获取 UClass 对象
UClass* ClassInfo = AMyActor::StaticClass();// 运行时动态获取(从实例)
UClass* ClassInfo = SomeActor->GetClass();// 打印类名
UE_LOG(LogTemp, Log, TEXT("Class: %s"), *ClassInfo->GetName());

UClass 内部存储了:

  • 所有 UPROPERTY → 以 FProperty 链表形式存储
  • 所有 UFUNCTION → 以 UFunction 对象存储
  • 父类指针(支持继承链查询)
  • CDO(Class Default Object,类默认对象)

3.2 CDO(Class Default Object)

每个 UCLASS 都有一个 CDO,是该类在引擎启动时创建的默认实例,用于:

  • 存储属性默认值
  • 序列化时做差量存储(只保存与 CDO 不同的部分)
  • 编辑器中"重置为默认值"的数据来源
AMyActor* CDO = GetDefault<AMyActor>();
UE_LOG(LogTemp, Log, TEXT("Default Health: %f"), CDO->Health);

四、属性遍历(运行时读写属性)

反射系统最实用的能力之一:在不知道具体类型的情况下,遍历和读写属性

void PrintAllProperties(UObject* Obj)
{UClass* Class = Obj->GetClass();// 遍历所有 UPROPERTYfor (TFieldIterator<FProperty> It(Class); It; ++It){FProperty* Prop = *It;FString PropName = Prop->GetName();// 以 float 为例,读取属性值if (FFloatProperty* FloatProp = CastField<FFloatProperty>(Prop)){float Value = FloatProp->GetPropertyValue_InContainer(Obj);UE_LOG(LogTemp, Log, TEXT("%s = %f"), *PropName, Value);}}
}

常用的 FProperty 子类:

类型 对应 FProperty 子类
float FFloatProperty
int32 FIntProperty
FString FStrProperty
bool FBoolProperty
UObject* FObjectProperty
TArray<> FArrayProperty
TMap<> FMapProperty

五、函数调用(运行时动态调用 UFUNCTION)

// 按名字找到函数
UFunction* Func = Obj->FindFunction(FName("TakeDamage"));if (Func)
{// 构造参数结构体(内存布局必须与函数签名匹配)struct FParams{float Amount;};FParams Params { 50.0f };Obj->ProcessEvent(Func, &Params);
}

ProcessEvent 是 UE 反射系统调用函数的底层入口,蓝图调用 C++ 函数、RPC 网络调用本质上都走这条路。


六、类型检查与转换

UE 提供了自己的类型转换,不推荐用原生 dynamic_cast

// 安全向下转型(失败返回 nullptr)
AMyActor* MyActor = Cast<AMyActor>(SomeActor);// 判断是否是某个类或其子类
if (SomeActor->IsA(AMyActor::StaticClass()))
{// ...
}// 判断两个 UClass 的继承关系
bool bIsChild = ChildClass->IsChildOf(ParentClass);

七、UPROPERTY 修饰符详解

UPROPERTY 的修饰符控制了属性的可见性、可编辑性、蓝图访问权限、网络同步等行为:

UPROPERTY(EditAnywhere,        // 在任何地方的 Details 面板可编辑BlueprintReadWrite,  // 蓝图可读可写Replicated,          // 网络同步Category = "Combat", // 编辑器分类meta = (ClampMin = "0.0", ClampMax = "100.0")  // 元数据限制
)
float Health;

常用修饰符速查:

修饰符 含义
EditAnywhere 原型和实例都可在编辑器编辑
EditDefaultsOnly 只能在原型(CDO)编辑
EditInstanceOnly 只能在场景实例编辑
VisibleAnywhere 编辑器只读显示
BlueprintReadWrite 蓝图可读写
BlueprintReadOnly 蓝图只读
Replicated 网络同步
Transient 不序列化(不存档)
SaveGame 参与存档系统

八、反射与垃圾回收的关系

UE 的 GC 依赖反射系统追踪 UObject 引用:

  • 只有被 UPROPERTY 标记的 UObject* 指针,GC 才能感知到引用关系
  • 裸指针(没有 UPROPERTY)不会被 GC 追踪,对象可能被回收导致野指针
// ❌ 危险:GC 不追踪这个指针,对象可能被回收
UMyObject* RawPtr;// ✅ 安全:GC 追踪此引用,对象存活
UPROPERTY()
UMyObject* SafePtr;

九、总结

宏标记(UCLASS/UPROPERTY/UFUNCTION)↓UHT 预处理↓生成反射元数据(.gen.cpp)↓
运行时 UClass / FProperty / UFunction 对象↓
支撑:蓝图互通 / 编辑器面板 / 序列化 / GC / 网络同步 / 动态调用

UE5 的反射系统是整个引擎的基础设施,理解它能帮助你更好地理解蓝图原理、网络同步、存档系统、编辑器扩展等几乎所有上层系统的工作方式。

http://www.jsqmd.com/news/651966/

相关文章:

  • 突破Linux无线网络困局:Realtek 8851BE驱动深度调优指南
  • 别再混淆了!一文搞懂AUTOSAR DEM中SWC与BSW报故障的区别(Dem_SetEventStatus vs Dem_ReportErrorStatus)
  • 智慧农业怎么选?新手不踩坑指南
  • DownKyi实战手册:解锁B站视频下载的完整工作流
  • HDU-3367 Pseudoforest
  • 5分钟掌握CaptfEncoder V3:跨平台网络安全工具套件实战指南
  • 3分钟极速安装!终极免费GitHub加速插件完整使用指南
  • 3个高效使用bilibili-api-python的进阶技巧:解决你的B站数据获取难题
  • 从华科期末考到机器学习:矩阵论里的奇异值分解(SVD)到底怎么用?
  • 从自行车变速到无人机飞控:聊聊‘转动惯量’这个参数在工程设计中到底有多重要
  • Kuikly 上手成本分析:面向跨平台框架选型的开发者指南 - 领先技术探路人
  • 目前最新可用claude code 亲自手动实操步骤
  • 第二十八天(4.16)
  • STM32光敏传感器实战:从硬件连接到智能控制
  • 绝地求生压枪宏终极指南:5分钟实现零后坐力稳定射击
  • 艾体宝干货|主流开源许可证解析
  • 在ruoyi vue实现后端单表user的CURD功能
  • 【QA】Word数学符号输入技巧:如何在字母上方添加小尖儿(^)
  • 生成式AI应用评测进入“后SITS时代”?2026版新增动态对抗测试、多轮意图漂移追踪、供应链溯源评分——仅限首批认证机构解密
  • NFC技术解析:从基础原理到实际应用
  • Qwen3.5-4B-Claude-GGUF新手教程:中文问答/代码生成/分步解题三大核心功能
  • 机器学习之超参数是什么?
  • 范式跃迁与价值重构:2026年人工智能发展的独到思考与实践路径
  • 【2026奇点智能技术大会权威内参】:AI学习助手的5大颠覆性能力与3个月落地实操路径
  • 保姆级教程:手把手调试高通CamX相机驱动的Open与Initialize流程(附Log分析)
  • 标注成本飙升300%?多模态数据标注流水线重构指南,6步实现人工标注量下降65%、模型收敛加速2.8倍
  • Golang怎么用go-noescape优化性能_Golang如何使用编译器指令控制逃逸分析行为【进阶】
  • 为什么92%的游戏AI团队还没跨过“多模态融合”门槛?奇点大会首席科学家亲授3步通关路径
  • 从Token级溯源到业务指标归因,生成式AI应用全链路追踪的5层黄金监控栈,92%团队尚未部署
  • 【企业级生成式AI集群治理白皮书】:基于27家头部客户实测数据,定义多集群SLA黄金标准