I think all unreal developer heard at least once something like “Avoid casting in blueprint. Use interfaces”.
If I’m not wrong, the known issue of using casts is that it creates a kind of “hard reference”. This means that the target class of the cast will be loaded to the memory as soon as the caller object is loaded. In the other hand, casts made in C++ or to C++ classes shouldn’t be feared since all the C++ classes are always loaded into the memory regardless. [Edited here]
With that in mind, some questions popped in my mind.
Lets imagine that we have a class A, a class B and a class X.
The class A have a hard reference to the class X.
The class B have a hard reference to the class X too.
My thoughts are the following:
The X class will be loaded twice in the memory?
If this is true, even the lightweight classes should create a mess when referenced by a large number of actors.
They will share the same “block of memory” where X class is allocated?
In this case I don’t see the memory problems when casting/hard referencing classes that will be necessarily loaded like GameInstance or GameMode.
Beyond that, there’s still the processing cost of casting in blueprints. I have no idea of the real impact of this.
Please, feel free to correct any mistake I’ve commit in this post and help me to solve this puzzle. All comments are welcome.
In both c++ and blueprints you can make use of soft object / class pointers.
These will not load a class into memory unless you tell it to.
The thing with blueprints is that any other pointer, I think even disconnected nodes, will count as a “hard reference / dependency” which will be loaded into memory even if the node is never used.
Not unless you have a static property, loading / unloading should be dynamic in all cases afaik. Here is more info on memory management for UObjects:
No. Link I posted has some information about the classes (UClass, CDO) logically they would be loaded once to serve as a template for any object instances such as actors you spawn in a level. Any new actor instance you spawn from such class does take up new memory.
*Edit
Casting does not lead to performance issues. If you are worried about this the unoptimized engine’s source code will make the eyes bleed. Often when you need to retrieve some value from engine source your request will be passed through a ton of classes. You can of course implement your own interfaces where desired, but it is not bad to cast. It is very common to cast Actor classes to pawns, controllers to playercontrollers etc, even on tick. If you do have to cast a lot in your own code it might point at a code design flaw though. Often you can move the related code to the class you cast to, or split functionality up into smaller classes.
Also, when an interface message is received, the Cast still happens but blueprints hide it nicely.
Cast vs Interface: 2 different tools for 2 different jobs. If you wanted to talk to 20 unrelated classes, you cannot rely on casting alone. If you need to talk to 20 unrelated classes with the same interface, then you have a much bigger architectural problem than choosing between the two methods.
Curious, what did you benchmark there? In the editor with all other things running at the same time it’s hard to be accurate… maybe when testing a million runs I don’t know XD.
There’s something else going on with interfaces, in c++ you have to do multiple checks to get a proper interface cast depending on if the interface is blueprint only or not. Extremely frustrating.
Hard to disagree. It’s from an older thread where we tried to gain a deeper understanding about this, it was a 10k loop or something, and rather meaningless, tbh. It does not translate into real life scenario. Especially in blueprints where performance is marred mostly by other things.
I post that picture when someone demonises casting, mostly for dramatic effect.
Since C++ implemented interfaces are compiled in directly in the native class, it may not be obvious, but the unreal generated code does push them to the UClass->Interfaces array just like blueprints, so it should work just fine in all cases.
For example this code :
UCLASS()
class AMyCharacter : public ACharacter
, public IAbilitySystemInterface
, public IGameplayTagAssetInterface
, public ITeamInterface
Bookmarking this, I’m not aware of any recent changes on this but the code I wrote was either for UE4.27 or UE5.0 at that time. When I implemented the code I wrote I had ran into a bug where casting to a c++ interface got null, so I wrote that after digging a bit. The problem case… might have been when a blueprint implements a c++ interface but the c++ base class does not. Something like that.