UE5 C++中的委托详细说明

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_DELEGATEDECLARE_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()

适用于
绑定智能指针类型的类成员函数,特别是 TSharedPtrTWeakPtr 类型的对象。

签名

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()

适用于
将智能指针类型的类成员函数绑定到委托,特别是 TSharedPtrTWeakPtr 类型的对象。

签名

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) { });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宗浩多捞

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值