【UE·C++】虚幻引擎中的委托(代理) Delegate

        自从研读了部分虚幻引擎的C++源代码,并使用虚幻C++开发了4个多月以来,心中对虚幻的技术团队有一种莫名的崇拜,没想到他们能将C++用的如此出神入化,希望可以站在巨人的肩膀上,继续砥砺前行。

        今天来总结一下虚幻中的委托。

        委托模式,在面向对象设计模式也是一种很常见的模式:它可以看做是函数的抽象,是函数的“类”。委托的实例将代表一个具体的函数,一个委托可以搭载多个方法,所有的方法被依次唤起,可以使委托对象所搭载的方法并不需要属于同一类。(网上找的简单的定义),它常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系,监听者通过将响应函数绑定到委托上,使得委托触发时立即收到通知,并进行相关逻辑处理带着这句话,来继续往下看,在你大概明白后,回头再来看这句话,你会豁然开朗,但是也可以带着这句话继续往下看

        开发项目过程中有一个需求是用IHttpRequest接口封装下载器(其实还有个下载管理器,管理所有downloader,与本文无关,跳过)供蓝图使用,下载成功需要在蓝图中做相关处理。所以只能在C++中定义委托,蓝图中绑定委托,由于接触UE时间不是很长,所有对于UE4的委托也是一头雾水,什么单播,多播,静态委托,动态委托网上很多文章都是基本概念介绍,根本没有讲到核心关键点,经过我的简单摸索,也封装成功了,回头看看,真的非常简单。

UE4中的委托按照绑定委托函数的个数分为单播多播委托,又按照是否可暴露给蓝图分为静态动态委托,故可分为4种类型,其实还有一种委托类型-事件  

DECLARE_EVENT_[XXXParam(s)]

它本质上就是一个多播委托,但事件在定义的时候需要传入一个拥有者对象事件只有在该拥有者内部绑定委托才生效,源码注释中建议不要使用此类事件,就用普通的多播委托即可

在头文件 DelegateCombinations.h 中提供了多种宏用于定义不同的委托,在该头文件中委托的参数数量最多支持到9个参数

委托的大致使用流程

  • 声明委托类型
  • 定义委托类型变量
  • 通过委托变量绑定委托函数
  • 执行委托
  • 解绑委托函数

理论是程序的基石,我们先来看一下基本概念,基本概念我会用引擎中的用到委托的代码彻底加深印象

单播委托

单播只能绑定一个委托函数(执行委托时只能触发一个唯一绑定:只能通知一个人),所绑定的委托函数可以有返回值,也可以没有返回值。静态委托执行前最好检查是否绑定,否则会导致程序崩溃,如果重复进行绑定,会覆盖上一次的绑定

  • 声明单播委托

  • 绑定函数到单播委托

 UE给我们提供了很多绑定函数,可以绑定不同类型的函数到单播上,但是要注意的时,如果重复绑定的话,新的绑定会覆盖上一次绑定

BindRaw可以绑定非继承自UObject类的对象方法

  • 执行单播委托(单播和多播所调用的函数时不一样的,多播使用Broadcast)

单播的执行有两个函数Execute()ExecuteIfBound(),如果委托函数有参数和返回值也是在这个函数中传入的

Execute()函数会直接执行委托,并不会检查是否绑定,如果直接执行没有绑定的单播,程序会崩溃,所以我们使用Execute的时候通常会使用IsBound先判断一下
 

if(MySingleDelegate.IsBound())
{
    /*参数实在这里传递的**/
    MySingleDelegate.Execute(参数...);
}

ExecuteIfBound调用时会判断有没有进行了绑定再进行调用,免去了我们自己编写IsBound判断环节

但是返回值是bool,所以用ExecuteIfBound调用绑定的函数对象必须没有返回值

  • 解绑委托函数

直接调用UnBind()函数解绑就行了,没啥说的

多播委托

多播可以绑定多个委托函数(执行委托时可以触发多个绑定,同时通知多人)

  • 多播只能绑定无返回值的函数
  • 广播执行时会执行所有委托,但不一定是按照绑定顺序来的
  • 在广播执行时不需要判断是否绑定了委托函数,直接广播执行即可

下面看一下声明以及使用方式

  • 声明多播委托

 可以看到多播委托的声明宏,因为多播只能绑定无返回值函数

  • 绑定函数到多播委托

  • 执行多播委托

 多播执行不需要判断是否绑定,直接Broadcast()就好,有些特性在上面已经写了注意查看一下

动态委托

  • 动态委托名必须以F开头,为统一写法静态的一般也是用F命名但是不使用也是合法的
  • 动态委托绑定只需要函数名,但是只能够绑定UFUNCTION标记的函数
  • 动态委托执行时需要在类中按照函数名(绑定时传进来的)来查找对应的函数,因此执行速度相对来说会比较慢
  • 动态委托如果需要传入参数,在代理声明的时候,需要写出类型跟变量名,类型后面需要定义变量名,类型名和参数名都需要用逗号隔开(因为动态委托可以暴露给蓝图,所以需要名字) ,相对于静态委托可以只写类型,也可以像普通函数参数一样,类型名+空格+参数名

以上是动态委托i的共性,下面看一下动态委托的相关声明与使用的共同点

  • 声明动态委托

动态委托,跟静态委托声明方式差不多,只不过前面多了_DYNAMIC ,如下代码

DECLARE_DYNAMIC_DELEGATE_TwoParams(FSingleDynamicDelegate,int,InInt,float,Infloat);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMultiDynamicDelegate);

 绑定动态委托

 BindDynamic是绑定动态单播的,AddDynamic是绑定动态多播的,同样的,动态单播可以绑定有返回值的函数,动态多播也只能绑定无返回值的函数,其他函数跟静态差不多,不过多赘述

虽然动态委托都支持反射,序列化(可被蓝图调用),但是只有动态多播可被蓝图绑定,通过指定UPROPERTY(BlueprintAssignable),来实现蓝图调用,动态单播可以使用BlueprintReadWrite标记,然后在蓝图中使用它的实例(个人感觉没啥用,可能自己UE的火候没到)

动态多播C++定义委托蓝图中调用的例子(引擎中的使用方式另写一篇吧)

  • 定义动态多播委托类型
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FMultiDynamicDelegate,int,intInt,float,InFloat);
  • 利用动态多播类型,定义变量
UPROPERTY(BlueprintAssignable)
FMultiDynamicDelegate MultiDelegate;
  • 执行委托,为了方便我直接在我的类中定义一个函数执行
UFUNCTION(BlueprintCallable)
void ExecuteMultiDeldagte();

/*实现**/
void UAudioManager::ExecuteMultiDeldagte()
{
	MultiDelegate.Broadcast(111,222.f);
}

以上是多播在蓝图中使用的例子,是不是很简单

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值