目录一常用UEC变量类型二理解UBT/UHT三反射系统关键宏用于生成用于调用运行时四UClassFPropertyUFunction一常用UEC变量类型// 基础类型 bool bool_val 1; uint8 byte_val 255; int32 int32_val -32; int64 int64_val -64; double double_val 3.14; // UE_LOG 的第 3 个参数Format必须是格式化字符串字面量便于编译时检查及节省运行时开销 UE_LOG(LogTemp, Error, TEXT(%d), bool_val); UE_LOG(LogTemp, Warning, TEXT(%d), byte_val); UE_LOG(LogTemp, Warning, TEXT(%d), int32_val); UE_LOG(LogTemp, Display, TEXT(%d), int64_val); UE_LOG(LogTemp, Display, TEXT(%f), double_val);// 字符串类型 FString str TEXT(FString!); //内部是TArrayTCHAR的封装并重载了operator*() FName name TEXT(FName!); FText text FText::FromString(TEXT(FText!)); UE_LOG(LogTemp, Display, TEXT(%s), *str); UE_LOG(LogTemp, Display, TEXT(%s), *name.ToString()); UE_LOG(LogTemp, Display, TEXT(%s), *text.ToString());// 容器类型 TArrayint32 arr { 1,2,3,4,5 }; TSetint32 set { 10,20,30,40,50 }; TMapint32, FString map { {1, TEXT(one)}, {2, TEXT(two)} }; FString arr_ret; for (auto num : arr) arr_ret FString::FromInt(num) TEXT( ); GEngine-AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, arr_ret); FString set_ret; for (auto num : set) set_ret FString::FromInt(num) TEXT( ); GEngine-AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, set_ret); FString map_ret; for (auto num : map) map_ret num.Value TEXT( ); GEngine-AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, map_ret);// 在.h头文件中定义一个跨文件/全局的自定义日志类别 // 声明.h 中必须和定义.cpp 中配对使用否则链接会报错; // .cpp文件定义 DEFINE_LOG_CATEGORY(MyCategory); DECLARE_LOG_CATEGORY_EXTERN(MyCategory, Log, All); // 在.cpp源文件中定义一个仅当前文件可见静态的自定义日志类别 DEFINE_LOG_CATEGORY_STATIC(LogBlankProgram, Log, All); // MyCategory自定义类别名 // Log运行时的默认详细级别枚举ELogVerbosity // Fatal致命错误触发断点/崩溃 // Error严重问题程序能跑打印红色文字 // Warning警告/潜在问题不影响主流程打印黄色文字 // Display显示 // Log普通日志 // Verbose详解日志 // VeryVerbose极详细日志 // All编译时过滤级别相当于总开关与上一参数一样 // NoLogging不输出日志 // All保留所有日志等同于 VeryVerbose二理解UBT/UHTUBTUnreal Build Tool 虚幻编译工具负责管理整个编译流程包括收集所需编译的模块、处理依赖关系、调用 UHT最后再调用标准的 C 编译器如 MSVC完成最终编译UHTUnreal Header Tool预处理负责解析头文件中的特殊宏如UCLASS(),UFUNCTION()等读取为 UObject 系统添加的“元数据”并自动生成*.generated.h和*.gen.cpp等中间代码从而支持反射、蓝图调用等功能点击编译 │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 1. UBT (Unreal Build Tool) 启动 │ │ - 读取 .uproject 文件获取项目信息 │ │ - 读取 Target.cs 和所有模块的 Build.cs 文件 │ │ - 构建完整的模块依赖关系图包括引擎模块和游戏模块 │ │ - 基于时间戳和依赖关系判断哪些源文件需要重新编译 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 2. UBT 调用 UHT (Unreal Header Tool) │ │ - 扫描所有需要反射的头文件 (.h) │ │ - 识别 UCLASS, USTRUCT, UFUNCTION, UPROPERTY 等宏 │ │ - 验证反射规范的合法性如 UFUNCTION 必须在 UCLASS 内等 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 3. UHT 生成反射所需的中间代码 │ │ - 为每个反射类型生成 .generated.h 文件供其他文件包含 │ │ - 生成 .gen.cpp 文件包含 │ │ • 静态反射数据表如 UClass 的初始化结构 │ │ • 属性UPROPERTY的序列化/反序列化代码 │ │ • 函数UFUNCTION的参数封包RPC 或蓝图调用代码 │ │ - 所有中间文件输出到 Intermediate 文件夹 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 4. UBT 准备编译环境 │ │ - 生成编译命令行参数优化级别、调试信息等 │ │ - 设置包含目录Include Paths包括生成的 Intermediate 目录│ │ - 配置预处理器宏如 _DEBUG, _EDITOR 等 │ │ - 确定编译配置Debug / Development / Shipping │ │ - 可选生成预编译头PCH以加速编译 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 5. UBT 调用底层编译器MSVC / Clang │ │ - 编译所有 .cpp 源文件包括原始代码和 .gen.cpp │ │ - 输出 .obj 目标文件 │ │ - 将 .obj 文件链接成动态库.dll或可执行文件.exe │ │ - 若为模块生成对应的 .module 文件用于模块管理 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 6. UBT 处理编译输出 │ │ - 将生成的 .dll / .exe 复制到项目的 Binaries 目录 │ │ - 更新模块热重载信息如生成 .hotreload 文件供编辑器使用 │ │ - 若为游戏目标可能复制到最终打包目录 │ │ - 注意着色器编译由引擎资源系统在运行时或 Cook 时处理 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ 引擎可以运行新代码三反射系统反射是程序在运行时检查、访问和操作自身结构类、属性、函数等的能力其在UE中的主要用途编辑器交互最核心能直接在编辑器的Details面板里修改它的值无需任何额外代码如在UPROPERTY(EditAnywhere)蓝图与C交互可直接在蓝图节点中调用C函数如UFUNCTION(BlueprintCallable)反之C也能调用蓝图中实现的事件如BlueprintImplementableEvent序列化保存与加载保存游戏时反射系统能自动遍历对象上所有UPROPERTY()标记的变量把值写入磁盘加载时再自动恢复垃圾回收UPROPERTY()最重要的职责之一是阻止垃圾回收被标记的指针GC就知道“这是正在使用的”不会错误地清理掉防止内存泄漏和野指针的关键网络复制UPROPERTY(Replicated)可让某个属性在服务器和所有客户端之间自动同步省去了手写大量网络通信代码的麻烦注必须是UObject派生类完整的反射功能如垃圾回收只在继承自UObject的类上生效普通的C类不行关键宏// 创建新类型时“对外声明”告诉构建工具“该类需要被纳入反射系统”否则UBT在扫描头文件时会直接忽略该类不会为它生成 .generated.h 和 .gen.cpp 文件 // 可在其后附加说明符用于该类与引擎编辑器及蓝图系统的沟通交互如BlueprintableBlueprintTypemeta(...) // 标记类型错误如USTRUCT用在了UObject上UHT会编译错误 UCLASS()对继承自UObject的类反射提供完整反射支持如UFUNCTION、垃圾回收、网络复制等 USTRUCT()对普通C结构体轻量级反射支持UPROPERTY、序列化、蓝图作为数据类型但不支持函数暴露和垃圾回收 UENUM()对C枚举反射可在蓝图、编辑器下拉菜单和序列化中直接使用 UINTERFACE()接口类标记可被蓝图实现的接口必须配合GENERATED_BODY() // “对内填充”在类体内补齐必要的代码 // 提供必要的函数实现如StaticClass()返回本类专属的UClass指针必要的类型定义如Super GENERATED_BODY() // 对类型成员的反射标记需要进行反射的宏 // 必须用于被UCLASS或USTRUCT标记的类型内部成员 // 不可用于全局变量或全局函数也不可用于普通 C 类/结构体中 UPROPERTY()反射成员变量支持序列化、蓝图访问、网络复制等用于UCLASS/USTRUCT UFUNCTION()反射函数支持蓝图调用、网络远程调用、控制台命令等用于UCLASS/UINTERFACEUPROPERTY() FString GlobalName; // ❌ 错误全局变量不能用 class MyNormalClass { UPROPERTY() int Value; // ❌ 错误普通C类不能用 };// 定义一个蓝图可识别的类,引用类型,受垃圾回收GC管理 UCLASS() // ✅ 正确在UCLASS内部使用 class AMyActor : public AActor { GENERATED_BODY() UPROPERTY() int Score; UFUNCTION() void DoAction(); }; // 定义一个蓝图可识别的结构体,值类型,不受垃圾回收GC直接管理 // 可将.CSV文件导入UE并选择该结构体导入数据 USTRUCT(BlueprintType) // ✅ 正确在USTRUCT内部使用 struct FMyTable : public FTableRowBase { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite) FString Name; UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 Score; UPROPERTY(EditAnywhere, BlueprintReadWrite) float Num; }; // 定义一个蓝图可识别的枚举 UENUM(BlueprintType) enum class EMyEnum : uint8 { type1 UMETA(DisplayName 类型一), type2 UMETA(DisplayName 类型二), type3 UMETA(DisplayName 类型三) };用于生成UPROPERTY通过反射系统将对应属性暴露给蓝图// 编辑器可编辑性Edit / Visible UPROPERTY(VisibleAnywhere) // 始终可见但不可编辑只读显示实例和默认值均可见 UPROPERTY(VisibleDefaultsOnly) // 仅类默认值中可见只读 UPROPERTY(VisibleInstanceOnly) // 仅实例细节面板中可见只读 UPROPERTY(EditAnywhere) // 实例和类默认值蓝图/CDO均可编辑 UPROPERTY(EditDefaultsOnly) // 仅类默认值可编辑实例不可 UPROPERTY(EditInstanceOnly) // 仅实例细节面板可编辑类默认值不可// 蓝图访问控制Blueprint UPROPERTY(BlueprintReadWrite) // 蓝图可读写即可get/set UPROPERTY(BlueprintReadOnly) // 蓝图只读即只可get UPROPERTY(BlueprintGetter) // 指定一个自定义函数作为 Getter替代默认的读操作 UPROPERTY(BlueprintSetter) // 指定一个自定义函数作为 Setter替代默认的写操作// 资产与元数据 UPROPERTY(Category 名称) // 指定属性在编辑器 Details 面板中所属的分类 UPROPERTY(SimpleDisplay) // 优先显示在简单列表中而不是高级折叠页 UPROPERTY(AdvancedDisplay) // 默认折叠到“高级”区域 UPROPERTY(AssetRegistrySearchable) // 属性会加入资产注册表允许在内容浏览器中搜索// meta元数据说明符主要用于精细控制属性在编辑器、蓝图等环境中的显示与交互方式不影响核心逻辑只存在于编辑器环境中 UPROPERTY(meta (DisplayName xxx)) // 在编辑器中显示的名称而不是变量名 UPROPERTY(meta (EditCondition mybool)) // 只有在mybool变量为真时才可编辑 UPROPERTY(meta (ToolTip 角色的基础移动速度)) // 鼠标悬停时显示的提示文本 UPROPERTY(meta (meta (Category 移动属性)) // 将属性分组显示在细节面板的指定分类下 UPROPERTY(meta (ClampMin 0, ClampMax 100)) // 硬限制数值编辑范围仅对浮点和整数 UPROPERTY(meta (UIMin 0.0, UIMax 1.0)) // 软限制数值编辑范围仅对浮点和整数 UPROPERTY(meta (ArrayClamp MyArray)) // 限制数值在指定数组对整数 UPROPERTY(meta (AllowPrivateAccess true)) // 允许蓝图访问私有成员不推荐但有时有用// 网络复制Replication UPROPERTY(Replicated) // 属性会进行网络复制需在 GetLifetimeReplicatedProps 中注册 UPROPERTY(ReplicatedUsing) // 属性复制时会调用指定的回调函数通常在客户端执行// 序列化与持久化 UPROPERTY(SaveGame) // 属性会被包含在 SaveGame 存档系统中 UPROPERTY(Transient) // 属性不会被序列化保存/加载时忽略加载后为默认值 UPROPERTY(DuplicateTransient) // 复制Duplicate对象时此属性不会被复制到新对象 UPROPERTY(TextExportTransient) // 导出为文本如复制到剪贴板时忽略 UPROPERTY(NonTransactional) // 在编辑器中操作如移动、修改时不参与 Undo/Redo 系统// 实例化与引用 UPROPERTY(Instanced) // 对于 UObject* 或 TSubclassOf每个实例都会拥有自己独立的对象而不是共享默认对象 UPROPERTY(Ref) // 标记一个引用参数通常用于函数参数很少用在 UPROPERTY UPROPERTY(Export) // 将引用的对象作为子对象序列化内嵌而不是通过引用路径// 配置相关 UPROPERTY(Config) // 此属性可从配置文件*.ini读取/写入 UPROPERTY(GlobalConfig) // 类似 Config但保存在全局基类配置文件中不保存在子类 UPROPERTY(Localized) // 属性是本地化的UI 文本等// 其他实用说明符 UPROPERTY(Native) // 仅用于结构体标记为本地类型 UPROPERTY(NoClear) // 对象引用不能设置为 None必须总是有效UFUNCTION通过反射系统将对应函数暴露给蓝图// 蓝图交互 UFUNCTION(BlueprintCallable) // 蓝图可调用允许蓝图节点调用此C函数是暴露函数最常见的方式 UFUNCTION(BlueprintPure) // 蓝图纯函数无副作用在蓝图中不显示执行引脚直接连出数据const函数默认隐含此标记 UFUNCTION(BlueprintNativeEvent) // C默认实现C需在函数名后加_Implementation实现蓝图可重写重写后使用重写的内容 UFUNCTION(BlueprintImplementableEvent) // 纯蓝图实现C声明无实现完全由蓝图实现有返回值是函数无返回值的是事件// 网络与权限 UFUNCTION(NetMulticast) // 网络多播 UFUNCTION(Server) // 服务器执行 UFUNCTION(Client) // 客户端执行 UFUNCTION(Reliable / Unreliable) // 配合RPC使用保证/不保证网络调用必达; UFUNCTION(BlueprintAuthorityOnly) // 限制蓝图代码仅在拥有网络权限的机器上执行; UFUNCTION(BlueprintCosmetic) // 标记为装饰性函数在专用服务器上会被跳过;// 其他实用功能 UFUNCTION(Exec) // 将函数暴露为游戏内控制台命令 UFUNCTION(CallInEditor) // 在编辑器中选中对象便可在细节面板看到调用按钮; UFUNCTION(Category Name) // 在蓝图节点面板中为函数指定分类名称; UFUNCTION(meta (DisplayName...)) // 自定义函数在蓝图中的显示名称 UFUNCTION(BlueprintSetter) // 当蓝图修改特定UPROPERTY时关联并自动调用此函数;// MyClass.h UCLASS() class UMyClass : public UObject { GENERATED_BODY() public: // 1. 可在蓝图中调用的函数 UFUNCTION(BlueprintCallable, Category MyFunctions) void DoSomething(); // 2. 带默认实现但允许蓝图重写的函数 UFUNCTION(BlueprintNativeEvent, Category MyFunctions) int32 CalculateValue(int32 Input); // 需要额外实现 CalculateValue_Implementation // 3. 纯函数无副作用 UFUNCTION(BlueprintPure, Category MyFunctions) float GetHealthPercent() const; // 4. 在服务器上执行的 RPC 函数 UFUNCTION(Server, Reliable, WithValidation) void ServerDoAction(); // 需要额外实现 ServerDoAction_Implementation 和 ServerDoAction_Validate // 5. 控制台命令 UFUNCTION(Exec) void MyConsoleCommand(); };用于调用运行时在程序运行期间通过字符串名字或类型信息动态地查找、访问、调用对象的属性和方法主要用途运行时类型识别RTTI判断对象是否为某个类型或其子类MyActor-IsA(AActor::StaticClass())判断类之间的继承关系MyClass-IsChildOf(UObject::StaticClass())反射访问属性UPROPERTY通过FindPropertyByName获取FProperty描述符结合对象实例读写成员变量的值通过ContainerPtrToValuePtr或CopyCompleteValue反射调用函数UFUNCTION通过FindFunctionByName获取UFunction调用UObject::ProcessEvent动态执行函数支持参数和返回值动态创建对象NewObjectUObject(Outer, UClass*)创建任意UObject派生对象World-SpawnActorAActor(UClass*, ...)在关卡中生成Actor获取类默认对象CDOUClass::GetDefaultObject()返回该类的默认实例用途读取/修改类的默认属性值影响所有新实例比较对象属性是否与默认值不同用于网络同步、序列化差异快速获取类的一些静态配置支撑引擎底层系统序列化遍历UClass的所有UPROPERTY自动保存/加载网络复制标记Replicated的属性会通过UClass查找并同步垃圾回收通过UClass遍历对象引用的属性编辑器 Details 面板根据UClass中的属性元数据动态生成 UI蓝图虚拟机通过UClass查找函数并执行ProcessEvent反射入口 → UClass (StaticClass / GetClass) ↓ 属性FindPropertyByName → FProperty → ContainerPtrToValuePtr → 读写 函数FindFunctionByName → UFunction → ProcessEvent → 调用 类型IsA / IsChildOf 创建NewObject / SpawnActor// 获取 UClass元数据入口 T::StaticClass() // 获取已知 C 类 T 的 UClass编译期 UObject::GetClass() // 获取实例对象所属的 UClass运行时继承于UObject UClass* LoadClassUObject() // 加载蓝图类的全局模板函数只要指定类型UObject的子类即可// 读写属性UPROPERTY UClass::FindPropertyByName(FName(PropName)) // 按名称查找 FProperty TFieldIteratorFProperty // 遍历类的所有属性含继承 FProperty::ContainerPtrToValuePtrvoid(Object) // 获取对象中该属性的内存指针 FProperty::CopyCompleteValue(Dest, Src) // 复制属性值不关心类型 FProperty::GetValue_InContainer(Object, OutVal) // 读取属性值模板版 FProperty::SetValue_InContainer(Object, NewVal) // 设置属性值 FIntProperty::GetPropertyValue() // 获取FProperty的具体子类属性值 FIntProperty::SetPropertyValue() // 设置FProperty的具体子类属性值// 调用函数UFUNCTION UClass::FindFunctionByName(FName(FuncName)) // 按名称查找 UFunction TFieldIteratorUFunction // 遍历类的所有函数 UObject::ProcessEvent(UFunction*, void* Parms) // 执行函数支持参数/返回值 UFunction::Invoke(Object, Parms) // 另一个调用方式较少用// 动态创建对象 // 创建 UObject 派生对象只是创建一个变量全局模板函数 T* NewObjectT(Outer); T* NewObjectT(Outer, TEXT(Newname)); T* NewObjectT(Outer, UClass*) // 在世界中生成 Actor必须是 AActor 子类因为Actor具备世界空间坐标/生命周期管理接口由UWord定义 World-SpawnActorAActor(UClass*, FTransform, ...)// 类型判断与转换 UObject::IsA(UClass*) // 判断对象是否属于某类或子类继承于UObject UClass::IsChildOf(UClass*) // 判断类是否继承自另一个类 CastT(UObject*)/CastCheckedT // 安全转换编译期已知类型UObject及其子类 CastFieldT(FProperty*)/CastFieldCheckedT // 安全转换 FField 及其子类如 FProperty DynamicCastT(UObject*) // 运行时反射转换类似 Cast StaticClass()-IsChildOf(AActor::StaticClass()) // 类继承检查// 其他辅助 FindFieldFProperty(UClass*, FName) // 等价于 FindPropertyByName FindFieldUFunction(UClass*, FName) // 等价于 FindFunctionByName UClass::GetDefaultObject() // 获取类默认对象CDO UClass::GetSuperClass() // 获取父类 UObject::GetFName() // 获取对象名称可用于反射查找继承于UObject// 常用宏编译期帮助反射生成 GENERATED_BODY() // 必须在类声明中展开反射所需的代码 DECLARE_DYNAMIC_MULTICAST_DELEGATE(...) // 声明动态委托支持蓝图 DECLARE_FUNCTION // 自定义 UFUNCTION 底层极少用四UClass是描述一个 UObject 派生类元数据属性、函数、父类、大小等的核心类型是UE反射系统为每一个UCLASS即带有UCLASS()宏的 UObject 派生类自动生成的元数据类型继承链UObject - UField - UStruct - UClass可理解为C type_info的超级增强版——不仅包含类型名称、父类信息还存储了该类的所有属性UPROPERTY、函数UFUNCTION、以及用于序列化、网络复制、实例化等的额外数据该类型是引擎核心代码中已经写好的位于UObject.h/Class.h是UE中“类的类”提供了运行时对 C 类结构属性、函数、继承、默认值的完整描述和操作能力是反射、动态创建、编辑器集成等所有高级功能的基础每个 UObject 派生类都有一个唯一的 UClass 对象单例UClass 对象是模块加载时创建的其元数据内容由UHT生成提供基类的UClass与子类的UClass是两个完全独立、互不包含的UObject对象通过GetSuperClass()/SuperStruct获取父类UClass注UClass本身的UClass是其自身AMyActor 编译 | | UHT 扫描 .h 文件 | 生成 .generated.h 和 .gen.cpp | | .gen.cpp 中包含 | 1. 静态结构体TClassCompiledInDeferAMyActor 的实例 | 2. 该类的元数据属性名、偏移量、函数指针等 | ┌─────────────────────────────────────────────────────────────┐ │ 模块加载 / 热重载DLL 加载 | └─────────────────────────────────────────────────────────────┘ | | ① 静态对象 TClassCompiledInDeferAMyActor 的构造函数执行 | → 将类名、大小、CDO 创建函数指针等信息 | 添加到一个全局的“待注册类列表”中GetDeferredClassRegistration | | ② 模块加载完成后统一处理所有登记的类引擎调用 ProcessNewlyLoadedUObjects() | → 遍历全局“待注册类列表” | → 对每个类调用 UClass::CreateClass() | 生成UClass 对象分配内存存入元数据表 | ① 填充属性 (FProperty)、函数 (UFunction) 列表 | ② 链接父类 (UClass::Super) | ③ 将该 UClass* 注册到全局名称映射表 (GUObjectArray) | | UClass 准备就绪调用 UClass::CreateDefaultObject() | → 内部调用 StaticConstructObject_Internal | → 调用 AMyActor 的 C 构造函数FObjectInitializer.bIsCDO true | ├─ 初始化成员变量 | └─ CreateDefaultSubobject → NewObject(组件) ✅ 真正分配内存 | → 调用 PostInitProperties() | ├─ 将组件注册到 UClass 的子对象列表 | └─ 处理 config 文件覆盖 | 生成CDO 对象(Class Default Object) | ├─ 标记 RF_ClassDefaultObject加入 Root Set 防回收 | └─ 编辑器中修改 Class Defaults 即修改此 CDO 实例的属性值 | 运行时AMyActor* NewActor GetWorld()-SpawnActorAMyActor(...); | → SpawnActor 内部调用 UClass::GetDefaultObject()即 CDO | → 为 Actor 本体分配原始内存FMemory::Malloc | → 通过 memcpy 复制 CDO 的内存布局极快的浅拷贝 | → 再次调用 C 构造函数FObjectInitializer.bIsCDO false且携带 CDO 指针 | ├─ 修正虚表指针指向正确的子类虚函数表 | ├─ CreateDefaultSubobject → DuplicateObject(组件) ✅ 深拷贝组件 | └─ 基础类型变量不修正保持 memcpy 的值除非显式赋值 | → 调用 PostInitProperties() | ├─ 将深拷贝的组件注册到当前实例的 UObject 链表 | └─ 触发 OnSubobjectAdded编辑器感知 | → SpawnActor 后处理 | ├─ PostSpawnInitialize设置 Owner/Instigator执行碰撞调整 | └─ OnConstruction如果允许运行时构建 | → 将 Actor 添加到 World 的 Actor 数组开启 Tick 和复制同时建立 GC 引用链防止被回收 | 生成AMyActor 的运行时实例// 简化的 UStruct 源代码 class UStruct : public UField { private: TObjectPtrUStruct SuperStruct; public: TObjectPtrUField Children; FField* ChildProperties; int32 PropertiesSize; int16 MinAlignment; public: FProperty* PropertyLink; FProperty* RefLink; FProperty* DestructorLink; FProperty* PostConstructLink; public: UStruct(const FObjectInitializer ObjectInitializer); int32 GetPropertiesSize() const; int32 GetMinAlignment() const; UStruct* GetSuperStruct() const FTopLevelAssetPath GetStructPathName() const; FProperty* FindPropertyByName(FName InName) const; bool IsChildOf( const UStruct* SomeBase ) const; }// 简化的 UClass 源代码 class UClass : public UStruct // 继承自 UStruct继承 ChildProperties 链表 { public: // 继承自父类 UStruct // 记录所有UPROPERTY()标记的属性 FProperty* PropertyLink; // 从最高派生到基类的属性链表内存数据不会被序列化 // 记录所有UPROPERTY()标记的对象引用属性UObject/UObject*/TObjectPtrUObject等包含对象引用的属性阻止GC回收 FProperty* RefLink; // 从最高派生到基类的对象引用属性的链表内存数据不会被序列化 // 自身定义 EClassFlags ClassFlags; // 类标志枚举类型 TObjectPtrUObject ClassDefaultObject; // CDO类默认对象 TMapFName, TObjectPtrUFunction FuncMap; // 函数名 - UFunction 的哈希表快速查找 // ----- 构造 ----- UClass(const FObjectInitializer ObjectInitializer FObjectInitializer::Get()); explicit UClass(const FObjectInitializer ObjectInitializer, UClass* InSuperClass); // ----- 常用接口 ----- UClass* GetSuperClass() const { return (UClass*)GetSuperStruct(); } UObject* GetDefaultObject(bool bCreateIfNeeded true) const { return ClassDefaultObject; } FName GetDefaultObjectName() const; UObject* GetDefaultSubobjectByName(FName ToFind); void GetDefaultObjectSubobjects(TArrayUObject* OutDefaultSubobjects); EClassFlags GetClassFlags() const bool HasAnyClassFlags( EClassFlags FlagsToCheck ) const bool HasAllClassFlags( EClassFlags FlagsToCheck ) const // ----- 查找属性继承于UStruct ----- FProperty* UStruct::FindPropertyByName(FName InName) const { for (FProperty* Property PropertyLink; Property ! nullptr; Property Property-PropertyLinkNext) { if (Property-GetFName() InName) return Property; } return nullptr; } // ----- 查找函数沿继承链递归 ----- UFunction* FindFunctionByName(FName InName, EIncludeSuperFlag::Type IncludeSuper EIncludeSuperFlag::IncludeSuper) const; { if 如果排除父类或既没有接口也没有父类直接在当前类的 FuncMap 中查找 Result FuncMap.FindRef(InName); else 考虑接口和父类 先检查全局缓存 AllFunctionsCache 缓存未命中开始实际查找 在本类 FuncMap 中查找 本类未找到则遍历接口递归查找Interfaces 在父类 SuperClass 中递归查找 } };FPropertyFProperty是UE反射系统的核心用于描述一个类或结构体的成员变量从 UE 4.25 开始替代原有UProperty不再继承自UObject以降低内存和性能开销FProperty是所有属性类型的基类本身不存储属性的值只存储属性的元数据名称、类型、大小、偏移量、标志等FProperty是一个抽象基类对于每种基本数据类型都有具体的派生类来实现其特定行为class FField { FFieldClass* ClassPrivate; public: FFieldVariant Owner; FField* Next; FName NamePrivate; EObjectFlags FlagsPrivate; EObjectFlags GetFlags() const; FName GetFName() const; FString GetName() const; FFieldClass* GetClass() const; bool HasAnyFlags(EObjectFlags FlagsToCheck) const; bool HasAllFlags(EObjectFlags FlagsToCheck) const; bool IsA(const FFieldClass* FieldType) const; FString GetPathName(const UObject* StopOuter nullptr) const; void GetPathName(const UObject* StopOuter, FStringBuilderBase ResultString) const; FString GetFullName() const; FFieldVariant GetOwnerVariant() const }// 简易伪代码 (基于 UE 5.x) class FProperty : public FField { public: // ----- 元数据 ----- int32 ArrayDim; // 数组维度如果是静态数组 int32 ElementSize; // 单个元素的大小字节 EPropertyFlags PropertyFlags; // 属性标志 (如 UPROPERTY 的说明符) FProperty* PropertyLinkNext; // 从派生程度最高的属性到基类的属性链表 int32 Offset_Internal; ... // ----- 构造 ----- FProperty(FFieldVariant InOwner, const FName InName, EObjectFlags InObjectFlags); FProperty(FFieldVariant InOwner, const UECodeGen_Private::FPropertyParamsBaseWithOffset Prop, EPropertyFlags AdditionalPropertyFlags CPF_None); FProperty(FFieldVariant InOwner, const UECodeGen_Private::FPropertyParamsBaseWithoutOffset Prop, EPropertyFlags AdditionalPropertyFlags CPF_None); // ----- 常用方法 ----- // 继承自FField FName GetName() const; // 获取属性变量名称 FFieldClass* GetClass() const; // 获取属性类型描述FProperty类类似UClass描述UObject类 virtual FName GetID() const; // 获取所属类型的唯一ID标签名称 int32 GetElementSize() const; // 获取容器元素的大小 virtual bool SameType(const FProperty* Other) const; // 是否深度类型等价 // ----- 核心方法 ----- // 给定一个指向包含此属性的对象/结构体的指针 (Container)计算出此属性值的确切内存地址 templatetypename ValueType // UObject容器 ValueType* ContainerPtrToValuePtr(UObject* ContainerPtr, int32 ArrayIndex 0) const return (uint8*)ContainerPtr Offset_Internal static_castsize_t(GetElementSize()) * ArrayIndex; templatetypename ValueType //结构体等非UObject容器 ValueType* ContainerPtrToValuePtr(void* ContainerPtr, int32 ArrayIndex 0) const return (uint8*)ContainerPtr Offset_Internal static_castsize_t(GetElementSize()) * ArrayIndex; // 复制单个元素 (基类默认Memcpy派生类如FStringProperty重写为深拷贝) virtual void CopySingleValue(void* Dest, const void* Src) const; // 复制完整值 (自动处理 ArrayDim 1 的静态数组循环复制容器类型重写为深拷贝整个容器) virtual void CopyCompleteValue(void* Dest, const void* Src) const; // 在指定内存地址上构造默认值调用构造函数 virtual void InitializeValue(void* Dest) const; // 销毁指定内存地址的值调用析构函数 virtual void DestroyValue(void* Dest) const; ... };// 属性遍历 UObject* MyObject ...; // 获取其类的反射信息 UClass* MyClass MyObject-GetClass(); // 遍历该类及其父类的所有属性 for (TFieldIteratorFProperty It(MyClass); It; It) { FProperty* Property *It; // 1. 获取元数据 FString PropertyName Property-GetName(); FString PropertyType Property-GetClass()-GetName(); // 2. 获取属性值的内存地址 void* ValuePtr Property-ContainerPtrToValuePtrvoid(MyObject); // 3. 根据属性类型执行不同操作 if (FIntProperty* IntProp CastFieldFIntProperty(Property)) { int32 Value IntProp-GetPropertyValue(ValuePtr); // 处理 int32 值... } else if (FStrProperty* StrProp CastFieldFStrProperty(Property)) { FString Value StrProp-GetPropertyValue(ValuePtr); // 处理 FString 值... } // ... 处理其他类型 }UFunctionUFunction是UE中一个核心的类类型是 UE 反射系统可识别的 C 函数在引擎内部的运行时数据表示类似 C 函数的“元数据镜像”存储了函数的所有信息使得函数可在蓝图、网络通信、控制台等系统中被动态识别和调用核心作用蓝图调用网络复制class UFunction : public UStruct { public: EFunctionFlags FunctionFlags; // 函数标志位 uint8 NumParms; // 参数总数 uint16 ParmsSize; // 参数总大小 uint16 RPCId; // RPC ID uint16 ReturnValueOffset; // 返回值偏移 FProperty* FirstPropertyToInit; // 第一个本地结构体属性的指针 UFunction* EventGraphFunction; // 该函数调用的蓝图事件图表 private: FNativeFuncPtr Func; // 绑定到的C函数 // ---- 常用方法继承于UObject ---- FName GetName() const; // 获取函数名称 FFieldClass* GetClass() const; // 获取反射类信息 UObject* GetOuter() const; // 获取外部对象可选 // --- 核心方法 --- // 继承于UObject void ProcessEvent(UFunction* Function, void* Params) // 继承于UStruct FProperty* FindPropertyByName(FName PropName) const UFunction* GetSuperFunction() const; // 获取父函数 FProperty* GetReturnProperty() const; // 获取返回值属性 void Invoke(UObject* Obj, FFrame Stack, RESULT_DECL); // 在UObject上调用UFunction };// 查找函数并调用 UFunction* TargetFunc MyClass-FindFunctionByName(TEXT(MyFunction)); if (TargetFunc) { // 分配参数内存 uint8* Params (uint8*)FMemory_Alloca(TargetFunc-ParmsSize); FMemory::Memzero(Params, TargetFunc-ParmsSize); // 设置参数假设有一个 int 参数 Value if (FIntProperty* IntParam CastFieldFIntProperty(TargetFunc-FindPropertyByName(TEXT(Value)))) { int32 ValueToSet 42; IntParam-SetPropertyValue(IntParam-ContainerPtrToValuePtrvoid(Params), ValueToSet); } // 调用函数继承于UObject MyObject-ProcessEvent(TargetFunc, Params); // 如函数有返回值从 Params 中读取 if (FProperty* ReturnProp TargetFunc-GetReturnProperty()) { // 获取返回值例如 int if (FIntProperty* IntReturn CastFieldFIntProperty(ReturnProp)) { int32 Result IntReturn-GetPropertyValue(ReturnProp-ContainerPtrToValuePtrvoid(Params)); UE_LOG(LogTemp, Warning, TEXT(Return value: %d), Result); } } }