Download

Why use keyword "class" in TSubobjectPtr, TSubclassOf and in function parameters?

In the Strategy Game sample see examples of this such as:


TSubobjectPtr<class UStrategyAIDirector> AIDirector;

TSubclassOf<class AStrategyChar> MinionCharClass;

virtual void OnConstructedBuilding(class AStrategyBuilding* ConstructedUpgrade);

But also times when “class” is not used:


virtual bool ReplaceBuilding(TSubclassOf<AStrategyBuilding> NewBuildingClass) override;

I am trying to understand what purpose class has in this context as it is not something I am familiar with from my work experience and I’ve not been able to find any explanations.

As a bonus I would also like to know why TSubobjectPtr was used for AIDirector, while TSubclassOf for MinionCharClass.

Thanks.

TSubclassOf<> indicate type Of class.

Without any pun intended, think of class like a Blueprint. It doesn’t do anything, but out if it you can construct new objects. This is what you pass trough TSubclassOf<> an Blueprint, from which new object can be constructed.

Now using this you can pass literally Blueprint class (in editor those things which are dark purple), or StaticClass() in C++ like:



UObject::StaticClass()


As for TSubobjectPtr<> it is used to declare Subobject for other objects, which can be constructed up construction of owning object (think of ActorComponenets for Actors).

As of 4.6 TSubobjectPtr is no longer relevelant, you will be using raw pointers.

Hi Tarostar,
The ‘class’ keyword here is simply being used instead of a forward declaration. In many cases I’ve seen in UE4 code it’s not strictly necessary as the class being referenced may already be known. It seems to be a convention.
Cheers,
Ben

Ok, so if class is simply a forward declaration (and potentially a UE4 convention) then that is really straight forward. :slight_smile:

Knowing that TSubobjectPtr will be removed in 4.6 means I can continue to use just TSubclassOf, otherwise it’s just a pointer. I was further confused by the terminology in blueprints where passing an instance of a class you pass an “object” but if you pass the class blueprint (if you will) then you use “class” as the parameter type, but I think that everything makes sense now.

Appreciate the help.

This Use of Class is Extremely Important

I just did this a few moments ago!

This special use of class as a forward declaration is extremely important!

It’s way more concise than forward declaring at the top of your .h file

Consider the following code which I wrote for a project just a few moments ago. This code below is in my highest level class structure, where the actual Actor class being used has not yet been defined.



USTRUCT(BlueprintType)
struct FGalaxyWeapon
{
	GENERATED_USTRUCT_BODY()
 
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Galaxy")
	TEnumAsByte<EGalaxyWeapons::Type> Type;
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="Galaxy")
	FName SocketName; 
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="Galaxy")
	USkeletalMesh* Mesh; 
	
	UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="Galaxy")
	TSubclassOf<class AGalaxyPickupWeapon> PickupClass;
	
	FGalaxyWeapon()
	{
		//etc
	}
};


For newcomers to the thread, we’re talking about this line:



UPROPERTY(EditAnywhere, BlueprintReadWrite,Category="Galaxy")
TSubclassOf<**class** AGalaxyPickupWeapon> PickupClass;


If I did not include class, the above code would throw a compile error because the AActor class is much further along in the compilation process and has not yet been defined.

Yes you could use a forward declaration the way I describe in my wiki, but this method is more concise

Enjoy!

Rama

Forward declaration as explained in Rama’s wiki is how I’ve always done it, and the primary reason for doing that (e.g. class MyClass; in the header) was to avoid circular dependencies. I’m not sure if the UE4 way of doing forward declarations is “better”, but it does bring the declaration to where it is used - which I like.

Remember that a forward declaration only works when members of the class (including constructor/destructor) are not used. This is not much of a problem since it is used in headers, but limits use to pointers (including TSubclassOf). So writing class MyClass ClassInstance* will work, but writing class MyClass ClassInstance will invoke the constructor and since that has not been defined by the forward declaration it will not work. Please correct me if that is in any way not correct.

Now, is there any reason NOT to use this type of forward declaration everywhere as a convention (as seems to be the case)?

So this is being replaced?


TSubobjectPtr<class UStrategyAIDirector> AIDirector;

What will we do instead in 4.6?


class UStrategyAIDirector* AIDirector;

Indeed, the point I think is that TSubobjectPtr is just a pointer with a fancy name. Adam Davis (Unreal Engine Support) wrote: “We’re getting rid of TSubobjectPtr. It was confusing and weird. Just use normal pointers to your sub-objects now!” Presumably you might use smart pointers also, such as TSharedPtr/TWeakPtr.

uh?

It makes no sense using TSharedPtr/TWeakPtr instead of the old TSubOjbtPtr, since the UPROPERTY are already “reference counted”.

Just use naked pointers.

Ah makes sense now!

Sure UPROPERTY pointers will be garbage collected, but if you want to manage the lifetime of your pointers then you should use smart pointers. I’m not saying you should manage it yourself, but you could and there is nothing wrong with that as far as I know. If you use smart pointers then you simple leave less garbage for the collector to collect (obviously if you do not use UPROPERTY for a pointer then you really should use smart pointers or you are opening yourself up for memory leaks).

TSharedPtr/TWeakPtr do not work with UObjects.
If you want to use smart pointer with UObject you need to use TWeakObjectPtr<>

Ok, that is good to know. Thanks.