介绍

官方文档介绍

  • 委托本身是一种特殊对象
  • 委托可绑定任意对象的函数
  • 委托是一种观察者模式,当委托执行时,通知所有绑定到这个委托的对象

定义委托类的宏可以在DelegateCombinations.h查看,这里只暂时只展示了无参数的宏。这些宏用于声明和定义一个委托类。

#define DECLARE_DELEGATE( DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, void )
#define DECLARE_MULTICAST_DELEGATE( DelegateName ) FUNC_DECLARE_MULTICAST_DELEGATE( DelegateName, void )
#define DECLARE_EVENT( OwningType, EventName ) FUNC_DECLARE_EVENT( OwningType, EventName, void )
#define DECLARE_DYNAMIC_DELEGATE( DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, , FUNC_CONCAT( *this ), void )
#define DECLARE_DYNAMIC_MULTICAST_DELEGATE( DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, , FUNC_CONCAT( *this ), void )
#define DECLARE_DELEGATE_RetVal( ReturnValueType, DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, ReturnValueType )
#define DECLARE_DYNAMIC_DELEGATE_RetVal( ReturnValueType, DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE_RETVAL( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, ReturnValueType, , FUNC_CONCAT( *this ), ReturnValueType )

从上往下一次是:

  • 单播委托:只能绑定一个函数
  • 多播委托:可绑定多个函数
  • 事件:特殊的多播委托,只能在指定类中触发
  • 动态单播委托:只能绑定一个函数,可暴露给蓝图使用
  • 动态多播委托:能绑定多个函数,可暴露给蓝图使用
  • 单播委托_带返回值:以上只能绑定void函数,这个可绑定带返回值的函数,并可使用返回值
  • 动态单播委托_带返回值:同上,可暴露给蓝图使用

可以看到关键词的意义:
单播:只能绑定一个函数
多播:可绑定多个函数
动态:可给蓝图使用
带返回值:可绑定带返回值的函数,并可获取返回值(所以也只支持单播)
事件:类限定的多播

翻看Actor.h会发现其使用的是稀疏动态多播代理,如下。

DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam(FActorDestroyedSignature, AActor, OnDestroyed, AActor*, DestroyedActor );
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams(FActorEndPlaySignature, AActor, OnEndPlay, AActor*, Actor , EEndPlayReason::Type, EndPlayReason);

源码中的解释:

稀疏的委托可以用于不经常绑定的委托,以便对象仅使用1个字节的存储空间,而不用承担委托调用列表的全部开销。 从委托中调用,添加,删除等的成本高于直接使用委托的成本,因此应在节省内存的好处与期望绑定委托的频率之间进行权衡。

委托的使用

委托的使用可分为4个步骤:

  • 声明委托(委托签名):使用宏声明和定义一个委托类,表明委托可接受的函数签名
  • 创建委托:在需要执行委托的类中声明一个委托成员变量
  • 执行委托:执行委托,会触发绑定的函数
  • 绑定委托:将委托执行时触发的对象成员函数绑定到这个委托上

以上是按照开发时写代码的顺序,实际运行时是绑定在前、执行在后。

示例:

// 1.声明和定义一个委托类
DECLARE_DELEGATE(FMyDelegate);class  FMyObject
{public:void MyFunction();// 2.创建一个委托成员变量FMyDelegate MyDeleage;
};void FMyObject::MyFunction()
{// 3.执行委托MyDelegate.ExecuteIfBound();
}
// 4. 在其它的地方,需要将函数绑定到委托上class  FObserver
{public:void Begin();void Test();FMyObject MyObject;
};void FObserver::Begin()
{// 4.找个地方绑定委托// 当MyObject的MyDeleage执行的时候,就会触发Test函数MyObject.MyDeleage.BindRaw(this,&FObserver::Test);
}

上面的例子只是简单的示例,实际使用时可参考UE4引擎中的例子,比如Actor中的碰撞事件、伤害事件、点击事件等。

各种委托使用的快速参考

  • 通常单播委托执行使用ExecuteIfBound(),多播委托执行使用Broadcast()。
  • 通常什么类声明,什么类就负责执行委托。
  • 通常单播委托绑定使用Bind**(),多播委托绑定使用Add**()。
  • 适应性最广的是动态多播委托。如果只是给C++用则使用多播委托。
  • 用于绑定的函数应该与委托签名一致。

单播委托

  • 定义委托类
DECLARE_DELEGATE(FMyDelegate);//不带参数
DECLARE_DELEGATE_OneParam(FMyDelegate1, int32);//带一个int32类型的参数
DECLARE_DELEGATE_TwoParams(FMyDelegate2, int32, float);//带一个int32和float类型的参数
  • 创建委托变量
// 假设放在MyObject中
FMyDelegate MyDelegate;
FMyDelegate1 MyDelegate1;
FMyDelegate2 MyDelegate2;
  • 执行
MyDelegate.ExecuteIfBound();
MyDelegate1.ExecuteIfBound(1);
MyDelegate2.ExecuteIfBound(1, 0.5f);
  • 绑定和解绑
//假设为了触发FMyObject2中的MyFunction函数。
MyObject->MyDelegate.BindRaw(this,&FMyObject2::MyFunction);//this为非UObject对象,最好不用,使用BindSP代替
MyObject->MyDelegate.BindUObject(this,&FMyObject2::MyFunction);//this为UObject对象
MyObject->MyDelegate.BindUFunction(this,FName("MyFunction"));//最好不用,使用BindUObject代替
MyObject->MyDelegate.BindSP(MyObject2Ptr,&FMyObject2::MyFunction);//MyObject2Ptr为共享指针
MyObject->MyDelegate.BindStatic(&FMyObject2::MyFunction);//MyFunction为static函数
MyObject->MyDelegate.BindLambda([](){});//绑定一个Lambda函数MyObject->MyDelegate.UnBind();//解除绑定

多播委托

  • 定义委托类
DECLARE_MULTICAST_DELEGATE(FMyDelegate);//不带参数
DECLARE_MULTICAST_DELEGATE_OneParam(FMyDelegate1, int32);//带一个int32类型的参数
DECLARE_MULTICAST_DELEGATE_TwoParams(FMyDelegate2, int32, float);//带一个int32和float类型的参数
  • 创建委托变量
// 假设放在MyObject中
FMyDelegate MyDelegate;
FMyDelegate1 MyDelegate1;
FMyDelegate2 MyDelegate2;
  • 执行
MyDelegate.Broadcast();
MyDelegate1.Broadcast(1);
MyDelegate2.Broadcast(1, 0.5f);
  • 绑定和解绑
//假设为了触发FMyObject2中的MyFunction函数。
MyObject->MyDelegate.AddRaw(this,&FMyObject2::MyFunction);//this为非UObject对象,最好不用,使用BindSP代替
MyObject->MyDelegate.AddUObject(this,&FMyObject2::MyFunction);//this为UObject对象
MyObject->MyDelegate.AddUFunction(this,FName("MyFunction"));//最好不用,使用BindUObject代替
MyObject->MyDelegate.AddSP(MyObject2Ptr,&FMyObject2::MyFunction);//MyObject2Ptr为共享指针
MyObject->MyDelegate.AddStatic(&FMyObject2::MyFunction);//MyFunction为static函数
MyObject->MyDelegate.AddLambda([](){});//绑定一个Lambda函数MyObject->MyDelegate.Remove(this,&FMyObject2::MyFunction);//解除绑定
MyObject->MyDelegate.RemoveAll();//解除绑定

动态单播委托

“动态”意味着可以给蓝图使用,限制是但是只能绑定UFUNCTION宏标记的函数。

  • 定义委托类
DECLARE_DYNAMIC_DELEGATE(FMyDelegate);//不带参数
DECLARE_DYNAMIC_DELEGATE_OneParam(FMyDelegate1, int32);//带一个int32类型的参数
DECLARE_DYNAMIC_DELEGATE_TwoParams(FMyDelegate2, int32, float);//带一个int32和float类型的参数
  • 创建委托变量
// 假设放在MyObject中
FMyDelegate MyDelegate;
FMyDelegate1 MyDelegate1;
FMyDelegate2 MyDelegate2;
  • 执行
MyDelegate.ExecuteIfBound();
MyDelegate1.ExecuteIfBound(1);
MyDelegate2.ExecuteIfBound(1, 0.5f);
  • 绑定和解绑
//假设为了触发FMyObject2中的MyFunction函数。
MyObject->MyDelegate.BindDynamic(this,&FMyObject2::MyFunction);//this为UObject对象MyObject->MyDelegate.UnBind();//解除绑定

动态多播委托

  • 定义委托类
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMyDelegate);//不带参数
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMyDelegate1, int32);//带一个int32类型的参数
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FMyDelegate2, int32, float);//带一个int32和float类型的参数
  • 创建委托变量
// 假设放在MyObject中
FMyDelegate MyDelegate;
FMyDelegate1 MyDelegate1;
FMyDelegate2 MyDelegate2;
  • 执行
MyDelegate.Broadcast();
MyDelegate1.Broadcast(1);
MyDelegate2.Broadcast(1, 0.5f);
  • 绑定和解绑
//假设为了触发FMyObject2中的MyFunction函数。
MyObject->MyDelegate.AddDynamic(this, &FMyObject2::MyFunction);//最好不用,使用BindUObject代替MyObject->MyDelegate.Remove(this, &FMyObject2::MyFunction);//解除绑定
MyObject->MyDelegate.RemoveAll();//解除绑定

蓝图中委托的创建

  • 蓝图中的事件通常表示一个在EventGraph中的一个函数(其实就是一个void函数),比如BeginPlay,Tick等。
  • 委托在蓝图中叫EventDispatchers,只能绑定void函数。

C++创建

对于动态(单播或多播)委托,只需要用UPROPERTY(BlueprintAssignable)标记,即可暴露给蓝图使用。

// 假设放在MyObject中
UPROPERTY(BlueprintAssignable)
FMyDelegate MyDelegate;

蓝图中创建,使用

蓝图中是创建一个Event Dispatchers,相当于一个动态多播委托。

UE4中的委托和事件相关推荐

  1. C#中的委托和事件(续)

    引言 如果你看过了 C#中的委托和事件 一文,我想你对委托和事件已经有了一个基本的认识.但那些远不是委托和事件的全部内容,还有很多的地方没有涉及.本文将讨论委托和事件一些更为细节的问题,包括一些大家常 ...

  2. C# 中的委托和事件

    引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去 ...

  3. C# 中的委托和事件(1)

    C# 中的委托和事件 欢迎浏览本文的后续文章: C#中的委托和事件(续) PDF 浏览:http://www.tracefact.net/Document/Delegates-and-Events-i ...

  4. 艾伟_转载:C#中的委托和事件-抛砖引玉

    最近在学习委托和事件,在书店里面看了好多书,但是都是迷迷的-- 今天在博客园里面看到了 张子阳 所写的博客C#中的委托和事件:http://www.tracefact.net/CSharp-Progr ...

  5. C# 中的委托和事件(转载)

    C# 中的委托和事件 (今天去因为委托和事件这两个东西把我搞得头疼死了,偶然发现这篇文章,觉得非常不错,就copy过来了!) 引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而 ...

  6. [转]C#中的委托和事件(续)

    源码下载:http://www.tracefact.net/SourceCode/MoreDelegate.rar C#中的委托和事件(续) 引言 如果你看过了 C#中的委托和事件 一文,我想你对委托 ...

  7. 【转】C# 中的委托和事件

    阅读目录 C# 中的委托和事件 引言 将方法作为方法的参数 将方法绑定到委托 事件的由来 事件和委托的编译代码 委托.事件与Observer设计模式 .Net Framework中的委托与事件 总结 ...

  8. C# 中的委托和事件[转]

    引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去 ...

  9. C# 中的委托和事件(详解) ....

    C# 中的委托和事件 委托和事件在 .NET Framework 中的应用非常广泛,然而,较好地理解委托和事件对很多接触 C# 时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太 ...

  10. [轉]C# 中的委托和事件

    轉自:http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html pdf:http://www.tracefact.net/Doc ...

最新文章

  1. 《走出软件作坊》书评活动图书奖品名单
  2. 体验Rabbitmq强大的【优先级队列】之轻松面对现实业务场景
  3. 常用的HTML标签(超文本标记语言)
  4. Java基础——Java异常处理机制
  5. TimeSpan 用法 求离最近发表时间的函数
  6. zip在python中的用法_Python中zip()函数用法实例教程
  7. [WebApi] 捣鼓一个资源管理器--数据库辅助服务器文件访问
  8. 二元函数连续性、可导性及极限
  9. Sentaurus TCAD模型创建、激活电极等
  10. 人体的神经系统图 分布,人的神经系统分布图
  11. 或是独体字吗_独体字
  12. 银河麒麟v10离线安装docker-ce
  13. 12000字解读安踏:DTC中国化的“热血战纪”
  14. Vue开发实例(11)之el-menu实现左侧菜单导航
  15. 来自全网超火的Android面试笔记GitHub下载量过百万
  16. Java mail Exchange Service
  17. Lua 5.4.4函数、模块注册
  18. 专精特新软件开发类企业实力指数发布,麒麟信安荣誉登榜
  19. python绘制彩色地震剖面断层解释_python绘制地震散点图
  20. 关于对话系统(任务式/检索式/生成式)的若干总结

热门文章

  1. Java8中Map新方法:compute使用详解
  2. 腾讯觅影正式对外开放,可用AI进行医学图像分析和辅助诊疗
  3. 解决Windows Server 2008 System进程占用80端口问题
  4. Redis的基本操作
  5. iOS开发iPhone竖屏icon尺寸与启动页尺寸汇总
  6. Nginx配置防盗链和内核参数优化
  7. php url中文转码
  8. 圆柱体的表面积,三位数反转,交换变量
  9. 笑坏肚皮的俏皮男女趣语
  10. 正则表达式——特殊字符(MyBatis)