How to call a function in a TsubclassOf

Header:

 UPROPERTY(EditDefaultsOnly, Category = Weapon)
    		TSubclassOf<class ABaseWeapon> PrimaryWeapon;

cpp:

void UCharacterClassManager::Fire()
{
	switch (WeaponSlotEnum)
	{
	case EWeaponSlotEnum::WS_Primary:
		
		PrimaryWeapon->Fire();

		break;
	case EWeaponSlotEnum::WS_Secondary:
		break;
	default:
		break;
	}
}

essentially what my current system is, is I have a manager that’s supposed to manage primary, secondary and grenades. All this class is supposed to do be able to switch out weapons on the fly and call reload, fire, switch (between primary and secondary)
I use the tsubclass so have a base weapon (which is a separate file), that contains actions like the reload and fire, so that the manager says “I want to fire this weapon” and the base weapon class has the firing logic.

Problem is I can’t call the firing logic, it instead gives me the error message that “class UClass has no member Fire”, but it has it.

void ABaseWeapon::Fire()
{

}

Your PrimaryWeapon variable doesn’t hold the reference to the weapon actor spawned in the world, but instead holds the class type

Change from this:

UPROPERTY(EditDefaultsOnly, Category = Weapon)
TSubclassOf<class ABaseWeapon> PrimaryWeapon;

to this:

UPROPERTY(EditDefaultsOnly, Category = Weapon)
class ABaseWeapon* PrimaryWeapon;

and save it like so:

PrimaryWeapon = ()->Spawn<ARifle>(...)

I don’t want to spawn it in the world though. I just want it to hold the necessary information. in this case, the firing pattern, ammunition, etc. So that the manager can access that information or functions. Pretty much like this:
charater (calls fire in the manager)
manager (calls fire of the weapon)
weapon (fires)
I want to do it like this so i can add a lot of weapons in a short amount of time and keep it as modular as possible.

In the end i want to have a system like in a multiplayer game, where you can choose what primary, secondary you want to have.

Did you try to call PrimaryWeapon->GetDefaultObject()->Fire()
Would be great to hear if it worked :slight_smile:

1 Like

nope, that did not work. I think I found a solution, at least theoretically. I’m just gonna spawn the weapon in the world and attach it to the character.

But you need to spawn it to create data for it, you might also consider making actor component maybe

yeah. seems like best way is to spawn it in the world and attach it to the character. Do you mean the weapon itself should be a actor component?

oh. well the weapon manager is a actor component attached to the character.

1 Like

Hi PasteteDoeniel,

Just as the error says, UClass does not have a member function called Fire. Your class ABaseWeapon does, though.

TSubclassOf<…> is a wrapper around a type to allow it to be passed around with both compile-time and runtime safety. As Ali Akbar and have said, if you want to call a method on your weapon then you are going to need some kind of instance to call the method on. The most common approach to doing this is to, as you stated in a comment, spawn the weapon in the world yourself and attach it to a bone on your character.

If you would like a good example of an existing system that has multiple weapons, you can take a look at the ShooterGame project that comes with the engine.

No, your weapon manager, you could also spawn and just hold the pointer no need to attach it since it’s not physical at all. But you could good as well implement Fire function and weapon managment in actor it self.

Your class ABaseWeapon does, though.

Exactly! And, PasteteDoeniel, since your individual weapons all probably derive from your ABaseWeapon class (hence its name), then no matter which specific weapon the player is using, it is guaranteed to have a Fire function.

Another way you can ensure that your weapons have the required functions is to use interfaces.

But, in either case, as others have said, you still have to have an instance to call those functions on!

Difference between an object and an Actor is that Actors exist in the world and are spawned not just constructed

ok I’m gonna have a look at these things. I might have a look at the ShooterGame project (but I’ll try to avoid it, because I want to figure it out on my own through learning by doing.

I’m gonna have a look at these interfaces. sounds interesting and helpful.

TSubclassOf type main function is to limit selection of class to specific subclass so you are 100% sure the class you getting is related to that class (but it still can be nullptr), it also limits selection in the property editor

Small correction: TSubclassOf variables cannot be nullptr because they are value types, not pointer (reference) types. But they can be null, which was your meaning, I think. So, yeah!

Yes, as I said using TSubclassOf gives you guaranteed type safety at both compile- and runtime. It is a wrapper for UClass, and assigning it a value is limited in the editor and checked at runtime by inspecting the type hierarchy. My point for clarifying what TSubclassOf was, though, was to give an explanation for PasteteDoeniel’s confusion regarding the class UClass has no member Fire error message.

Thanks for adding to the conversation, @TimCarter.

It’s true that one can access functions and variables through the CDO, but it’s important to remember that such access is intended to be read-only — meaning, if you do call one of the CDO’s functions, it should basically be a ‘getter’ type and it should definitely not modify the underlying default object.

In this case, using the CDO wouldn’t be a solution for the OP because the OP wants to make the player’s currently equipped gun fire when a higher-level manager calls Fire() on a superclass of that currently equipped gun. This implies (really, requires) that the player’s gun already exists as an instantiated object, so the CDO is not really needed here.

Besides, calling Fire() directly on the CDO is either meaningless or dangerous — for example, assuming the Fire() function spawns a projectile or traces a line forward, where would that projectile or line trace begin? The CDO has no valid transform data, like position or rotation, because it doesn’t really exist in the world. The CDO’s purpose is to answer questions like the one featured in the first resource that you linked: for example, “How much does this thing cost?” or “How many tiles does this thing occupy once placed?” Those are safe questions to ask, because they are both “getter” questions.

Even almost a year later, it still sounds to me like the best solution for what the OP needs (and same goes for others in a similar situation) is, defining generic Fire() behavior in a high-level (base) weapon class, deriving from that base class to create the individual weapons, and overriding the Fire() function on the subclasses to implement the desired individual behaviors. This way, you could call Fire() at a high level, not even needing to know which subclass you’re dealing with at that moment, and the individual desired behavior would execute, all thanks to polymorphism.

So, in my opinion, the accepted answer is still the best one.

Old post, but it still comes up in searches with no resolution to OP original question. Contrary to the answers above, you do not need to create an object or spawn an actor in the world to access its default properties and functions.

If your wanting to call a method from a TSubclassOf variable without spawning or creating a new instance of the class, you can access the default CDO, and call the method from there.

“Each UCLASS maintains one Object called the ‘Class Default Object’, or CDO for short. The CDO is essentially a default ‘template’ Object, generated by the class constructor and unmodified thereafter. Both the UCLASS and the CDO can be retrieved for a given Object instance, though they should generally be considered read-only.”

You can find more info here and here.

Ninjin gave good advice, though the syntax is:

/** Property in header, can be set in editor */
UPROPERTY(EditAnywhere)
TSubclassOf<class UMyClass> MySubclass;


/** Call function somewhere in cpp */
MySubclass->GetDefaultObject<UMyClass>()->MyMethod();

His question was “How to call a function in a TsubclassOf” not “What is your opinion on design architecture for firing a weapon”.

I agree with what you say, but it wasn’t the question asked. Several even stated that it wasn’t possible and OP would have to spawn/create to call the method, which is inaccurate.

In addition, even using polymorphism and calling Fire() at a high level as you suggest, if the high level object is a TSubclassOf, OP would still need to know the answer to the original question that was asked, which is “How to call a function in a TsubclassOf”.

If someone searches that question they will come across this post as the top search return and it wouldn’t have answered the question being asked, but instead gave an opinion on a single over-specific use case.