Could I please get a simple explanation of TSubclassOf

Hi.

I’m doing some university study in software eng and I feel like I should be able to figure this out but still can’t get my head around it properly.

In the Unreal docs there is this defintion of TSubclassOf:

TSubclassOf is a template class that provides UClass type safety. For instance, let’s imagine that you are creating a projectile class that allows the designer to specify the damage type. You could just create a UPROPERTY of type UClass and hope the designer always assigns a class derived from UDamageType or you could use the TSubclassOf template to enforce the choice.

The way I have used this class is as follows:

  • create a c++ character. the c++ character is the parent to a character blueprint
  • in the c++ character class I can create a UProperty like:
    UPROPERTY(Category=“Bullet”, EditAnywhere, BlueprintReadOnly)
    TSubclassOf<ABullet> BulletBP;

So what that seems to do is create a variable called BulletBP in the character blueprint and there is a drop down list.

I have a bullet c++ class representing different bullet types and this is the parent of a bullet1_bp and bullet2_bp. In the BulletBP drop down list in the character blueprint I can select which bullet to use.

Lets say I select bullet1_bp in the BulletBP dropdown list. What I can’t seem to get my head around is why I can’t get a reference to the contents and variables of the bullet1_bp (whose parent is the ABullet class) from within the c++ character class.

Thanks.

TSubclassOf is a class, not an instance.

In C++ (and only in C++) - you can get the ‘ClassDefaultObject’ (CDO). The CDO is essentially a read-only object from which all children of that class are instanced from. You can get properties from that object, but obviously they will have their default/serialized values.

1 Like

To elaborate a bit more to TheJamsh’s reply:

TSubclassOf is basically a pointer to a UClass object, which just describes an object type. You can grab the CDO from a TSubclassOf like so:



if (*BulletBP) // This just checks if the TSubclassOf is valid and not pointing to a nullptr or anything.
{
  ABullet* MyBullet = BulletBP->GetDefaultObject();
}


Each time you compile a Blueprint, you are making a unique class. So your properties and such should be there. Just realize changing the CDO changes all instances of that class. If you wanted to grab a version you could alter at runtime, you’d want to do something like:



ABullet* MyModifiableBullet = NewObject<ABullet>(GetTransientPackage() /*or owner, or whatever */, *BulletBP);


2 Likes

So even though TSubclassOf is a class and not an instance - it would seem the Unreal blueprint system knows which instances of the class exist because it automatically puts the instances eg. bullet1_bp, bullet2_bp into a drop down list. I guess I don’t quite understand why then Unreal can’t do the reverse and just expose the actual objects in c++.

The reason I ask is I am struggling with how to handle the number of enemies killed in my game. I have an enemyspawner c++ class (as parent to enemyspawn_bp) and that generates a starting number of enemies eg. 20 - but when an enemy dies i’m not sure how to get access to the currentremainingenemies.

I did try to set all this in the gameinstance but it crashed my unreal and i got that dreaded 71% error where it just continues to fail to load when it reaches 71%.

Advice would be great.

Thx/

C++ side only know C++ types.
If you create a variable on Blueprint the C++ base class won’t know that variable exists unless the variable is declared in C++ base class instead of Blueprint.
The reasons for that are many, unfortunately I’m feeling lazy today to go deeper :s

You can define in C++ get/set functions that can be used in Blueprints to pass variables to C++ code in base class, but Visual Studio won’t show you a dropdown list of variables you have only created on the Blueprint side.

Unity automatically workaround that making heavy use of dotNET code reflection, when using Unreal it feels somewhat clunky and confusing.

1 Like

Not sure if this is the best way to handle this but i guess using an event dispatcher between blueprints derived from c++ classes might be the best way to go

A blueprint is a subclass of it’s parent, it is not an instance of it’s parent. An Actor in the world is an instance of whatever Blueprint/Class it is derived from.

So when you specify TSubclassOf<AMyActor>, any valid value for that is any subclass of AMyActor, as well as any blueprints that are derived from any of those subclasses. This is what the editor shows you.

Once you have a TSubclassOf, you can spawn it into the world, or whatever. You don’t want to be trying to access values inside it, though, unless you need to know it’s Defaults.

I don’t understand how this has anything to do with your other stated issues – it shouldn’t be related.

2 Likes

Thx @eblade for explaining that blueprints are actually subclassed from the c++ class and not an instance. I have two questions following on. As you say *“So when you specify TSubclassOf<AMyActor>, any valid value for that is any subclass of AMyActor, as well as any blueprints that are derived from any of those subclasses” *- So if I have two different blueprints BP_1 and BP_2 that have AMyActor as a parent (eg. two different weapon blueprints that have AWeapon as a parent) and I wish to only spawn BP_2 into the world how can I do that using TSubclassOf<AMyActor> when it seems to refer to everything subclass from AMyActor?

Second part of the question is - I still haven’t found a “right” answer to the “accessing values” inside of the AMyActor class. There probably isn’t a “right” answer - but keeping track of things like player/enemy health, enemy kills, bullets used - is that just best done in the blueprint itself?

Thanks.

1 Like

TSubclassOf<AWeapon> is a reference to a specific class, as long as that class’ inheritance hierarchy includes AWeapon. In Blueprint, you specify which particular class it’s referring to (either BP_1 or BP_2), but the drop down knows it has to be some sort of AWeapon, so it lists all the AWeapons to make the choice faster/easier for you. But from the C++ side, TSubclassOf<AWeapon> doesn’t refer to ALL the subclasses of AWeapon, only to the specific one chosen in the Blueprint dropdown.

If you want to access values of that blueprint, the values should probably exist on the parent. ie: EnemyKills, MaxAmmo, etc are variables defined in AWeapon. Because the child classes (BP_1, BP_2) inherit from AWeapon, they can set those variables, and because C++ knows it’s some sort of child of AWeapon, it can also access those variables.

If you’d rather have variables that only exist in Blueprint (…for whatever reason), then you probably should use functions to get that data, and the functions should be defined in AWeapon, and (re)defined in each individual Blueprint to return the needed values.

2 Likes

I don’t entirely follow – player health would normally be a concern of the player, enemy health would be a concern of the enemy, ammunition would be a concern of the weapon or ammo objects, etc. Generally, you want to put data in the classes that need it, or that it relates to. also, as nilamo says, TSubclassOf is a single pointer, it refers to any one thing, that is a subclass of <thing>