Search code examples
c++unreal-engine4

Restrictions on cast unreal


I know it is possible to cast thing in Unreal using Cast Keyword

Cast<Object>(object...)

But I was wondering if we could use:

  • static_cast
  • dynamic_cast
  • reinterpret_cast

I created a Interface (pure virtual class), but I saw some problems when doing reinterpret_cast with it.

E.g.

I can have:

class IMyInterface {
    void doSomething() = 0;
};

UCLASS()
class MYTEST_API My_Character : public ACharacter, public IMyInterface
{
    GENERATED_BODY()

But when I do reinterpret_cast<IMyInterface*> my object is not fully loaded and sometimes the program crashes.

Is there any restrictions doing these common c++ cast in Unreal Engine?


Solution

  • But I was wondering if we could use:

    • static_cast
    • dynamic_cast
    • reinterpret_cast

    Yes, of course you can use these. However, there are some restrictions and do's and don'ts here.

    First off, the only casts you'll probably need are the Cast<T>() and StaticCast<T> which Unreal provides. Cast<T>() uses reflection to determine the passed in type and the templated type and try to match them, returning a nullptr on failure. Note that, because of the nature of Unreals reflection, Cast<T>() only works on types that are USTRUCTs or UCLASSes. You can look into its inner workings here in the source.

    StaticCast<T>() is internally just the static_cast<T>() that you are used to. But there are reasons why it exists:

    This exists to avoid a Visual Studio bug where using a cast to forward an rvalue reference array argument to a pointer parameter will cause bad code generation. Wrapping the cast in a function causes the correct code to be generated.

    Source

    Using a reinterpret_cast on an UObject is most definitely the wrong approach. Did you know that you can just define UINTERFACE implementations and cast typesafe using Cast<T>()?
    A major issue with that is that holding a reference to an interface does not guarantee the lifetime of the object. So, if you want to keep it alive, you probably want to store the UObject* of the interface as a reference, either in a TStrongObjectPtr or as a UPROPERTY() in another UCLASS().