跳到主要内容

02 - 委托

本文主要说明了UE5中有关委托的概念和基本用法。

委托

委托(UDELEGATE())是一种能在C++对象上引用和执行成员函数的数据类型。可使用委托动态绑定到任意对象的成员函数,之后通过委托调用该对象绑定的函数,即使调用程序不知绑定对象的类型也能进行操作。

UE共支持三种类型的委托:

  • 单点委托(单播):只绑定1个委托函数;
  • 组播委托(多播):可以绑定多个委托函数,但不能有返回值;
  • 动态单播/多播:支持序列化,可暴露给蓝图的单播/多播委托,但执行速度比常规委托慢;

单播委托

声明

需要使用宏来声明委托,最基础的委托宏为DECLARE_DELEGATE(DelegateName),它对应void Func()。如果想要添加返回值等属性,需要在基础宏上添加一些关键字。UE5目前支持以下关键字和基础宏的任意组合:

  • 有返回值:DECLARE_DELEGATE_RetVal(RetValType, FDelegateName)
  • 最多8个函数参数:DECLARE_DELEGATE_<Num>Params(FDelegateName, Param1Type, ...)

例如,要声明一个函数签名为bool MyFunc(int32)的单播委托,宏应该这样写:DECLARE_DELEGATE_RetVal_OneParam(bool, FMyFunc, int32)

委托函数支持与UFUNCTION()相同的说明符,但使用UDELEGATE()而不是UFUNCTION()。例如:

UDELEGATE(BlueprintAuthorityOnly)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FInstigatedAnyDamageSignature, float, Damage, const UDamageType*, DamageType, AActor*, DamagedActor, AActor*, DamageCauser);

绑定

根据函数签名声明完委托后,就需要将它的实例和函数对象相绑定了。UE提供了如下主要的绑定函数,使用方式为DelegateInstance.BindXXX()

函数描述
Bind()绑定到现有委托对象
BindStatic()绑定原始C++指针全局函数委托
BindRaw()绑定原始C++指针函数委托,如果目标对象被删除,再调用Execute()ExecuteIfBound()会不安全
BindLambda()绑定一个Lambda函数
BindSP()绑定基于共享指针的成员函数委托,该类委托会保留对对象的弱引用,可用ExecuteIfBound()调用
BindUObject()绑定基于UObject的成员函数委托,该类委托会保留对你的对象UObject的弱引用,可用ExecuteIfBound()调用
Unbind()解绑委托

此外,如果想在创建实例时就进行绑定,可用FDelegateName::CreateXXXX(),它会返回一个绑定好的委托。

携带载荷

在绑定委托函数时还可以携带至多4个额外“载荷”变量(不支持动态委托),用于函数参数的传递:

MyDelegateInstance.BindRaw( &MyFunction, true, 20 );

执行

最后就能执行委托了,可直接用Execute()执行委托。但通常为了安全性,执行委托前需检查该委托实例是否已绑定,可通过IsBound()检查,或调用ExecuteIfBound()检查并执行。

多播委托

声明

多播委托函数签名的基础宏为DECLARE_MULTICAST_DELEGATE,并且不得使用返回值,其余操作和单播委托类似。

绑定

多播委托可以绑定多个函数,当委托触发时,将调用所有这些函数。因此绑定相关函数的语法和数组TArray类似:

函数说明
Add()添加函数委托至该多播委托的调用列表中
AddStatic()添加原始C++指针全局函数委托
AddRaw()添加原始C++指针函数委托,由于无法保证添加对象的生命周期,此行为不安全
AddLambda()添加不捕获指针的Lambda函数
AddSPLambda()添加只有在目标共享指针弱引用有效的情况下才被调用的Lambda函数
AddWeakLambda()添加只有在对UObject的弱引用有效的请胯下才被调用的Lambda函数
AddSP()添加基于共享指针的非线程安全成员函数委托,保留对对象的弱引用
AddUObject()添加基于UObject的成员函数委托,保留对对象的弱引用
Remove()从该多播委托的调用列表中删除函数,不保证调用顺序统一
RemoveAll()从该多播委托的调用列表中删除所有已注册委托,除了未绑定的对象指针的原始委托,不保证调用顺序统一

执行

多播委托使用Broadcast()函数一次性同时执行多个函数委托,可能已过期的对象除外。

动态委托

声明

动态委托的基础宏如下:

  • 动态单播:DECLARE_DYNAMIC_DELEGATE
  • 动态多播:DECLARE_DYNAMIC_MULTICAST_DELEGATE

绑定

动态委托用到辅助宏进行绑定操作:

辅助宏说明
BindDynamic(UserObject, FuncName)动态单播委托的绑定辅助宏
AddDynamic(UserObject, FuncName)动态多播委托用于添加绑定的辅助宏
RemoveDynamic(UserObject, FuncName)动态多播委托用于移除绑定的辅助宏

执行

动态委托同样使用Execute()ExecuteIfBound()执行。

参考资料