Casting - C++ syntax and UE syntax

What is the difference between those 2 casting options?


ABuildingsMain* obj = (ABuildingsMain*)AVikingKingPlayerController::mouseHit.GetActor();


ABuildingsMain* obj = Cast<ABuildingsMain>(AVikingKingPlayerController::mouseHit.GetActor());

Both work, So why do I have to use UE syntax and not the regular C++ syntax?

2 Likes

There is no such thing as UE syntax, UE4 macros is valid C++ syntax. This probably have to do with C++ casters this might picks the right one:

1 Like

Thank you :slight_smile:

You don’t have to use the UE4 templated cast function, but it is much safer.

This is all about up-casting vs down-casting and type safety. There is some type safety stuff that happens with up-casting because it can be automatic. You can always cast a AActor to a UObject automatically but you obviously can’t automatically cast a UObject to a UComponent because it could actually be an AActor or even a UMaterial!.

Because down casting isn’t so easy, you use explicit casting like Cast<UBaseclass>() or the C raw pointer cast (UBaseclass*). The issue with the normal C cast is that it does not perform any run-time type checking, it simply tells the compiler that you want the pointer to be treated as a pointer of some other type. This works fine if you know the pointer is always going to be pointing at an object of the type you are expecting, but what happens if it’s not?

In comes the Cast template function. How this works is that it uses the UE4 reflection information to verify that the type you want to cast to is in fact something that is allowed. If it is not, it simply returns nullptr.

An example of where this is handy is in the AActor::RecieveHit(). Say the actor is a energy bolt cast from a spell. Now this spell only deals damage to Trolls so in RecieveHit() on your spell bolt you can write something like this:



ATroll* troll = Cast<ATroll>(Other);
if (troll != nullptr)
{
    troll->KillTroll();
}


If you were to use the normal C cast like this.


ATroll* troll = (ATroll*)Other;

And the actor you hit was a wall. The troll pointer would not be null and then when you call KillTroll(), the game would probably crash.

There is also a variation of CastChecked() which will assert if the type cannot be cast to. It is useful for making sure that higher level code is providing you with the correct inputs.

11 Likes

Can someone please give an example of when to use Cast and when to use CastChecked? I’ve read that CastChecked is faster but I’m not sure when should I use it and how. For example, do I still need to verify for nullptr if using CastChecked like we need to do for Cast?

CastChecked will assert (break to the debugger, or crash the program) if the cast is unsuccessful, so you just use it in cases where the object must be of the type you are casting to, and if it’s not then it implies a programmer error which needs resolving. It can’t return nullptr, so there is no point in null checking.

3 Likes

Thank you!

I’d like to add something to the topic.

So UE Cast can only be used on UObjects which means some classes with F prefix do **not **fit.

Here’s an example where you can only use C++ syntax but static_cast would still be preferred than the raw pointer cast.


IAssetEditorInstance* AssetEditor = FAssetEditorManager::Get().FindEditorForAsset(Blueprint, true);
if (AssetEditor)
{
    FBlueprintEditor* BlueprintEditor = static_cast<FBlueprintEditor*>(AssetEditor);
    BlueprintEditor->UpdateNodesUnrelatedStatesAfterGraphChange();
}


You can find more examples in the engine source code like the one above ^.

Regarding the previous post … don’t use static_cast for downcasting lightly (see https://stackoverflow.com/questions/…atic-cast-in-c). Use dynamic_cast instead.

2 Likes

Regarding also the previous post F prefix is for structs in UE conventions, not for classes.