怎么做的英文网站国外优秀网页设计网站
怎么做的英文网站,国外优秀网页设计网站,建网站用哪个好,怎么用电脑做网站第 10 章 Cast () 与类型扩展
标准 C 有四种类型转换#xff1a;static_cast、dynamic_cast、reinterpret_cast、const_cast。其中 dynamic_cast 是唯一的运行时安全向下转型——但它慢#xff0c;而且依赖 RTTI。
Unreal 用 CastT() 替代了 dynamic_cast#xff…第 10 章 · Cast () 与类型扩展标准 C 有四种类型转换static_cast、dynamic_cast、reinterpret_cast、const_cast。其中dynamic_cast是唯一的运行时安全向下转型——但它慢而且依赖 RTTI。Unreal 用CastT()替代了dynamic_cast利用反射系统的继承链信息实现了更快的类型转换。但 Unreal 对 C 类型系统的扩展远不止一个 Cast——它还引入了TSubclassOf类型安全的类引用、TObjectPtr原始指针的替代、TSoftObjectPtr延迟加载的资产引用等一系列类型包装器。本章把它们一并讲清楚。10.1 CastT()更快的 dynamic_castdynamic_cast 的工作原理标准 C 的dynamic_cast在运行时执行类型检查。它的实现通常需要遍历虚表vtable中的类型信息沿继承链向上搜索判断目标类型是否在继承路径上。Base*baseGetSomeObject();Derived*deriveddynamic_castDerived*(base);if(derived){derived-DerivedMethod();}这个遍历过程的性能取决于继承深度。在 Unreal 这样动辄十几层继承的体系中AMyCharacter→ACharacter→APawn→AActor→UObjectdynamic_cast的开销不容忽视。CastT() 的实现Unreal 的CastT()不依赖 C 的 RTTI。它利用的是第 4 章介绍的反射系统每个 UObject 都有一个UClass*而UClass记录了完整的继承链。AActor*SomeActorGetSomeActor();AMyCharacter*CharCastAMyCharacter(SomeActor);if(Char){Char-TakeDamage(50.0f);}底层的检查逻辑大致是取 SomeActor 的 UClass 检查该 UClass 是否是 AMyCharacter::StaticClass() 的子类 → 通过 UClass 中缓存的继承深度和父类指针链快速判断 如果是直接 static_cast 并返回 如果不是返回 nullptr关键优化在于UClass 存储了预计算的继承信息包括继承深度和直接的父类指针链类型检查不需要逐级遍历虚表——而是直接比较预存的数据。在大多数情况下这比dynamic_cast快得多。另一个区别CastT()对nullptr输入直接返回nullptr不需要额外的空指针检查。// dynamic_cast 对 nullptr 的行为是安全的返回 nullptr// CastT 也是——但很多人习惯先检查空AActor*MaybeNullnullptr;AMyCharacter*ResultCastAMyCharacter(MaybeNull);// 安全返回 nullptr对接口的 CastCast同样适用于 UInterface第 6 章if(IDamageable*DamageableCastIDamageable(SomeActor)){Damageable-ApplyDamage(25.0f);}10.2 CastChecked 与 ExactCastCastCheckedT()// 转换失败时Debug/Development 版本直接崩溃断言失败AMyCharacter*CharCastCheckedAMyCharacter(SomeActor);Char-TakeDamage(50.0f);// 如果走到这里Char 一定有效CastChecked用于你确信转换一定会成功的场景。如果失败了说明程序逻辑有 bug——用断言崩溃比让错误的 nullptr 继续传播要好。在 Shipping 构建中CastChecked的断言会被移除与check()一样变成等价于static_cast——零开销。ExactCastT()// 精确匹配SomeObject 的类型必须恰好是 T不考虑子类UMyObject*ExactExactCastUMyObject(SomeObject);CastT在继承链上向上搜索——T 及 T 的所有子类都能通过。ExactCastT只有对象的实际类型恰好是 T 时才返回非空。使用场景很少但在某些需要精确类型匹配的框架代码中有用。选择指南场景用什么不确定是否能转换需要检查CastT() if 检查确信能转换失败是 bugCastCheckedT()需要精确类型匹配ExactCastT()编译期已知安全的向下转型static_cast不经过反射最快10.3 TSubclassOfT类型安全的类引用在 Unreal 中你经常需要在编辑器中配置用哪个类——比如这个生成器应该生成哪种类型的子弹。最直接的做法是用UClass*UPROPERTY(EditAnywhere)UClass*ProjectileClass;问题是编辑器会列出引擎中所有的类用户可以选择任何一个——包括UTexture、USoundWave等完全不相关的类。运行时你用这个UClass*去SpawnActor如果用户选了一个非 Actor 的类就会崩溃。TSubclassOfT解决了这个问题UPROPERTY(EditAnywhere)TSubclassOfAProjectileProjectileClass;编辑器层面下拉列表只显示AProjectile及其子类。用户无法选到不相关的类。编译器层面TSubclassOfAProjectile不能被赋值为AWeapon::StaticClass()除非AWeapon是AProjectile的子类。类型安全在编译期保证。运行时使用if(ProjectileClass){AProjectile*ProjGetWorld()-SpawnActorAProjectile(ProjectileClass);}TSubclassOf内部就是一个UClass*但带了编译期的类型约束。它是 Unreal 对 C 类型系统最优雅的扩展之一——几乎零开销却大幅提升了类型安全性和编辑器体验。10.4 TObjectPtrTUE5 的原始指针替代UE4 中引用 UObject 就用裸指针// UE4 风格UPROPERTY()UStaticMeshComponent*MeshComp;UE5 引入了TObjectPtrT// UE5 风格UPROPERTY()TObjectPtrUStaticMeshComponentMeshComp;为什么要替换裸指针TObjectPtr在编辑器构建中提供了两个额外能力延迟加载Lazy Loading。TObjectPtr可以在首次访问时才真正加载被引用的资产而不是在包含它的对象被加载时就立刻加载。这减小了初始加载时间。访问追踪Access Tracking。编辑器可以记录哪些对象通过TObjectPtr被访问了用于资产依赖分析和 cook 优化。在打包后的游戏中Shipping 构建TObjectPtrT退化为普通的T*——零运行时开销。使用方式TObjectPtrT的使用几乎与裸指针完全一样——你可以用-和*操作它可以把它传给接受T*的函数可以与nullptr比较。唯一的区别是声明时的类型。UPROPERTY()TObjectPtrUTexture2DIcon;// 使用方式完全一致if(Icon){FVector2DSize(Icon-GetSizeX(),Icon-GetSizeY());}如果你在写新的 UE5 项目UPROPERTY 中的 UObject 指针应该优先使用TObjectPtr。如果你在维护 UE4 迁移的代码不必急着改——裸指针仍然有效。10.5 TSoftObjectPtr 与软引用最后一类类型扩展解决的是资产加载问题。当你在 UPROPERTY 中引用一个资产UPROPERTY(EditAnywhere)UStaticMesh*WeaponMesh;这是一个硬引用Hard Reference。硬引用意味着当包含这个属性的对象被加载时WeaponMesh指向的 StaticMesh 也必须同时加载到内存中。对于小型项目这没问题。但在大型项目中一个角色硬引用了武器网格武器又硬引用了材质材质又硬引用了纹理……引用链传递下去加载一个角色可能连带加载了几百 MB 的资产。软引用Soft Reference打断了这条链UPROPERTY(EditAnywhere)TSoftObjectPtrUStaticMeshWeaponMesh;TSoftObjectPtr存储的是资产的路径字符串而不是指向已加载对象的指针。资产不会被自动加载——你需要显式请求加载// 检查是否已经加载if(WeaponMesh.IsValid()){UStaticMesh*MeshWeaponMesh.Get();// 直接使用}elseif(!WeaponMesh.IsNull()){// 异步加载FStreamableManagerStreamableManager...;StreamableManager.RequestAsyncLoad(WeaponMesh.ToSoftObjectPath(),FStreamableDelegate::CreateLambda([this](){UStaticMesh*MeshWeaponMesh.Get();// 加载完成使用 Mesh}));}TSoftClassPtr类似地TSoftClassPtrT是TSubclassOfT的软引用版本UPROPERTY(EditAnywhere)TSoftClassPtrAProjectileProjectileClass;// 加载后使用UClass*LoadedClassProjectileClass.LoadSynchronous();if(LoadedClass){GetWorld()-SpawnActorAProjectile(LoadedClass);}FSoftObjectPath / FSoftClassPath更底层的表示——纯字符串路径没有模板参数的类型约束FSoftObjectPathAssetPath(TEXT(/Game/Weapons/Sword.Sword));UObject*LoadedAssetPath.TryLoad();硬引用 vs 软引用选择场景选择始终需要的核心资产角色骨骼、主武器网格硬引用T*/TObjectPtrT按需加载的大型资产可选皮肤、远处的建筑软引用TSoftObjectPtrT编辑器配置的类类型TSubclassOfT硬或TSoftClassPtrT软10.6 类型扩展全景把本章介绍的所有类型包装器放在一起UObject 指针类型 ┌────────────┴────────────┐ 强引用 弱/软引用 ┌──────┴──────┐ ┌──────┴──────┐ 直接指针 类引用 弱引用 软引用路径 ┌────┴────┐ │ │ ┌────┴────┐ T* TObjectPtr TSubclassOf TWeakObjectPtr TSoftObjectPtr TSoftClassPtr (UE4) (UE5) (Ch9)每一种类型在类型安全、“加载时机”、GC 行为三个维度上做了不同的取舍。理解这张图你就能在任何场景下选出正确的指针类型。实验Cast 与 TSubclassOf / 软引用Cast 与层级。用 SpawnActor 生成一个 ACharacter或任意派生类把返回的AActor*存到变量里分别用CastAPawn(Actor)和CastACharacter(Actor)转换并检查是否非空理解Cast 沿继承树向上兼容再尝试对完全不相关的类如 UTextureCast应得到 nullptr。TSubclassOf 在编辑器中的表现。在 Actor 上声明UPROPERTY(EditAnywhere) TSubclassOfAActor ActorClass;编译后在 Details 里查看下拉框应只列出 AActor 及其子类理解类引用 类型约束如何避免配错类。TSoftObjectPtr 延迟加载。把一个 UPROPERTY 从UStaticMesh*改成TSoftObjectPtrUStaticMesh在编辑器中指定同一资产路径运行后用IsNull()/IsValid()和LoadSynchronous()或异步加载 API 取到指针体会不自动加载、按需加载与硬引用的区别。一句话总结Unreal 用 CastT() 替代 dynamic_cast 获得更快的类型转换用 TSubclassOf 添加编译期类型约束用 TObjectPtr 支持延迟加载用 TSoftObjectPtr 实现按需资产加载——这些不是语法糖而是游戏引擎在类型系统维度上的必要扩展。