Previously I wrote about delegates in UE4. Today I want to elaborate on this topic and tell you how to bind to delegates. We’ll mostly focus on C++ side but it’s not going to be very difficult so bear with me.
Static Delegates
Binding a function to a delegate is basically adding a listener to an event dispatcher. Simple delegates allow adding only one listener, multicast – many. There is also a distinction between static and dynamic delegates. I will start with static.
BindStatic
Use BindStatic
when you want to bind to a global function. Works like this:
// .h file
DECLARE_DELEGATE(FTestDelegate);
FTestDelegate TestDelegate;
// .cpp file
void DelegateHandler() {}
...
TestDelegate.BindStatic(&TestFunc);
Nothing special. I did not use it in my practice, so it is hard to tell what would be a proper use-case.
BindSP
In Unreal Engine office documentation there is an example for this binding. To no surprise it’s incorrect – it uses TSharedPtr
as a parameter to the function, but that’s probably outdated, because at this moment TSharedRef
should be used. So I modified the example a little bit:
// .h file
class RawClass
{
public:
RawClass()
{}
void RawFunc() {}
};
...
TSharedPtr<RawClass> ObjectPtr;
// .cpp file
ObjectPtr = MakeShareable<RawClass>(new RawClass());
TestDelegate.BindSP(ObjectPtr.ToSharedRef(), &RawClass::RawFunc);
This would be the proper usage example.
BindRaw
Use BindRaw
when you want to bind to a simple object of a non-UObject
class:
// .h file
RawClass* RawObject;
// .cpp file
RawObject = new RawClass();
...
TestDelegate.BindRaw(RawObject, &RawClass::RawFunc);
BindLambda
This might be a useful delegate handler when you want to define a handler right in the function block. So it allows binding lambdas to delegates:
// .cpp file
void ATestActor::TestFunc() {}
...
TestDelegate.BindLambda([this]
{
TestFunc();
});
BindUObject
And the final. I think this could be the most useful. Since UObjects
are the most commonly used objects in game projects it needs to use a special kind of a delegate for them. In this case it is BindUObject
– you won’t be able to attach other delegates to UObject
class:
// .h file
UFUNCTION()
void TestFunc();
// .cpp file
void ATestActor::TestFunc() {}
...
TestDelegate.BindUObject(this, &ATestActor::TestFunc);
Note, that declaration of TestFunc
is annotated with UFUNCTION
macros. It is necessary in order to handle an event properly.
This was an overview of simple delegates. Multicast delegates are almost the same. The only difference is that you use “Add-"
prefix , rather than “Bind
-” to add a delegate function.
Dynamic Delegates
You can bind only one type of function to a dynamic delegate. And it is a class method annotated with UFUNCTION
. To bind it use BindDynamic
method:
// .h file
DECLARE_DYNAMIC_DELEGATE(FTestDynamicDelegate);
...
FTestDynamicDelegate TestDynamicDelegate;
...
UFUNCTION()
void TestFunc();
// .cpp file
TestDynamicDelegate.BindDynamic(this, &ATestActor::TestFunc);
To bind a function to a multicast dynamic delegate use the function AddDynamic
Hey, thanks for sharing! I’m just getting into UE (UE 5).
Thank you!
Very useful info thanks. I want to add – avoid binding your delegates in UObject constructors – instead put them in your BeginPlay. It’s bad news to have your bindings in your constructors because they get serialized – so even after you remove them from your constructor (say you change your mind) your callbacks may still be getting fired, leading to much confusion.
https://forums.unrealengine.com/t/adddynamic-is-permanent/416021/7
Thanks for adding some useful info. Yeah , you are right!
TestDelegate.BindUObject(this, &ATestActor::TestFunc);
TestFunc doesn’t have to be UFUNCTION() if the delegate is static. this has to be a UObject though.