虚幻学习笔记17—C++委托(单播)

一、前言

        相比“代理”这个名词我更喜欢叫“委托”,虚幻的委托分为三类,分别为单播、多播和动态多播。单播顾名思义就是一次只能绑定一个函数的委托,多播能一次性绑定多个,动态多播即可以在蓝图中进行动态的绑定且可以绑定多个。

        使用的虚幻版本为5.2.1,VS版本为2022。

二、实现

        在虚幻中创建一个Actor类,命名为“DelegateActor”类。

 1、定义类型

单播可以定义带参数、返回值和参数+返回值三类委托,如下代码所示,分别定义了这三类单播委托,所有的说明见注释部分

DECLARE_DELEGATE(NoParamDelegate);//没有参数没有返回值的委托,委托名称为“NoParamDelegate”
DECLARE_DELEGATE_OneParam(OneParamDelegate, FString);//一个参数没有返回值的委托,名称为“OneParamDelegate”
DECLARE_DELEGATE_TwoParams(TwoParamDelegate, FString, int32);//两个参数没有返回值的委托,名称为“TwoParamDelegate”
DECLARE_DELEGATE_RetVal(FString, OnlyRetDelegate);//仅仅是返回值的委托,名称为“OnlyRetDelegate”
DECLARE_DELEGATE_RetVal_OneParam(FString, RetOneParamDelegate, FString);//定义了带参数和返回值的委托,第一个参数为返回值,第二个为委托名称,第三个为返回值
2、声明委托类型变量

上述定义的可以将其看作是一个类型定义,要真正使用还需要在类中声明该类型的变量,如下所示

	//单播代理变量的声明NoParamDelegate NoParamDelegate;OneParamDelegate OneParamDelegate;TwoParamDelegate TwoParamDelegate;OnlyRetDelegate OnlyRetDelegate;RetOneParamDelegate RetOneParamDelegate;

注:C++中居然允许变量名称可以和委托名称一样,这样带来的问题是后续想再定义一个同类型的委托变量就会报错。如图2.1.1所示

图2.1.1
因此最好还是将变量名称不要定义成和类型名称一样
	NoParamDelegate NoParamDelegate1;NoParamDelegate NoParamDelegate2;OneParamDelegate OneParamDelegate1;TwoParamDelegate TwoParamDelegate1;OnlyRetDelegate OnlyRetDelegate1;
3、定义委托需要绑定的函数

        定义的函数要和对应的委托保持一致的返回值和参数。

	//单播代理绑定函数定义void NoParamDelegateFunc1();void NoParamDelegateFunc2();void OneParamDelegateFunc(FString strVal);void TwoParamDelegateFunc(FString strVal, int32 intVal);FString OnlyRetDelegateFunc();FString RetOneParamDelegateFunc(FString strVal);

其实现代码如下,注:FString作为返回值时,不能直接返回声明的FString类型变量tempStr,必须返回FString(tempStr)这样的结构。


void ADelegateActor::NoParamDelegateFunc1()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("NoParamDelegateFunc1")));
}void ADelegateActor::NoParamDelegateFunc2()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("NoParamDelegateFunc2")));
}void ADelegateActor::OneParamDelegateFunc(FString strVal)
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("OneParamDelegateFunc:%s"), *strVal));
}void ADelegateActor::TwoParamDelegateFunc(FString strVal, int32 intVal)
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("NoParamDelegateFunc:%s,%d"), *strVal, intVal));
}
FString ADelegateActor::OnlyRetDelegateFunc()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("OnlyRetDelegate")));return FString();
}FString ADelegateActor::RetOneParamDelegateFunc(FString strVal)
{FString tempStr = strVal.Append("RetOneParamDelegateFunc");return FString(tempStr);
}
4、 最后在构造函数或其他初始函数中进行绑定

            单播委托的绑定如下所示

	NoParamDelegate1.BindUObject(this, &ADelegateActor::NoParamDelegateFunc1);NoParamDelegate2.BindUObject(this, &ADelegateActor::NoParamDelegateFunc2);OneParamDelegate1.BindUObject(this, &ADelegateActor::OneParamDelegateFunc);TwoParamDelegate1.BindUObject(this, &ADelegateActor::TwoParamDelegateFunc);OnlyRetDelegate1.BindUObject(this, &ADelegateActor::OnlyRetDelegateFunc);RetOneParamDelegate1.BindUObject(this, &ADelegateActor::RetOneParamDelegateFunc);
5、执行

        通过如下代码进行执行,编译代码通过后,在编辑器中创建该类的蓝图并将其拖放到场景中运行即可看到每个函数的打印消息。

	NoParamDelegate1.ExecuteIfBound();NoParamDelegate2.ExecuteIfBound();OneParamDelegate1.ExecuteIfBound("TestStr");TwoParamDelegate1.ExecuteIfBound("TwoParam", 22222);OnlyRetDelegate1.Execute();//这个和上面的不一样FString tempStr = RetOneParamDelegate1.Execute("this is:");GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, tempStr);

注:带返回值的和不带返回值的执行函数是不一样的,这点官方文档也未作详细说明,敲代码的时候这个执行函数也不会提示,也是比较坑。

6、解绑与绑定新的函数

        解绑有点坑,官方文档写的是"UnBind",而实际上是“Unbind()"函数,而在使用了番茄助手的情况下又没有提示,敲完”UnBind“后一直报错

	NoParamDelegate.Unbind();

绑定新的函数,直接像之前一样添加绑定,绑定后会覆盖掉之前的,在执行的时候只会执行新的绑定函数。

	NoParamDelegate.BindUObject(this, &ADelegateActor::NoParamDelegateFunc2);

如图6.1.1所示为官方给定的其他绑定函数,不过官方没有案例说明,只有如图简单的介绍性说明,这点和Unity是没法比,所以针对每一个绑定只能自己去尝试使用一下。

图6.1.1

1)Bind

        绑定现有的委托对象,提示没有这个函数,暂时还不知道怎么使用。

2)BindStatic

        需要定义一个静态函数然后进行绑定,执行方法不变。

//定义
static void StaticNoParamDelegate();//实现
void StaticNoParamDelegate()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("BindStatic")));
}
//绑定全局静态函数
NoParamDelegate1.BindStatic(StaticNoParamDelegate);//绑定类中的静态函数
NoParamDelegate1.BindStatic(类名::静态函数名称);

注意:可以绑定类和全局的静态函数,这里和之前BindUObject中不同的是参数前不用”&“运算符。

3)BindRaw

       绑定不是继承虚幻UObject类的函数,这个和BindUObject正好相反。首先需要在虚幻中创建一个不继承任何东西的类

然后在其类中顶一个不带参数和返回值的函数 

//函数定义void Raw_NoParamDelegateFunc();//函数实现
void MyRawClass::Raw_NoParamDelegateFunc()
{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, FString::Printf(TEXT("Raw_NoParamDelegateFunc")));
}

注:在不经常虚幻基础类的其他类中也可以使用虚幻引擎的打印屏幕函数。

绑定这个函数

	MyRawClass* tempRawClass = new MyRawClass();NoParamDelegate1.BindRaw(tempRawClass, &MyRawClass::Raw_NoParamDelegateFunc);

注意绑定的参数第一个是对象指针,如下所示是另一种创建对象方式(这都是C++的基础,(;´༎ຶД༎ຶ`) 

	MyRawClass tempRawClass;NoParamDelegate1.BindRaw(&tempRawClass, &MyRawClass::Raw_NoParamDelegateFunc);

4)BindLambda

绑定一个Lambda表达式,Lambda表达式是一个匿名函数片段,即可以在函数内单独定一个一段函数,代码如下,使用关键字auto,其中”auto LambdaDelegateFunc = []()->void“,()里面可以添加参数,返回值可以将void类型改成其他返回值类型。

	auto LambdaDelegateFunc = []()->void{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("LambdaDelegateFunc")));};NoParamDelegate1.BindLambda(LambdaDelegateFunc);

Lambda表达式也可以直接写在要绑定的方法参数里,这个比上面的更简便,完全没有函数名

	NoParamDelegate1.BindLambda([]()->void{GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Green, FString::Printf(TEXT("LambdaDelegateFunc")));});

5)BindSP

        绑定SharedPtr(智能指针)指向对象的函数,即纯C++类(非继承虚幻基类的类)的函数。因为纯C++类一般会使用TSharedPtr用于管理内存。

	//绑定智指针TSharedRef<MyRawClass> ObjSP1 = MakeShareable(new MyRawClass());NoParamDelegate1.BindSP(ObjSP1, &MyRawClass::Raw_NoParamDelegateFunc);

注意,这段绑定函数不要和之前的函数一样放在构造函数中,否则会出现绑定不成功的情况。

6)BindUObject

       绑定继承了虚幻引擎基类的类成员函数,前面案例中已经介绍使用,不再赘述。 

三、总结

3.1、单播可以定义三类委托,分别为带参数、返回值和参数+返回值。

3.2、声明委托的时候变量名称最好不要喝类型名称一样。

3.3、要绑定的函数和定义的委托在参数和返回值上要一致。

3.4、带返回值的和不带返回值的执行函数是不一样的。

3.5、解绑不是"UnBind",而实际上是“Unbind()"函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/225124.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mybatisplus使用雪花id通过swagger返回ID时精度丢失问题

在使用mybatisplus自带雪花的时候会发现返回的ID是19位的长度&#xff0c;因此在通过swagger页面展示的时候会发现后端返回的和页面展示的ID不一致问题。是因为精度丢失的问题。因此需要更改雪花ID的长度跟踪进去&#xff1a;发现是DefaultIdentifierGenerator类实现了Identifi…

蓝桥杯专题-真题版含答案-【扑克牌排列】【放麦子】【纵横放火柴游戏】【顺时针螺旋填入】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

【Redis】【MySQL】redis与mysql的慢查询

redis和mysql都存在对于慢查询的日志记录&#xff0c;下面将叙述一下两者的慢查询。 一&#xff0c;redis[1] redis的慢查询日志本质上是一个list对象&#xff0c;不过redis并没有提供慢查询日志的key。开发者可以通过下列命令查询慢查询日志&#xff1a; #获得慢查询日志&a…

Python Pandas 如何给DataFrame增加一行/多行 数据(第6讲)

Python Pandas 如何给DataFrame增加一行/多行 数据(第6讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ…

目标检测YOLO系列从入门到精通技术详解100篇-【图像处理】人脸识别

目录 前言 算法原理 网络压缩(network compression) 视觉问答(visual question answering)

读书笔记:《汽车构造与原理》

《透视汽车会跑的奥秘》《汽车为什么会跑&#xff1a;底盘图解》《汽车为什么会跑&#xff1a;图解汽车构造与原理》 一、心脏&#xff1a;发动机 活塞往复运动转化为曲轴的旋转运动 活塞&#xff1a;膝关节活塞连杆&#xff1a;小腿曲轴&#xff1a;自行车脚踏板 四冲程&…

GZ015 机器人系统集成应用技术样题2-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题2 选手须知&#xff1a; 本任务书共 25页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

QT-坦克大战游戏

QT-坦克大战游戏 一、演示效果二、关键程序三、下载链接 一、演示效果 二、关键程序 #include "score.h" Score::Score(){health30; maxHealthhealth;QLabel *label1 new QLabel(this);label1->setFrameStyle(QFrame::Plain | QFrame::Box);label1->setStyle…

将 Github token 添加至远程仓库

将 Github token 添加至远程仓库后便于每次 push 重复输入的麻烦 首先,将已生成的 token 记录(注:生成后的 token 确认后便无法查看只能重新生成)并找到对应的项目 git 本地文件路径下 其次,将其与项目所关联,按如下格式配置即可 token 格式类似于 ghp_CAxxxxxxxxxxxxxxxxxGx5j…

常见ORM 框架

特点MyBatisHibernateJPA (Java Persistence API)SQL 控制支持开发者编写和管理自己的 SQL 语句对 SQL 抽象程度更高&#xff0c;Hibernate 提供 HQL对 SQL 抽象程度高&#xff0c;定义更抽象的查询条件映射方式XML 或注解方式映射 SQL 查询结果到 Java 对象基于注解或 XML 配置…

竞赛保研 python+深度学习+opencv实现植物识别算法系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的植物识别算法研究与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 更多…

Oracle日期加减

1.直接加减数字 SELECT SYSDATE "当前时间", SYSDATE 1 "加一天", SYSDATE (1 / 24) "加一小时", SYSDATE (1 / 24 / 60) "加一分钟", SYSDATE (1 / 24 / 60 / 60) "加一秒钟", SYS…

AI人工智能在建筑智能化工程设计的应用

AI人工智能在建筑智能化工程设计的应用 相关政策&#xff1a; 建筑智能化工程设计资质是为了合理设计各种智能化系统&#xff0c;让它们有机地结合成为有效的整体作用。在工程设计标准中&#xff0c;智能化资质设计全称为建筑智能化系统专项设计资质。企业一旦具备智能化设计资…

vue 使用 Echarts做地图及飞线效果

前言&#xff1a; 效果图 一. 项目中安装以及引入Echarts 1.1 npm 命令安装echarts库 npm install echarts --save 1.2 yarn命令安装echarts库 yarn add echarts 1.3 引用 a. 在使用页面上引入 在Vue组件的script标签中引入echarts库 使用 echarts import * as echarts f…

动态面板简介以及ERP原型图案列

动态面板简介以及ERP原型图案列 1.Axure动态面板简介2.使用Axure制作ERP登录界面3.使用Asure完成左侧菜单栏4.使用Axuer完成公告栏5.使用Axuer完成左边侧边栏 1.Axure动态面板简介 在Axure RP中&#xff0c;动态面板是一种强大的交互设计工具&#xff0c;它允许你创建可交互的…

【C#】Microsoft C# 之 LINQ 查询语法视频学习总结

1、LINQ - 限制操作符&#xff08;Restriction Operators&#xff09; The where clause of a LINQ query restricts the output sequence. Only the elements that match a condition are added to the output sequence.译文&#xff1a;LINQ查询的where子句限制了输出顺序。…

mysql数据库损坏后重装,数据库备份

重装 先卸载 sudo apt-get remove --purge mysql-server mysql-client mysql-common sudo apt-get autoremove sudo apt-get autoclean 然后重新安装MySQL: sudo apt-get install mysql-server mysql-client 首先要先使用无密码登录数据库一定要使用 sudo mysql -uroo…

TOGAF—架构(Architecture)项目管理

一、简介 1.1概述 架构(Architecture)项目在本质上通常是复杂的。他们需要适当的项目管理来保持正轨并兑现承诺。本指南适用于负责规划和管理架构(Architecture)项目的人员。我们解释了如何用事实上的方法和标准(如PRINCE2或PMBOK)来补充TOGAF架构开发方法(ADM),以加…

跨站点分布式多活存储建设方案概述

1-伴随着私有云、海量非结构数据的爆炸性增长&#xff0c;软件定义存储已经成为用户构建“敏捷IT” 架构的数据基石&#xff0c;同时越来越多的关键业务接入“敏捷IT” 架构。在分布式软件定义存储的产品架构下&#xff0c;怎样既保证对爆炸数据量的平稳承接&#xff0c;又能对…

C#Winform菜鸟驿站管理系统-快递信息管理界面多条件查询实现方法

1&#xff0c;具体的页面设计如下&#xff0c; 2&#xff0c; 关于下拉框数据填充实现&#xff0c;站点选择代码实现如下&#xff0c;因为站点加载在很多界面需要用到&#xff0c;所以把加载站点的方法独立出来如下&#xff1b; /// <summary>/// 加载站点下拉框/// <…