UEC++ UBT/UHT及反射系统

在Unreal Engine中,UHT与反射机制 虚幻引擎UHT与Visual Studio的编译配合是一个非常精细的过程,我将详细为你解析:1.编译流程概述2.编译前UHT处理步骤3.代码生成细节每个UCLASS()标记的类都需要生成一个UClass对象,描述该类的元信息。这个UClass对象用于虚幻引擎的反射系统,它包含了类的基本信息,如类名、父类、方法和属性等。在 UHT 生成的代码中,UClass对象是一个指向类描述的指针,它会通过静态构造函数来进行初始化。这些对象对于引擎动态加载和访问类、对象实例以及蓝图交互至关重要。 阅读详情

目录

一,常用UEC++变量类型

二,理解UBT/UHT

三,反射系统

关键宏

用于生成

用于调用(运行时)

四,UClass 

FProperty

UFunction

五,TFieldIterator


一,理解UBT/UHT

  • UBT(Unreal Build Tool )虚幻编译工具,负责管理整个编译流程,包括收集所需编译的模块、处理依赖关系、调用 UHT,最后再调用标准的 C++ 编译器(如 MSVC)完成最终编译;

  • UHT(Unreal Header Tool)预处理,负责解析头文件中的特殊宏(如 UCLASS(), UFUNCTION() 等),读取为 UObject 系统添加的“元数据”,并自动生成 *.generated.h 和 *.gen.cpp 等中间代码,从而支持反射、蓝图调用等功能;

    • 为UClass对象提供数据;

  • 在.generated.h内的DECLARE_CLASS2宏声明StaticClass();

            点击编译
                │
                ▼
┌─────────────────────────────────────────────────────────────────┐
│ 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()标记的变量,把值写入磁盘,加载时再自动恢复;只操作“属性数据”(填充UClass实例),不涉及定义(包括属性名称/类型等);
  • 垃圾回收,UPROPERTY()最重要的职责之一是阻止垃圾回收,被标记的指针,GC就知道“这是正在使用的”,不会错误地清理掉,防止内存泄漏和野指针的关键;
  • 网络复制,UPROPERTY(Replicated)可让某个属性在服务器和所有客户端之间自动同步,省去了手写大量网络通信代码的麻烦;

注:必须是UObject派生类,完整的反射功能(如垃圾回收)只在继承自UObject的类上生效,普通的C++类不行;

关键宏
// 创建新类型时“对外声明”,告诉构建工具“该类需要被纳入反射系统”;否则UBT在扫描头文件时会直接忽略该类,不会为它生成 .generated.h 和 .gen.cpp 文件;
// 可在其后附加说明符,用于该类与引擎编辑器及蓝图系统的沟通交互(如Blueprintable,BlueprintType,meta=(...));
// 标记类型错误(如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/UINTERFACE;
UPROPERTY() 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 通过反射系统将对应属性暴露给蓝图;

// 编辑器可编辑性(Visible / Edit)
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 = (ClampMin = "0", ClampMax = "100"))	// 硬限制数值编辑范围(仅对浮点和整数)
UPROPERTY(meta = (UIMin = "0.0", UIMax = "1.0"))	    // 软限制数值编辑范围(仅对浮点和整数)
UPROPERTY(meta = (ArrayClamp = "MyArray"))	            // 限制数值在指定数组(对整数)
UPROPERTY(meta = (AllowPrivateAccess = "true"))	        // 允许蓝图访问私有成员(不推荐,但有时有用)
UPROPERTY(Category = "移动属性", meta = (ClampMin = "0.0", ClampMax = "1000.0", ToolTip = "角色的基础移动速度"))
// 网络复制(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 动态执行函数(支持参数和返回值);

  • 动态创建对象
    • NewObject<UObject>(Outer, UClass*):创建任意 UObject 派生对象;

    • World->SpawnActor<AActor>(UClass*, ...):在关卡中生成 Actor;

  • 获取类默认对象(CDO)
    • UClass::GetDefaultObject() 返回该类的默认实例;

    • 用途:

      • 读取/修改类的默认属性值(影响所有新实例);

      • 比较对象属性是否与默认值不同(用于网络同步、序列化差异);

      • 快速获取类的一些静态配置;

  • 支撑引擎底层系统
    • 序列化:遍历 UClass 的所有 UPROPERTY,自动保存/加载;

    • 网络复制:标记 Replicated 的属性会通过 UClass 查找并同步;

    • 垃圾回收:通过 UClass 遍历对象引用的属性;

    • 编辑器 Details 面板:根据 UClass 中的属性元数据动态生成 UI;

    • 蓝图虚拟机:通过 UClass 查找函数并执行 ProcessEvent;

// 该函数是UHT生成的.generated.h内的DECLARE_CLASS2宏声明并最终在GENERATED_BODY()展开
// 所有参与反射的类型均有此函数(即标记了 UCLASS()/USTRUCT()/UENUM() )
// 通过该函数可保证每个UObject类均只有一个全局唯一的 UClass 单例对象
// 懒加载,首次调用该函数时创建UClass对象(首次可能是模块加载/首次调用/其他类引用)
static UClass* StaticClass()

// 针对UObject*,依据反射系统,本质上是利用IsA()遍历继承链比较UClass*,可跨模块
// 不同于原生的dynamic_cast依赖遍历虚表
Cast<T> / CastChecked<T>
// 针对FProperty*,遍历FField继承链比较FFieldClass*
CastField<T> / CastFieldChecked<T>

auto EnumName = StaticEnum<EMyEnum>()->GetName();       // 结果:EMyEnum
auto StructName = FMyStruct::StaticStruct()->GetName(); // 结果:MyStruct
auto UObjectName = UObject::StaticClass()->GetName();   // 结果:Object
反射入口 → UClass (StaticClass / GetClass)
            ↓
属性:FindPropertyByName → FProperty → ContainerPtrToValuePtr → 读写
函数:FindFunctionByName → UFunction → ProcessEvent → 调用
类型:IsA / IsChildOf
创建:NewObject / SpawnActor
// 获取 UClass(元数据入口)
T::StaticClass()	          // 获取已知 C++ 类 T 的 UClass
UObject::GetClass()	          // 获取实例对象所属的 UClass(运行时),有可能指向子类UClass
UClass* LoadClass<UObject>()  // 加载蓝图类的全局模板函数(只要指定类型UObject的子类即可)
// 读写属性(UPROPERTY)
UClass::FindPropertyByName(FName("PropName"))	    // 按名称查找 FProperty
TFieldIterator<FProperty>	                        // 遍历类的所有属性(含继承)
FProperty::ContainerPtrToValuePtr<void>(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
TFieldIterator<UFunction>	                    // 遍历类的所有函数
UObject::ProcessEvent(UFunction*, void* Parms)	// 执行函数(支持参数/返回值)
UFunction::Invoke(Object, Parms)	            // 另一个调用方式(较少用)
// 动态创建对象
// 创建 UObject 派生对象(只是创建一个变量),全局模板函数
T* NewObject<T>(Outer);
T* NewObject<T>(Outer, TEXT("Newname"));
T* NewObject<T>(Outer, UClass*)	
// 在世界中生成 Actor(必须是 AActor 子类,因为Actor具备世界空间坐标/生命周期管理接口,由UWord定义)                 
World->SpawnActor<AActor>(UClass*, FTransform, ...)	 
// 类型判断与转换
UObject::IsA(UClass*)	                          // 判断对象是否属于某类或子类,其底层调用的是 IsChildOf
UClass::IsChildOf(UClass*)	                      // 判断类是否继承自另一个类
Cast<T>(UObject*)/CastChecked<T>	              // 安全转换(编译期已知类型),UObject及其子类
CastField<T>(FProperty*)/CastFieldChecked<T>      // 安全转换 FField 及其子类(如 FProperty)
StaticClass()->IsChildOf(AActor::StaticClass())	  // 类继承检查
// 其他辅助
FindField<FProperty>(UClass*, FName)	// 等价于 FindPropertyByName
FindField<UFunction>(UClass*, FName)	// 等价于 FindFunctionByName
UClass::GetDefaultObject()	            // 获取类默认对象(CDO)
UClass::GetSuperClass()	                // 获取父类
UObject::GetFName()	                    // 获取对象名称(可用于反射查找),继承于UObject
// 常用宏(编译期帮助反射生成)
GENERATED_BODY()	                        // 必须在类声明中,展开反射所需的代码
DECLARE_DYNAMIC_MULTICAST_DELEGATE(...)	    // 声明动态委托(支持蓝图)
DECLARE_FUNCTION	                        // 自定义 UFUNCTION 底层(极少用)

三,UClass 

  • 一个UClass对象是描述一个 UObject 派生类元数据(属性、函数、父类、大小等);
    • UClass 是UE反射系统为每一个 UCLASS(即带有 UCLASS() 宏的 UObject 派生类)自动生成的元数据类型(继承链UObject -> UField -> UStruct -> UClass );
    • 可理解为C++ type_info的超级增强版——不仅包含类型名称、父类信息,还存储了该类的所有属性(UPROPERTY)、函数(UFUNCTION)、以及用于序列化、网络复制、实例化等的额外数据;
    • 该类型是引擎核心代码中已经定义好的(位于 UObject.h / Class.h);
  • UClass 是UE中“类的类”,提供了运行时对 C++ 类结构(属性、函数、继承、默认值)的完整描述和操作能力,是反射、动态创建、编辑器集成等所有高级功能的基础;
  • 每个 UObject 派生类都有一个唯一的 UClass 对象(单例);
    • UClass 对象是模块加载时创建的,其元数据内容由UHT生成提供;
  • 基类的 UClass 与子类的 UClass,是两个完全独立、互不包含的 UObject 对象;
    • 通过GetSuperClass() / SuperStruct,获取父类 UClass;

注,描述 UClass 类型的那个 UClass 对象,引擎已事先通过硬编码方式手动设置好的,不会陷入无限循环;

类型描述类型
E枚举UEnum
F结构体UScriptStruct
UObjectUClass (类型名称、成员属性、成员函数、父类、类大小,及元数据(Tooltip、Category等))
UObject 成员变量

FProperty 描述变量本身(变量名称、大小、偏移量、标志等)

        FFieldClass 描述变量类型(描述FProperty)

UObject 成员函数

函数参数

UFunction 

FProperty

AMyActor 编译
    |
    |  UHT 扫描 .h 文件
    |
生成 .generated.h 和 .gen.cpp
    |
    |  .gen.cpp 中包含:
    |  1. 静态结构体:TClassCompiledInDefer<AMyActor> 的实例
    |  2. 该类的元数据(属性名、偏移量、函数指针等)
    |
┌─────────────────────────────────────────────────────────────┐
│  模块加载 / 热重载(DLL 加载)                               |
└─────────────────────────────────────────────────────────────┘
    |
    |  ① 静态对象 TClassCompiledInDefer<AMyActor> 的构造函数执行
    |     → 将类名、大小、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()->SpawnActor<AMyActor>(...);
    |  → 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:
    // 表示描述对象的父类的描述类型指针(如描述AMyActor类的 SuperStruct 指向AMyActor父类AActor的 UClass 对象)
    TObjectPtr<UStruct> SuperStruct; 
public:
    // 表示包含描述对象自身拥有重量级成员的链表头(成员为函数或UENUM()/USTRUCT()定义的嵌套类型的描述),迭代器使用
    TObjectPtr<UField> Children; 
    // 表示包含描述对象自身拥有轻量级成员变量的链表头(成员为 FProperty 及其子类),迭代器使用
    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*/TObjectPtr<UObject>等包含对象引用的属性),阻止GC回收
    FProperty* RefLink;          // 从最高派生到基类的对象引用属性的链表,内存数据;
  // 自身定义
    EClassFlags ClassFlags;                      // 类标志(枚举类型)
    TObjectPtr<UObject> ClassDefaultObject;      // CDO(类默认对象实例,记录成员变量值包括父类默认值),便于快速实例化
    TMap<FName, TObjectPtr<UFunction>> 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(TArray<UObject*>& 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 中递归查找
    } 
};
// 利用UClass对象的成员变量ChildProperties,遍历自身拥有的属性
auto child_proes = GetClass()->ChildProperties;
while (child_proes)
{
	auto name = child_proes->GetName();
	UE_LOG(LogTemp, Warning, TEXT("FProperty: %s;"), *name);
	child_proes = child_proes->Next;
}

// 利用UClass对象的成员变量Children,遍历自身拥有的函数
auto ChildFuncs = GetClass()->Children;
while (ChildFuncs)
{
	auto name = ChildFuncs->GetName();
	UE_LOG(LogTemp, Warning, TEXT("UFunction: %s;"), *name);
	if (auto func = Cast<UFunction>(ChildFuncs))
		this->ProcessEvent(func, nullptr);
	ChildFuncs = ChildFuncs->Next;
}
FProperty

        FProperty 是UE反射系统的核心,用于描述一个类或结构体的成员变量(不是变量类型);从 UE 4.25 开始,替代原有 UProperty,不再继承自 UObject,以降低内存和性能开销;

        FProperty 是所有属性类型的基类,本身不存储属性的值,只存储属性的"元数据"(名称、类型、大小、偏移量、标志等);

        FProperty 是一个抽象基类,对于每种基本数据类型,都有具体的派生类来实现其特定行为;

// 描述 FField 及其子类的类型
class FFieldClass
{
private:
    FName Name;
    EClassFlags ClassFlags;
    uint64 Id;
    FFieldClass* SuperClass;
    FField* DefaultObject;
public:
    FName GetFName() const;
    FString GetName() const;
    bool IsChildOf(const FFieldClass* InClass) const;
    FFieldClass* GetSuperClass() const;  
    FField* GetDefaultObject();           
}
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;

    // 向上遍历外部对象链(定义该属性的所属类型)
    FFieldVariant GetOwnerVariant() const; // 获取所有者容器(通常用于引擎内部判断所有者是 FField 还是 UObject)
    UObject* GetOwnerUObject() const;     // 获取所有者的任意UObject及其派生类
    UClass* GetOwnerClass() const;         // 获取所有者的UClass
    UStruct* GetOwnerStruct() const;       // 获取所有者的UStruct(最常用)
    UField* GetOwnerUField() const;        // 获取所有者的UField

    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
}
// 简易伪代码 (描述成员变量本身包括类型/名称/内存偏移量等)
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),计算出此属性值的确切内存地址
    template<typename ValueType> // UObject容器
    ValueType* ContainerPtrToValuePtr(UObject* ContainerPtr, int32 ArrayIndex = 0) const
        return (uint8*)ContainerPtr + Offset_Internal + static_cast<size_t>(GetElementSize()) * ArrayIndex;
    template<typename ValueType> //结构体等非UObject容器
    ValueType* ContainerPtrToValuePtr(void* ContainerPtr, int32 ArrayIndex = 0) const
        return (uint8*)ContainerPtr + Offset_Internal + static_cast<size_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 (TFieldIterator<FProperty> It(MyClass); It; ++It)
{
    FProperty* Property = *It;
    
    // 1. 获取元数据
    FString PropertyName = Property->GetName();
    FString PropertyType = Property->GetClass()->GetName();
    
    // 2. 获取属性值的内存地址,该Property对应成员变量在对象实例上的内存位置
    void* ValuePtr = Property->ContainerPtrToValuePtr<void>(MyObject);
    
    // 3. 根据属性类型执行不同操作
    if (FIntProperty* IntProp = CastField<FIntProperty>(Property))
    {
        int32 Value = IntProp->GetPropertyValue(ValuePtr);
        // 处理 int32 值...
    }
    else if (FStrProperty* StrProp = CastField<FStrProperty>(Property))
    {
        FString Value = StrProp->GetPropertyValue(ValuePtr);
        // 处理 FString 值...
    }
    // ... 处理其他类型
}
UFunction

        UFunction 是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;                 // 获取函数名称
    UClass* 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
};
// 查找函数并调用,TargetFunc 描述成员函数
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 = CastField<FIntProperty>(TargetFunc->FindPropertyByName(TEXT("Value"))))
    {
        int32 ValueToSet = 42;
        IntParam->SetPropertyValue(IntParam->ContainerPtrToValuePtr<void>(Params), ValueToSet); // 查找的是属于成员函数的参数内存位置
    }

    // 调用函数(继承于UObject)
    MyObject->ProcessEvent(TargetFunc, Params);

    // 如函数有返回值,从 Params 中读取
    if (FProperty* ReturnProp = TargetFunc->GetReturnProperty())
    {
        // 获取返回值(例如 int)
        if (FIntProperty* IntReturn = CastField<FIntProperty>(ReturnProp))
        {
            int32 Result = IntReturn->GetPropertyValue(ReturnProp->ContainerPtrToValuePtr<void>(Params));
            UE_LOG(LogTemp, Warning, TEXT("Return value: %d"), Result);
        }
    }
}

四,TFieldIterator

// 可迭代任何继承自 UField 或 FField 的反射类型 <T>
template <class T>
class TFieldIterator
{
private:
	const UStruct* Struct;
	typename T::BaseFieldClass* Field;    // 指定迭代类型的最基类(UField/FField)
	int32 InterfaceIndex;
	const bool bIncludeSuper;
	const bool bIncludeDeprecated;
	const bool bIncludeInterface;
public:
    TFieldIterator(const UStruct* InStruct, EFieldIterationFlags InIterationFlags = EFieldIterationFlags::Default)

    explicit operator bool() const;
    bool operator !() const;
    bool operator==(const TFieldIterator<T>& Rhs);
    operator!=(const TFieldIterator<T>& Rhs);
    void operator++();    // 移动迭代位置 Field->Next;
    T* operator*();       // 返回对应类型指针 (T*)Field
    T* operator->();      // 返回对应类型指针 (T*)Field

    const UStruct* GetStruct();        
}
// 遍历成员变量
for (TFieldIterator<FProperty> it(GetClass(), EFieldIterationFlags::None); it; ++it) {
	auto pro_name = (*it)->GetName();
	auto protype_name = (*it)->GetClass()->GetName();
	UE_LOG(LogTemp, Warning, TEXT("FProperty: %s; FFieldClass: %s;"), *pro_name, *protype_name);
}

//遍历成员函数
for (TFieldIterator<UFunction> it(GetClass(), EFieldIteratorFlags::ExcludeSuper); it; ++it) {
	auto func_name = (*it)->GetName();
	UE_LOG(LogTemp, Warning, TEXT("UFunction: %s;"), *func_name);
	this->ProcessEvent(*it, nullptr);
}

UEC++开发中GENERATED_BODY()宏报错全解析与根治方案 在C++游戏开发中,反射机制是实现运行时类型信息查询、序列化和脚本化交互的核心技术。其原理是通过预编译工具分析源代码中的元数据标记,自动生成额外的类型描述代码,从而让静态类型语言具备动态特性。这项技术的工程价值在于大幅提升了开发效率,支持了蓝图可视化编程、网络同步和编辑器集成等高级功能。在虚幻引擎(Unreal Engine)的C++(UEC++)开发实践中,反射系统的实现依赖于Unreal Header Tool(UHT)这一关键工具链。UHT会扫描包含特殊宏(如UCLASS、UPROPERTY)的头文件 阅读详情

相关推荐

【UE 反射】反射的原理是什么?如何使用机制?

静态类型检查确保了类型的早期一致性和高效的代码执行,但减少了灵活性。动态类型检查提供了更大的灵活性,但增加了运行时的开销和潜在的错误。反射作为一种动态特性,无论是在静态类型语言还是动态类型语言中,都提供了强大的运行时类型操作能力,但也伴随着性能和安全性方面的权衡。通过理解这些联系,开发者可以在不同的编程语言和应用场景中选择适合的类型检查方式和反射机制,以实现所需的动态行为和灵活性,同时保证性能和安全性。

hhw_hhw的博客 6032

【UE5 C++】UBT与UHT

UE有一组用于的工具,包括和(以及其他工具)。实现这一套工具的目的是为了,方便你配置各个平台的参数和编译选项。

weixin_64072619的博客 2648

UE4 反射系统(UBT和UHT)介绍

UE4反射系统的宏 反射系统在我理解就是UE4可以让开发者代码简化,然后通过通过Unreal Build Tool(UBT) 和UnrealHeaderTool(UHT)来生成对应实际可用的代码在generated文件。 UField UFUNCTION()搭配GENERATED_UCLASS_BODY()使用 USTRUCT()搭配GENERATED_UCLASS_BODY()使用 UScriptStruct UFunction UEnum

zzZZ20150101的专栏 3615

UE中的反射系统

是微软.NET框架的一种机制,能够在程序运行时动态访问其他程序集中的元数据。比如,虚幻引擎是正在运行的程序,开发者编写的类是其他程序集,虚幻引擎可以访问开发者编写的类。虚幻引擎反射系统通过各种封装开发者编写的类。比如,UCLASSUPROPERTYUFUNCTION宏等,当然,开发者仍旧可以编写标准的C++类。对每种类型的数据结构或成员标记相应的宏可使其成为能够被虚幻引擎反射系统识别的UClassUPropertyUFunction等。

vjsopmh 1296

Ue4 反射系统

原文:InsideUe4 总结 : 类型系统 强调的是程序运行期间内建立起来的类型信息树组织 反射则强调运行时通过类型系统提供的信息创建对象,读取对象属性以及方法的一种能力 为什么要是用反射 1.通过反射能够更通用的调用类对象函数,而不需要判断对象类型(例如Unity通过反射调用Updat、FixUpdate) 2.为数据序列化提供支持 TODO C++中提供基础的RTTI主要通过typeid以及dynamic_cast typeid:这...

@Go Nowhere Fast 789

SV--对象拷贝、参数化的类

对象拷贝,参数化的类

创芯人--fly的博客 1569

UE里的反射(Reflections)机制

由于C++语言是不支持反射的,像UE这种引擎为了支持反射,就只能自己设计一套系统了,UE里这套系统叫做Unreal Header Tool (UHT),实现反射的核心思路也比较清晰明了,就是让用户在需要支持反射的类代码里加对应的宏,然后UHT在编译的时候会为其生成相关代码,比如要给一个变量加到反射系统里,就在它前面给它加一个UPROPERTY的宏(有点类似于C#里的给Property加Attribute)。

alexhu2010q的博客 3371

手把手教你用OpenCompass评估Qwen1.5-1.8B模型(含数据集配置详解)

本文提供了使用OpenCompass评估Qwen1.5-1.8B-Chat模型的详细实战教程。内容涵盖从创建独立Python环境、下载模型与核心数据集,到编写配置文件、执行评测命令及解读结果的完整流程。重点解析了模型与数据集的配置细节,并分享了性能调优与常见问题排查方法,旨在帮助开发者快速上手系统化的模型评估。

weixin_29228781的博客 137

Unreal Engine中的UHT和UBT

Unreal Engine中的UHT和UBT

最不正经的计算机专业学生 1897

SAP-ABAP:SAP HANA性能神器FDA:是极速查询的引擎,也是CPU过载的元凶

在SAP S/4HANA的世界里,有一个被ABAP开发者们既爱又怕的特性——Fast Data Access(FDA),它能将性能提升百倍,也能让CPU瞬间飙升。本文将带您全面解剖这一核心机制。

baidu_35680696的博客 849

基于卷积神经网络CNN实现电力负荷多变量时序预测(PyTorch版)

随着智能电网的发展,精准的电力负荷预测对能源调度和电网稳定具有重要意义。本文基于PyTorch框架,提出一种基于卷积神经网络(CNN)的多变量时间序列预测模型,用于电力负荷的短期预测。

时序笔记 988

UE5 C++(一)— 入门介绍

表示项目环境依赖信息,用到哪些模块(“Core”,“CoreUObject”,“Engine”,“InputCore”,这些是初始内置模块)。GENERATED_BODY() :表示我们不直接使用父类的构造函数,如果要定义类中初始化操作,需要在.h头文件中声明构造函数,然后在.cpp文件中实现构造函数,它之后的成员是private的。

qq_40120946的博客 3280

《我的Classic Platform AUTOSAR之路》 BSWM 模式管理(二)ESH

只有 PostRun 和 wakeup 才能切换到 RUN,其他状态需要先切换到 wakeup 模式。进入 RUN 模式需要打开通信 allow,退出 Run 需要 disable 通信 allow。Prepareshut 与 dem_shutdown 绑定,如果没有 dem 配置,不会生成。除了 Init 模式下,其他模式下都要检查 ECU 的唤醒源和通信 pending 需求。与 ECUM 相关,整个 ECU 状态管理的状态机制。postrun 可以不配置,需要根据自己的需求使能。

libuping2023的博客 964

UEC++基础(一)入门介绍

GENERATED_UCLASS_BODY()表示我们使用父类的构造 如果我们在自定义的类中做一些初始化操作 可以直接在.cpp文件中实现构造函数 而不需要在.h头文件中去声明 这个宏会自动生成带有特定参数的构造函数 它之后的成员是public。GENERATED_BODY()表示我们不直接使用父类的构造函数 如果我们要在我们自定义的类中做一些初始化操作 需要我们自己在.h头文件中声明构造函数 然后在.cpp文件中 实现该构造函数 默认它之后的成员函数 成员变量是private。

m0_74081331的博客 439

2026年数字IC设计禾赛科技笔试带答案解析

本文介绍了一份数字IC设计工程师笔试的试卷结构和部分题目解析。试卷包含15道单选题(30分)、10道填空题(20分)和5道简答/编程题(50分),总分100分,考试时长120分钟。单选题涉及同步时序电路、Verilog语法、跨时钟域设计、FPGA优化、存储器层次、功耗优化等知识点;填空题考查环形振荡器、工艺参数、时序约束、LUT结构等基础概念。试题重点考察应聘者对数字电路设计核心概念的理解和实际工程应用能力,特别是针对激光雷达芯片设计中的关键技术点进行考核。

Open 123

深度揭秘!用 DeepSeek 打造超智能电商客服系统全流程

摘要:本文围绕使用 DeepSeek 开发电商智能客服展开详细教程。先介绍前期准备,包括了解 DeepSeek、获取 API 权限与搭建开发环境。接着阐述数据收集预处理,结合电商业务逻辑实现商品与订单信息查询。还提及优化性能的方法,如模型微调、多轮对话管理和错误处理。然后说明了基于 Web 和云平台的部署方案。最后强调持续监控和改进的重要性,通过设置监控指标、收集分析用户反馈来优化系统,助力开发者打造高效电商智能客服。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 7812

UE C++ 开发全生命周期 + 全场景的知识点清单

存储逻辑:Config (存入 .ini), PerObjectConfig (每个对象独立配置), Transient (内存临时,不序列化)。编辑器显示:HideCategories, ShowCategories, CollapseCategories (简化 UI)。抽象性:Abstract (标记为抽象类,不可直接实例化)。内存性质:DuplicateTransient (复制时重置), NonTransactional (撤销操作时不记录)。权限控制。

我的博客主要是用来给我自己复习的,主要是上传一些知识点,小型的项目和功能模块,如果有什么问题或错误麻烦联系我! 963

手把手教你学Simulink——无刷直流电机(BLDC)霍尔传感器(Hall Sensor)信号处理电路仿真

在中,转子位置靠​ 给出,换相逻辑(Commutation Table)据此决定。实际霍尔输出是,且常有:比较迟滞(内置或外加分压)RC 低通(防 EMI 尖刺)与 MCU 间想让你霍尔三相 UVW 理想方波(120° each, 换相每 60°elec)经观察:原始 HU/HV/HW、滤波后波形、整形后 TTL 电平验证换相表(001→100→010…)与转子转向匹配是破局关键。

amy_mhd的博客 38

虚幻引擎(UE4) 反射系统(Reflection)

反射是程序在运行时检查自身的能力。这是非常有用的,并且是虚幻引擎的基础技术,可以为许多系统提供动力,例如编辑器中的详细信息面板,序列化,垃圾收集,网络复制以及Blueprint / C ++通信。但是,C ++本身不支持任何形式的反射,因此Unreal拥有自己的系统来收集,查询和操纵有关C ++类,结构,函数,成员变量和枚举的信息。我们通常将反射称为属性系统,因为反射也是图形术语。 反射系统是可选的。您需要注释任何您希望在反射系统中可见的类型或属性,虚幻解析工具(UHT)会在编译项目时获取该信息。 .

刀客 4038

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

UE_C++ —— UE反射系统111

UE反射系统简介;

NapoleonCoder的博客 437

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

UE4 C++反射从入门到原理剖解(UE4 4.26)

UE4 C++反射具体应用案例 测试反射类ATestActor // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "TestActor.generated.h" UCLASS(Blueprintable, meta = (Dis..

qq_29523119的博客 7167

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

UE5 UObject和反射

在虚幻引擎中,几乎所有由引擎管理的类都继承自UObject。标准 C++ 的newdelete在 UE 中是被严格限制的。只要一个类继承了UObject垃圾回收(Garbage Collection):引擎会自动追踪其引用计数,自动释放内存。反射数据支持:其实时元数据(Metadata)可以被引擎在运行时读取。序列化(Serialization):可以轻松地将对象状态保存到硬盘或从硬盘加载。网络复制(Replication):其属性可以通过网络自动同步。概念标准 C++虚幻 C++根基类无。

2302_80013723的博客 572

UE4中的反射机制

在内容窗口右键鼠标弹出菜单选择【新建C++类】在弹出对话框中,勾选【显示所有类】选中Object,点击【下一步】输入一个名称和保存的位置,点击【创建类】在VS的项目中就多出两个文件MyObject.h和MyObject.cppMyObject.h中的代码。

wb175208的专栏 1838

ubuntu环境下从零开始建立,编译,运行一个c程序的步骤

1、编译软件 gcc,一般ubuntu系统会自带的,如果没有的话需要安装。1.查找ubuntu系统是否有gcc软件,输入指令 which gcc查看gcc的版本 gcc --version 然后就可以确定系统自带gcc编译器了2.编辑软件vim,首先需要安装vim,输入指令 sudo apt-get install vim  由于我已经安装了vim,因此不会显示进度条3.在当前目录下新建一个文件夹...

Lawrence_121 2万+

UBT编译记录

UE4 的功能被分成了很多的模块,在API文档里每个类都有 Module 这个属性(值为模块名) 每个模块使用其他模块要在Build.cs里导入,像vs里的引入库。 在构建时 PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });//引入模块 ...

weixin_30369041的博客 229

UE4 C#(1):虚幻编译工具(UBT)

认识一下虚幻编译工具UBT

weixin_44200074的博客 2864
上一篇: UE Mobility
下一篇: UEC++ 数据类型及继承关系
挨代码
博客等级 码龄5年 1696粉丝 384原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值