Can a Blueprint subclass override a C++ class' component type?

I have a C++ ACharacter subclass called AClassBase, and it has a component UPROPERTY(EditDefaultsOnly) class UWeapon * Weapon;

I want to derive multiple versions of AClassBase in Blueprint, but replace the Weapon – e.g. a Rogue that has an UKnife for its Weapon. UKnife would be inheriting from UWeapon. Ideally I would be able to do this just in the Class Defaults for the subclass.

I can’t seem to figure out how to do it – when I am editing the derived Blueprint class, it just says “Cannot edit variable type when they are inherited from parent.” for the type of Weapon. I’ve tried using Weapon = CreateAbstractDefaultSubobject(TEXT("Weapon")); in AClassBase::AClassBase().

Previous questions found in my searches that did not answer my question:

  1. https://answers.unrealengine.com/questions/46003/how-to-let-subclasses-override-components.html – which didn’t have an answer in May '14. There’s also
  2. https://answers.unrealengine.com/questions/54499/override-on-blueprint-components.html – which only has an answer that uses a construction script (which I’d like to avoid) and replaces variables in the component, not the type of the component.
  3. https://answers.unrealengine.com/questions/44855/how-to-let-super-classes-override-components.html – this seems to be C++ only, and to be referencing APIs that no longer exist.

Alternatively, it could also work if I had a TWeakObjectPtr in the parent that I could point to a real component on the derived class. I haven’t been able to figure out how to do this in the Class Defaults for the subclass, and if I use a Construction Script, it seems like it is executed after the AClassBase::PostInitProperties() – not sure when the construction script is actually run.

Thank you for your time.

The abstract subobject method will work, but only in C++. You’d need a derived C++ class for each character type (which you could then further specialize in a blueprint if you wanted). To do that, declare your base class constructor with an FObjectInitializer parameter:

AClassBase::AClassBase(FObjectInitializer const& OI)
{
  Weapon = CreateAbstractDefaultSubobject< UWeapon >(TEXT("Weapon"));
}

Then in each of your derived classes, you need to override as follows:

ADerived::ADerived(FObjectInitializer const& OI): Super(OI.SetDefaultSubobjectClass< UKnife >(TEXT("Weapon")))
{}

Your alternative approach is also an option, it has the advantage that you can add new subclasses and select their weapon type purely in blueprint, with the disadvantage that it requires a bit more manual setup. Basically, you’d just create whatever component you want via the AddComponent button in the blueprint editor for each blueprint subclass you have, and assign it to your pointer property at some point so the base class can access it. BeginPlay would be the safest place to do it. If your base class needs access to it earlier than BeginPlay, then I would have thought the construction script would work - it’s run every time you change any property of an actor in the editor.

Frustrating that it still is not possible to change the type of the component from the class defaults. That would have been great for avoiding Blueprint code dependencies.

I think I will end up using UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) TSubclassOf(UWeapon) WeaponType; and then have a UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite) class UWeapon *Weapon;. Then AClassBase::BeginPlay() can spawn the WeaponType and assign it to the Weapon instance. It means I can’t do configuration of class defaults for e.g. UKnife (like setting the damage or other effects), but I can get around that by just creating a Blueprint Class for the specific UKnife settings I want and configuring it there, then assigning that Blueprint Class to WeaponType.

Thank you for your answer!

Yep, that’s a common approach but like you say suffers from the fact that you can’t edit component properties inline, or per instance.

I believe I read ages ago that providing the SetDefaultSubobjectClass functionality in blueprints was something Epic wanted to do, but it hasn’t happened and suspect it probably won’t anytime soon.