虚幻学习笔记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.hqwc.cn/news/277750.html

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

相关文章

jmeter,动态参数之随机数、随机日期

通过函数助手&#xff0c;执行以下配置&#xff1a; 执行后的结果树&#xff1a; 数据库中也成功添加了数据&#xff0c;对应字段是随机值&#xff1a;

[C++]——学习模板

了解模板——初阶 前言&#xff1a;一、模板1.1 什么是模板1.2 模板的概念1.3 模板可以做什么1.4 泛型模板 二、函数模板2.1 函数模板概念和格式2.2 函数模板原理2.3 函数模板实例化2.3.1 隐式实例化2.3.2 显式实例化 2.4 模板参数的匹配原则2.5 函数模板声明定义分离 三、类模…

克隆虚拟环境

conda虚拟环境 克隆clone 在服务器上想要使用别人搭好的环境&#xff0c;但是又怕自己对环境的修改更新会影响他人的使用&#xff0c;这个时候可以使用conda命令进行复制环境。 首先假设已经安装了Anaconda。 根据已有环境名复制生成新的环境 1、假设已有环境名为A&#xff0c…

Vue 子传父 组件传参 defineEmits

defineEmits 属性&#xff1a;用于创建自定义事件&#xff0c;接收子组件传递过来的数据。 注意&#xff1a;如果自定义事件的名称&#xff0c;和原生事件的名称一样&#xff0c;那么只会触发自定义事件。 defineEmits 仅适用于 setup 语法糖&#xff0c;其它写法请见&#x…

issue unit

The Issue Unit issue queue用来hold住&#xff0c;已经dispatched&#xff0c;但是还没有执行的uops&#xff1b; 当一条uop的所有的operands已经ready之后&#xff0c;request请求会被拉起来&#xff1b;然后issue select logic将会从request bit 1的slot中&#xff0c;选择…

【Spring】05 生命周期之初始化回调

文章目录 1. 回调是什么2. 初始化回调2.1 实现 InitializingBean 接口2.2 配置 init-method 3. 执行顺序4.优势及应用总结 在 Spring 框架中&#xff0c;生命周期回调&#xff08;Lifecycle Callbacks&#xff09;是一种强大的机制&#xff0c;它允许我们在 Spring 容器中的 Be…

十几个软件测试实战项目【外卖/医药/银行/电商/金融】

项目一&#xff1a;ShopNC商城 项目概况&#xff1a; ShopNC商城是一个电子商务B2C电商平台系统&#xff0c;功能强大&#xff0c;安全便捷。适合企业及个人快速构建个性化网上商城。 包含PCIOS客户端Adroid客户端微商城&#xff0c;系统PC后台是基于ThinkPHP MVC构架开发的跨…

焊盘:十字连接VS全覆盖 铺铜

在铺铜规则中&#xff0c;焊盘连接方式有两种&#xff1a; 十字连接 优点&#xff1a;较好焊接&#xff1a;因铺铜面积减少&#xff0c;温度下降速度降低&#xff0c;较好焊接&#xff0c;不易虚焊。 缺点&#xff1a;载流能力较弱&#xff1a;铺铜面积↓ → 载流能力↓全连接…

Flink 数据集类型

现实世界中&#xff0c;所有的数据都是以流式的形态产生的&#xff0c;不管是哪里产生的数据&#xff0c;在产生的过程中都是一条条地生成&#xff0c;最后经过了存储和转换处理&#xff0c;形成了各种类型的数据集。如下图所示&#xff0c;根据现实的数据产生方式和数据产生是…

面对同行恶意排挤,佳卫苗灭杀病毒HPV向市场发出灵魂五问

近期&#xff0c;抗HPV市场因为一款名叫“佳卫苗灭杀病毒HPV”的产品诞生而风起云涌。上市之初&#xff0c;产品方便表示&#xff0c;佳卫苗灭杀病毒HPV的诞生&#xff0c;不仅是为了造福患者&#xff0c;更是为了优化市场、刺激行业升级&#xff0c;以“机理更科学、材料更先进…

【开源软件】最好的开源软件-2023-第14名 Appsmith

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

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

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