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()
执行。