虚幻4学习——TSubclassof<>的用法

虚幻4教程:TSubclassOf<>的应用解析
本文介绍了虚幻4中TSubclassOf<>模板的用途,包括如何方便关卡设计师编辑和在运行时进行安全类型转换。在示例中,解释了如何在ActEnemyController类中安全调用AIPawn的callPawnFunction函数,强调了TSubclassOf<>在虚幻4中的重要性。

虚幻4学习——TSubclassof<>的用法



TSubclassOf<> 模板提供了一个安全的虚幻类,他的好处有一下几个:


1.方便关卡设计师编辑


当我们准备在自己的类中引用一个伤害类型时,我们可能是这样定义这个伤害类的引用。

/** type of damage */ UPROPERTY(EditDefaultsOnly, Category=Damage) UClass* DamageType;

官方推荐的的定义方式是

/** type of damage */ UPROPERTY(EditDefaultsOnly, Category=Damage) TSubclassOf<UDamageType> DamageType;

官方推荐的这样方式的好处是在编辑器中,会给出游戏中所有的伤害类型,我们直接选择就可以,如果是UClass类,则会所有的类都会满足!降低了效率。



2.在运行时,类型转换的安全。

在运行时,我们可以动态的转换类型。如果不能转换,则是一个空指针. 在虚幻3的UC脚本中运用的最多。

比如在虚幻3中,我们建一个 AI控制类,这里我们命名为 ActEnemyController. 他是继承 AIController 类。

AIController 类继承 Controller 类。继承关系我们用下图表示。


ActEnemyController ——> AIController ——>

<think>嗯,用户的问题是关于在虚幻引擎中使用TSubclassOf<UMyBaseClass>作为指针,以及是否可以通过AClass->abc来访问成员变量或函数。我需要结合之前的对话和提供的引用内容来回答。 首先,回顾之前的回答,用户已经了解了TSubclassOf的基本用法,包括声明、编辑器配置和子类处理。现在用户的问题更具体,涉及到如何将TSubclassOf作为指针使用,以及访问成员的问题。 用户提到的引用内容中有关于C++类成员指针的内容(引用[1]),这可能涉及到如何在C++中处理成员指针,但虚幻引擎的TSubclassOf主要用于存储类引用,而不是直接处理成员指针。需要明确区分这两种概念。 用户的问题中,AClass->abc是否可行,这里的AClass应该是TSubclassOf持有的类类型,而abc是该类的成员。需要解释TSubclassOf的用途,它存储的是UClass*,而不是类的实例,因此不能直接访问实例成员。要访问成员,需要先创建实例,然后通过实例访问。 另外,引用[3]提到了智能指针,但TSubclassOf并不是智能指针,而是用来安全引用类类型的模板类。需要澄清这一点,避免混淆。 用户可能需要了解如何正确使用TSubclassOf来获取类信息,并通过生成的实例来访问成员。同时,可能需要提到GetDefaultObject()方法,用于获取类的默认对象,但需注意这仅适用于CDO。 总结回答步骤:1. 解释TSubclassOf的本质和用途;2. 说明如何通过生成的实例访问成员;3. 讨论CDO的使用场景;4. 强调类型安全的重要性;5. 提供相关问题扩展知识点。</think>### 一、`TSubclassOf<UMyBaseClass>`的核心用途与本质 #### 1. **类引用容器而非实例指针** `TSubclassOf<UMyBaseClass>`本质是**类型安全的UClass*包装器**,用于存储继承自`UMyBaseClass`的类信息(`UClass*`),而非具体对象实例。其核心作用是通过虚幻引擎反射系统实现安全的类选择[^1]。 ```cpp // 典型应用场景:创建指定类的实例 UClass* SelectedClass = MyClassSelector.Get(); // 获取存储的UClass* AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(SelectedClass); ``` #### 2. **成员访问的限制条件** 直接通过`TSubclassOf`访问成员变量/函数(如`AClass->abc`)是**不可行的**,因为它存储的是类定义而非实例。若要访问成员,必须满足以下条件: - **实例存在**:需通过`SpawnActor`或`NewObject`创建该类的具体实例 - **成员可见性**:目标成员需为`public`或通过`BlueprintReadOnly/Write`暴露给反射系统 --- ### 二、成员访问的正确实现方式 #### 1. **通过实例对象访问** ```cpp // 步骤1:获取类定义 UClass* TargetClass = MyClassSelector.Get(); // 步骤2:创建实例 UMyBaseClass* MyInstance = NewObject<UMyBaseClass>(GetTransientPackage(), TargetClass); // 步骤3:访问成员(需确保MyInstance有效且abc存在) if(MyInstance && MyInstance->GetClass()->IsChildOf(UMyBaseClass::StaticClass())) { MyInstance->abc = 123; } ``` #### 2. **通过默认对象(CDO)访问** 若需要访问类的默认值,可使用`GetDefaultObject()`获取Class Default Object: ```cpp UMyBaseClass* CDO = MyClassSelector->GetDefaultObject<UMyBaseClass>(); if(CDO) { int DefaultValue = CDO->ConfigValue; // 访问CDO的成员 } ``` *注意:CDO的修改会影响所有未显式设置该值的实例[^1]* --- ### 三、类型安全验证机制 虚幻引擎通过模板参数强制类型检查: ```cpp // 编译时类型检查 TSubclassOf<UMyBaseClass> ValidClass = UDerivedClass::StaticClass(); // 合法 TSubclassOf<UMyBaseClass> InvalidClass = AActor::StaticClass(); // 编译错误 ``` #### 运行时验证流程: 1. 通过`IsValid()`检查指针有效性 2. 使用`Get() -> UClass*`获取具体类引用 3. 调用`->IsChildOf(UMyBaseClass::StaticClass())`验证继承关系 --- ### 四、典型应用场景对比 | 场景 | `TSubclassOf`使用方式 | 成员访问方式 | |---------------------|--------------------------------------|--------------------------| | 动态生成Actor | 存储要生成的Actor类 | 实例化后访问成员变量 | | 配置武器类型 | 存储武器蓝图类 | 在生成的武器实例中调用方法 | | 数据驱动系统 | 存储不同技能效果类 | 通过CDO读取默认参数 | --- ### 五、高级注意事项 1. **蓝图派生类的处理** 若`UMyBaseClass`被标记为`Blueprintable`,在蓝图中添加的成员变量需要额外处理: ```cpp // C++代码中访问蓝图添加的变量需使用反射 FProperty* Prop = FindFProperty<FProperty>(TargetClass, "BlueprintVar"); if(Prop) { int32* ValuePtr = Prop->ContainerPtrToValuePtr<int32>(MyInstance); *ValuePtr = 100; } ``` 2. **跨模块类引用** 引用其他模块的类时需在`.Build.cs`中添加模块依赖: ```csharp PublicDependencyModuleNames.Add("OtherModule"); ``` --- ### 六、错误操作示例分析 #### ❌ 错误代码: ```cpp // 错误:试图直接访问类定义的成员 MyClassSelector->abc = 10; ``` #### ✅ 修正方案: ```cpp if(UMyBaseClass* DefaultObj = MyClassSelector->GetDefaultObject()) { DefaultObj->abc = 10; // 仅修改CDO的值 } ``` --- --相关问题--: 1. 如何在蓝图中访问`TSubclassOf`属性指定的类的静态成员? 2. `TSubclassOf`与`UClass*`直接赋值有何安全性差异? 3. 如何实现动态切换`TSubclassOf`存储的类并立即生效? 4. 虚幻引擎中`TSubclassOf`与C++标准库的`type_info`有何设计差异? [^1]: 虚幻引擎反射系统要求所有UCLASS类型必须通过GENERATED_BODY宏生成类型信息 [^2]: `GetDefaultObject()`返回的CDO在程序运行期间始终存在且唯一 [^3]: 直接操作CDO的成员变量会影响所有未显式设置该值的实例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值