如何创建调用CreateDefaultSubobject的UE4 UCLASS基类并允许子类修改子对象类型
解决方案
你可以通过基类构造函数接收类型参数的方式实现需求,这是UE GAS生态中的标准实践,完全规避你列出的所有限制:
实现步骤
1. 调整基类构造函数声明
给你的角色基类构造函数新增两个可选的类型参数,默认值为基础ASC/AS类型,无自定义需求的子类可直接继承无需额外修改:
// RPG角色基类头文件 UCLASS() class YOUR_MODULE_API ARPGCharacterBase : public ACharacter { GENERATED_BODY() public: explicit ARPGCharacterBase( const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get(), TSubclassOf<UAbilitySystemComponent> InASCClass = UAbilitySystemComponent::StaticClass(), TSubclassOf<UAttributeSet> InASClass = UAttributeSet::StaticClass() ); protected: // ASC实例 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS") UAbilitySystemComponent* AbilitySystemComponent; // 属性集实例 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS") UAttributeSet* AttributeSet; };
2. 基类构造函数内动态创建子对象
在基类构造函数体内,使用传入的类型参数调用CreateDefaultSubobject创建实例,固定子对象名称避免序列化异常:
// 基类cpp实现 ARPGCharacterBase::ARPGCharacterBase( const FObjectInitializer& ObjectInitializer, TSubclassOf<UAbilitySystemComponent> InASCClass, TSubclassOf<UAttributeSet> InASClass ) : Super(ObjectInitializer) { // 开发期校验传入类型合法性 check(InASCClass && InASCClass->IsChildOf(UAbilitySystemComponent::StaticClass())); check(InASClass && InASClass->IsChildOf(UAttributeSet::StaticClass())); // 按传入类型创建子对象 AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponent>( TEXT("AbilitySystemComponent"), true, InASCClass ); AttributeSet = CreateDefaultSubobject<UAttributeSet>( TEXT("AttributeSet"), true, InASClass ); }
3. 子类传入自定义类型
子类只需要在构造函数初始化列表调用基类构造时,传入自己扩展的ASC/AS类型即可:
// 自定义角色子类头文件 UCLASS() class YOUR_MODULE_API ACustomPlayerCharacter : public ARPGCharacterBase { GENERATED_BODY() public: explicit ACustomPlayerCharacter(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); }; // 子类cpp实现 ACustomPlayerCharacter::ACustomPlayerCharacter(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer, UMyCustomASC::StaticClass(), UMyCustomAS::StaticClass()) { // 子类其他构造逻辑 }
方案合规性说明
- 所有
CreateDefaultSubobject调用都在基类构造函数体内执行,符合UE的调用要求,不会触发崩溃 - 不需要使用UCLASS模板、构造函数模板、虚方法,完全规避你提到的所有限制
- 子对象名称固定,不会出现同名称重复添加的冲突问题
- 类型安全:开发期check会直接拦截非法的类型传入,避免运行时异常
内容的提问来源于stack exchange,提问作者GuyPaddock
相关产品推荐
相关产品推荐

