Sometimes it would be useful to have overridable virtual functions that can be called without having to instantiate a class by declaring the function static. Here is one such scenario: Imagine you have a base class that generates and returns transforms for your enemy units. Your game mode will use that class to generate spawning transforms for all your enemy units. You want to be able to easily create new rules for creating enemy unit transforms in BP, so you implement the function as a BlueprintNativeEvent like so:
UFUNCTION(BlueprintNativeEvent, Category = "Unit Spawning")
virtual TArray<FGenome> GenerateTransforms_Implementation();
//Here we can put some logic that generates the transforms.
Using a virtual BlueprintNativeEvent allows you to generate Blueprint child classes of the UnitSpawnerBase class and override the GenerateTransforms() event to have different rules for finding good spawning locations for your enemy units. This is a handy way to manage and extend the rules to spawn enemy units. You want different enemy spawn rules based on the map, difficulty level, enemy type? Just create new child classes for each!
To run GenerateTransforms() you instantiate the class in your game mode, for example using NewObject(), and then call the function in the instance:
UUnitSpawnerBase* UnitSpawner = NewObject<UnitSpawnerBase>(GetTransientPackage(), ClassToSpawn);
where ClassToSpawn is a TSubclassOf<UnitSpawnerBase> and contains the child BP of UnitSpawnerBase you want to use.
But you don’t really need an actual instance of UnitSpawnerBase, you just want to call its function GenerateTransforms() with the default values of the class.
Normally, you use static functions for functions you want to call without instantiating a class and that can be used anywhere. But you can’t override static functions because you can’t have virtual static functions in C++. Is there a way to access GenerateTransforms() without instantiating UnitSpawnerBase?
There is! You can access all of UnitSpawnerBase’s variables’ default values and its functions by using its Default Object. The default object is an instance of the class that is automatically generated by UE and contains the default values of the variables and serves as a template to create further instances of the class. This is how you can use it to access virtual functions of a class without creating a new instance of that class:
UUnitSpawnerBase* UnitSpawner = Cast<UUnitSpawnerBase>(ClassToSpawn->GetDefaultObject());
TArray<FTransforms> SpawnTransforms = UnitSpawner->GenerateTransforms();
GenerateTransforms() will then either run the CPP implementation if the BP child class does not contain an override of the event, or it runs the override defined in the BP class. And it doesn’t need to instantiate the class to do that!
You can also use the DefaultObject of a class to access the default values of its variables.