1、四种委托的基本概念
1.1 单播委托(Single-cast Delegate)
-
不带参数
- 声明方式:
DECLARE_DELEGATE(FMyDelegate);
- 广播方式:
MyDelegate.Execute();
- 回调签名:
void SomeFunction();
- 声明方式:
-
带参数
- 声明方式:
DECLARE_DELEGATE_OneParam(FMyDelegate, int32)
- 广播方式:
MyDelegate.Execute(42);
- 回调签名:
void SomeFunction(int32 Value);
- 声明方式:
说明: 单播委托适合用于一个事件只需要调用一个函数的情况,参数个数可以多个(所有委托的参数都可以0~9个),参数类型必须给,参数名随意,但回调函数中必须给参数名。
1.2 多播委托(Multi-cast Delegate)
-
不带参数
- 声明方式:
DECLARE_MULTICAST_DELEGATE(FMyMulticastDelegate);
- 广播方式:
MyMulticastDelegate.Broadcast();
- 回调签名:
void SomeFunction();
- 声明方式:
-
带参数
- 声明方式:
DECLARE_MULTICAST_DELEGATE_OneParam(FMyMulticastDelegate, int32);
- 广播方式:
MyMulticastDelegate.Broadcast(42);
- 回调签名:
void SomeFunction(int32 Value);
- 声明方式:
说明: 多播委托适合用于一个事件需要调用多个函数的情况。同样,参数名在声明时可选,但在回调函数签名中必须包含。
1.3 动态单播委托(Dynamic Delegate)
-
不带参数
- 声明方式:
DECLARE_DYNAMIC_DELEGATE(FMyDynamicDelegate);
- 广播方式:
MyDynamicDelegate.Execute();
- 回调签名:
UFUNCTION() void SomeFunction();
- 声明方式:
-
带参数
- 声明方式:
DECLARE_DYNAMIC_DELEGATE_OneParam(FMyDynamicDelegate, int32, Value);
- 广播方式:
MyDynamicDelegate.Execute(42);
- 回调签名:
UFUNCTION() void SomeFunction(int32 Value);
- 声明方式:
说明: 动态单播委托用于需要与蓝图交互的场景,它们可以在蓝图中绑定和解绑,回调函数必须使用 UFUNCTION()
修饰,以便在蓝图中进行绑定(C++中当然也可以)。带参数的动态委托在声明时必须指定参数名称,因为动态委托需要支持反射和序列化,参数名称需要反射到蓝图里面用。
1.4 动态多播委托(Dynamic Multicast Delegate)
-
不带参数
- 声明方式:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMyDynamicMulticastDelegate);
- 广播方式:
MyDynamicMulticastDelegate.Broadcast();
- 回调签名:
UFUNCTION() void SomeFunction();
- 声明方式:
-
带参数
- 声明方式:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMyDynamicMulticastDelegate, int32, Value);
- 广播方式:
MyDynamicMulticastDelegate.Broadcast(42);
- 回调签名:
UFUNCTION() void SomeFunction(int32 Value);
- 声明方式:
说明: 动态多播委托类似于动态单播委托,但可以绑定多个回调函数,同样需要 UFUNCTION()
修饰回调函数,并且在声明时必须包含参数名称。由于蓝图需要通过反射机制识别参数名称,因此在声明动态多播委托时,参数名称是必须的。
2. 委托的绑定方式
单播绑定回调的接口前缀都是:Bind
多播添加回调的接口前缀都是:Add
动态必须用后缀:Dynamic
,且回调函数必须带UFUNCTION()
标记
接口的后缀表示函数的类型:
- UObject子类的成员函数:
UObject
- 普通类的成员函数:
Raw
- 静态/全局函数:
Static
- Lambda表达式:
Lambda
2.1 单播委托
-
绑定普通成员函数
- 使用
BindUObject
绑定成员函数:MyDelegate.BindUObject(this, &MyClass::MyFunction);
- 使用
BindStatic
绑定静态函数或全局函数:MyDelegate.BindStatic(&MyStaticFunction);
- 使用
-
绑定Lambda表达式
- 使用
BindLambda
绑定Lambda:MyDelegate.BindLambda([]() { 。。。。 });
- 使用
说明: BindUObject
适用于绑定类的成员函数,this
指针需要指向类的实例。如果绑定静态函数或全局函数,则使用 BindStatic
。
2.2 多播委托
-
添加普通成员函数
- 使用
AddUObject
添加成员函数:MyMulticastDelegate.AddUObject(this, &MyClass::MyFunction);
- 使用
-
添加Lambda表达式
- 使用
AddLambda
添加Lambda:MyMulticastDelegate.AddLambda([]() { /* Your code here */ });
- 使用
-
添加静态函数或全局函数
- 使用
AddStatic
添加静态函数:MyMulticastDelegate.AddStatic(&MyStaticFunction);
- 使用
说明: 多播委托允许添加多个回调函数,每个回调函数都会在广播时依次被调用。AddUObject
用于绑定类的成员函数,AddStatic
用于绑定静态或全局函数。
2.3 动态单播委托
- 绑定到成员函数
- 使用
BindDynamic
绑定到成员函数:MyDynamicDelegate.BindDynamic(this, &MyClass::MyFunction);
- 使用
说明: 动态单播委托只能通过 BindDynamic
绑定到使用 UFUNCTION()
修饰的成员函数。这是因为动态委托需要支持反射,才能在蓝图中进行绑定和解绑。
2.4 动态多播委托
-
添加成员函数
- 使用
AddDynamic
添加成员函数:MyDynamicMulticastDelegate.AddDynamic(this, &MyClass::MyFunction);
- 使用
-
移除成员函数
- 使用
RemoveDynamic
移除绑定的成员函数:MyDynamicMulticastDelegate.RemoveDynamic(this, &MyClass::MyFunction);
- 使用
说明: 动态多播委托允许在运行时动态地添加和移除回调函数。同样,AddDynamic
绑定的函数必须是使用 UFUNCTION()
修饰的成员函数。
绑定方法说明
-
AddUObject()
与AddDynamic()
的区别AddUObject()
用于多播委托的非动态绑定,适合绑定成员函数,不需要UFUNCTION()
修饰。AddDynamic()
则用于动态多播委托的绑定,回调函数必须使用UFUNCTION()
修饰,以支持反射机制。
-
BindLambda()
与AddLambda()
的区别BindLambda()
用于单播委托绑定 Lambda 表达式,适合在需要灵活性且只需要一个回调的场景。AddLambda()
则用于多播委托,允许绑定多个 Lambda 表达式。
3、绑定回调的方式总结
绑定回调函数给委托的方法有很多,下面总结一下。
这只是其中一部分,举一反三,其他的方法看其注释即可了解如何使用以及使用场景
3.1 AddDynamic()
适用于
绑定到动态委托(DECLARE_DYNAMIC_MULTICAST_DELEGATE
或 DECLARE_DYNAMIC_DELEGATE
)的回调函数,回调函数必须是 UFUNCTION
。
签名
void AddDynamic(UserClass* InUserObject, UserClass::FuncType InFunc);
使用
Button->OnClicked.AddDynamic(this, &AMyActor::OnButtonClicked);
3.2 AddUObject()
适用于
将普通的 UObject 类成员函数绑定到委托,适用于非动态委托。回调函数不需要是 UFUNCTION
,可以是任何成员函数。
签名
void AddUObject(UserClass* InUserObject, UserClass::FuncType InFunc);
使用
SomeDelegate.AddUObject(this, &AMyActor::MyFunction);
3.3 AddLambda()
适用于
将一个匿名函数绑定到委托,适用于任何类型的委托。
签名
void AddLambda(TFunction<ReturnType(ParamTypes...)> Lambda);
使用
SomeDelegate.AddLambda([]() { });
3.4 AddRaw()
适用于
将普通的 C++ 类的成员函数绑定到委托。这种方法通常用于非 UObject 的普通 C++ 类,回调函数不需要是 UFUNCTION
,可以是任何成员函数。
签名
void AddRaw(UserClass* InUserObject, UserClass::FuncType InFunc);
使用
SomeDelegate.AddRaw(this, &AMyActor::MyFunction);
3.5 AddSP()
适用于
绑定智能指针类型的类成员函数,特别是 TSharedPtr
或 TWeakPtr
类型的对象。
签名
void AddSP(TSharedPtr<UserClass> InUserObject, UserClass::FuncType InFunc);
使用
SomeDelegate.AddSP(MySharedPtr, &MyClass::MyFunction);
3.6 AddUFunction()
适用于
动态地将一个 UFunction
绑定到委托。通常用于需要在运行时绑定某个 UFUNCTION
的情况,函数名以字符串形式提供。
签名
void AddUFunction(UObject* InUserObject, FName InFunctionName);
使用
TransformProxy->OnEndTransformEdit.AddUFunction(this, FName("OnEndWidgetCompTransformEdit"));
3.7 AddStatic()
适用于
将静态函数绑定到委托。静态函数不依赖于任何对象实例,因此它们不能访问类的成员变量或成员函数。
签名
void AddStatic(FuncType InStaticFunc);
使用
SomeDelegate.AddStatic(&MyStaticFunction);
3.8 BindLambda()
适用于
将一个 Lambda 表达式绑定到委托,与 AddLambda()
类似,但它是通过直接绑定的方式,而不是添加到已有的绑定列表中,如果之前有绑定的回调,这个操作会替换掉之前的回调函数。
签名
void BindLambda(TFunction<ReturnType(ParamTypes...)> Lambda);
使用
SomeDelegate.BindLambda([](int32 Param) { /* Your code here */ });
3.9 BindRaw()
适用于
与 AddRaw()
类似,但它是直接绑定到委托,而不是添加到绑定列表中。通常用于非 UObject 类的成员函数绑定,回调函数不需要是UFUNCTION
。
签名
void BindRaw(UserClass* InUserObject, UserClass::FuncType InFunc);
使用
SomeDelegate.BindRaw(this, &AMyActor::MyFunction);
3.10 BindUObject()
适用于
将 UObject 成员函数直接绑定到委托。
签名
void BindUObject(UserClass* InUserObject, UserClass::FuncType InFunc);
使用
SomeDelegate.BindUObject(this, &AMyActor::MyFunction);
3.11 BindSP()
适用于
将智能指针类型的类成员函数绑定到委托,特别是 TSharedPtr
或 TWeakPtr
类型的对象。
签名
void BindSP(TSharedPtr<UserClass> InUserObject, UserClass::FuncType InFunc);
使用
SomeDelegate.BindSP(MySharedPtr, &MyClass::MyFunction);
3.12 BindUFunction()
适用于
将一个 UFunction
绑定到动态委托。通常用于需要在运行时绑定某个 UFUNCTION
的情况,函数名以字符串形式提供。
签名
void BindUFunction(UObject* InUserObject, FName InFunctionName);
使用
SomeDelegate.BindUFunction(this, FName("MyUFunctionName"));
3.13 AddWeakLambda()
适用于
专门为弱引用对象(如 TWeakObjectPtr
)设计的,防止由于绑定的对象已经销毁而导致的崩溃,当绑定的对象被销毁时,不会执行 Lambda 表达式。。
签名
void AddWeakLambda(TWeakObjectPtr<UserClass> InWeakObjectPtr, TFunction<ReturnType(ParamTypes...)> InLambda);
使用
SomeDelegate.AddWeakLambda(WeakObjectPtr, [](int32 Param) { });