Why use TSubClassOf and not just the class itself?

I have read the documentation and I have seen some questions asked regarding TSubClassOf, but none explain what the point of it all is.

What extra does it bring?

I can write
UDamageType* dmgType = <some subclass of that damage type, either new or by ref>

or
TSubClassOf* dmgType = <some subclass of that damage type, either new or by ref>.

The only accepted types in BOTH cases are UDamageType or a sub class. What does the latter option provide that the former does not? The editor let me set the type properly when exposes to blueprints.

What am I missing?

The closest question.

2 Likes

UDamageType* dmgType;

vs

UClass* DamageType;

vs 

TSubclassOf<UDamageType> DamageType;

the first one is a blue pin object reference, which is not a class reference at all, its a reference to an object that is already created, or it is null. the second one is a purple pin Class reference, used to create new objects from, but in the details panel it would create a drop down menu that allows you to select any class.

the third one is TSubclassOf, which is like the second one, where it is a purple pin Class variable used to create new objects from, but the editor’s details panel will list only classes derived from UDamageType as choices for the property, instead of listing every class in the engine as an available replacement for that pointer.

so the first one is an object pointer, and the last 2 are class pointers, and the final one is a specific type of class pointer than narrows down the list of available class choices.

class pointers are different from object pointers, because UClass pointers reference class assets available in the editor, while object pointers can only be valid at runtime, because they can only reference objects that are already created or spawned into ram during gameplay.


so if you were making a weapon pickup item, where you wanted the designer to be able to choose the damage type for that weapon from the details panel, you would use

TSubclassOf<UDamageType> DamageTypeClass;

then on begin play, you can use

UDamageType* dmgType = NewObject<UDamageType>(DamageTypeClass);

that will give you a pointer to a created object of a type decided in the editor by a designer.

7 Likes

So, is it a stack object or a heap object? Are class pointers and object pointers not the same thing? A pointer is just a address to a point in memory after all.

Aa! Is it perhaps some kind of reflection that is incorporated into UE4?

i assume its the heap, because its dynamic memory, but in ue4, i never worry about stack vs heap, because ue4 has automatic garbage collection, so i never use Malloc or anything fancy, i just let it handle the memory maintenance how it wants.

class pointers and object pointers are different things. a UClass is something available in the editor, it has default properties and all knowledge needed to create or spawn an object or actor. its like a particle effect or static mesh or any other asset in the editor that is available in the editor without running the game.

objects and actors need to be spawned or created at runtime in order to exist or be pointed to.

so you could have an Actor called Dog, and a few subclasses called Poodle and Pitbull. using a TSubclassOf, you can select the type of dog in the editor, which you want to spawn in the game.

then when the game runs, you can spawn a hundred dogs of that type, and have an actor pointer which points to a specific dog. so even if there are 50 poodles, you can make a single poodle do a backflip, by calling a function using that actor pointer.

with a class pointer, you are not talking about a specific dog in the world, you are talking about a breed of dog, so you cant tell that breed of dog to do a backflip, you can only check its default properties, like how strong its biteforce is.

so in summary, TSubclassOf is a specific type of UClass pointer, which narrows down the list of available classes in the details panel, to a specific branch in the hierarchy of classes. it exists to give designers a choice between sublcasses of actors or objects, without having to change or compile any code.

3 Likes

TSubClassOf is same as UClass*, just limits class choose in editor to specific class base

2 Likes

That clarifies a lot. Thanks.

Those are similar but not the same (and not only because of “limiting class choice in editor”). Check @ScottSpadea answer.

I said “same as” not “are the same”, by that i mean they function exactly the same due to C++ magic :stuck_out_tongue: I’m fully aware this is template class that have cast overload to UClass*, the class contains only UClass pointer so in memory sense it makes no difference from normal UClass*. Only diffrence is that with TSubclassOf compiler pastes code on value get via inline that checks is class is related to class defined in template. You can look up here:

https://github.com/EpicGames/UnrealEngine/blob/f794321ffcad597c6232bc706304c0c9b4e154b2/Engine/Source/Runtime/CoreUObject/Public/Templates/SubclassOf.h#L75

But it really make no difference how do you use TSubclassOf and UClass* you use it the same way, it’s made so you don’t need to think that much about it.

If you want to pick on details ScottSpadea actully said something wrong “class pointers and object pointers are different things” all pointers ARE the same in C++, UClass IS object pointer as UDamageType pointer is object created by engine (not editor) on start up to identify class in UE4 reflection system and practically any pointer (not just object) as in reality all of them are just memory address integers. StaticClass() is a function which get you UClass* of specific class from generated code (each class have individual StaticClass() function declared and defined).

What ScottSpadea wanted to say is that they managed differently UClass is created by the engine on start up and it will be there until engine dies, it no different then any other object created by the engine which engine controls, while your class need to be initiated by yourself. So only difference is there life cycle and what is managing it. Still i use class pointer and object pointer term myself so… ;p engine design kind of force it in

I’m a bit too late but what do you mean that the “blue pin” can’t create a new object?

I’ve done for example UMediaPlayer* Media = NewObject; and it worked fine for the methods I used. I’m new to UE too

when you want to create a new object, or spawn a new actor, the spawning function requires a class reference, which has a purple pin in the blueprint editor. blue pins are actor or object pointers that are either already spawned in the world, or the pointer is null.

any 2 things could be considered the same, if abstracted enough, but that often ignores important distinctions. you don’t need to check if a class is null before using it, and you will never destroy a class when the game is running. a soup recipe and a bowl of soup are conceptually very different things. even if they are both made of atoms, you shouldn’t eat a soup recipe, and bowls of soup don’t belong on library shelves.

As I just stumbled upon this issue while trying to create an object from a TSubclassOf, I noticed that the first parameters of NewObject is the Outer or the owner class, the second parameter is the UClass to create the object from. So the correct way to call it would be (UE4 4.20)

UDamageType* dmgType = NewObject<UDamageType>(this, DamageTypeClass);

While I agree with your statement your analogy was the difference between a class and an object, NOT a difference between pointers. While the bowl and recipe are fundamentally different, the device used to find their locations (the pointer) is fundamentally the same. A pointer is a pointer is a pointer. They all perform the same task in fundamentally the same way. The pointer is not changed by what it points at. Imagine I have three signs, one pointing to hot dogs, another pointing to jewelry and the last pointing to a picture of your future fiance. Even though they point to fundamentally different objects, the signs are essentially the same. The hot dog sign may not make sense pointing to the jewelry, but that does NOT make the signs practically or conceptually different. The same is true for pointers.

“you don’t need to check if a class is null before using it” You are absolutly wrong, again TSubclassOf is only a template for UClass* and UClass* is a pointer and there for can be set to null state as any other pointer. Farther more user have a option to pick None in property editor and None in blueprints = null pointer in C++. For example you can set Default Pawn to None to disable auto spawn… and it does that by checking if . So you wither need to check for null (if you dont you only risking crash) or have a NoClear specifier for property editor(which btw don’t prevent setting it to null in blueprint scripting, so you need to check anyway)… but same as any other object pointer

“you will never destroy a class when the game” As much as you wont destroy UEngine object and many other object that run permanently, does this make them different in any way?. I would even argue that UClass can be destroyed and it happens when you unload the module containing the class, UClass is gonna be also destroyed together with blueprint asset. And TSubclassOf won’t help you here, you still need to check for null.

So yes they are absolutely the same