学习虚幻C++开发日志——委托(持续更新中)

委托

官方文档:Delegates and Lamba Functions in Unreal Engine | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community

简单地说,委托就像是一个“函数指针”,但它更加安全和灵活。它允许程序在运行时动态地调用不同的函数。

(1)解耦对象间的关联

委托允许对象之间以松散耦合的方式进行通信。通过委托,一个对象可以在不直接引用另一个对象的情况下,通知其执行特定的操作。这有助于降低对象之间的依赖性和耦合度,从而提高代码的灵活性和可维护性。

(2)事件驱动编程

委托是实现事件驱动编程的关键机制之一。在事件驱动编程中,对象的行为是基于事件的发生来触发的。委托允许对象在事件发生时通知其他对象,并允许这些对象对事件做出响应。这种机制使得代码更加模块化,并易于扩展和维护。

(3)泛型且类型安全

委托提供了一种泛型但类型安全的方式,在C++对象上调用成员函数。通过委托,你可以动态地绑定到任意对象的成员函数,即使调用程序不知道对象的具体类型也可以进行操作。这增加了代码的灵活性和可重用性,同时保证了类型安全。

(4)异步通信

委托还支持异步通信。在虚幻引擎中,许多操作可能需要花费一些时间才能完成,如加载资源、执行物理模拟等。通过使用委托,你可以在不阻塞主线程的情况下,通知其他对象在异步操作完成后执行特定的操作。这有助于提高应用程序的响应性和性能。

(5)广播和多播

虚幻引擎中的委托还支持广播和多播机制。广播允许一个委托通知所有绑定的对象,而多播则允许一个委托通知多个指定的对象。这种机制使得在多个对象之间传递消息变得更加简单和高效。

(6)蓝图可视化编程支持

在虚幻引擎的蓝图可视化编程环境中,委托也扮演着重要的角色。通过委托,蓝图脚本可以轻松地与C++代码进行交互,从而实现更加复杂和灵活的游戏逻辑。此外,蓝图还支持动态多播委托的声明和使用,这使得在蓝图中处理事件和消息变得更加方便。

(7)复制和安全性

委托对象在复制时是很安全的。你可以通过值或引用来传递委托,但需要注意的是,通过值传递需要在堆上分配内存,这通常不是最佳实践。通过引用传递则更加高效且安全。

但传递引用,在异步的情况下会涉及到生命周期问题,容易崩溃,虚幻的委托大部分时候拷贝是安全的,因为它会存一个执行委托对象的弱引用,如果这对象消亡了,那么这个委托被调用的时候就不会执行。

委托的大致使用流程

  • 声明委托类型
  • 定义委托类型变量
  • 通过委托变量绑定委托函数
  • 执行委托
  • 解绑委托函数(可根据自身情况而实施)

1.单播

先创建一个继承于Actor的类,并在其头文件包含头文件(此处文件命名为LearnSingleDelegateActor)

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "LearnSingleDelegateActor.generated.h"

 并在源文件添加GameplayStatics.h头文件

#include"Kismet/GameplayStatics.h"

(1)声明委托类型 

DECLARE_DELEGATE(FLearnSingleDelegatePrintLocation);
DECLARE_DELEGATE_RetVal_OneParam(FVector,FLearnSingleDelegateGetLocation,FString);
//DECLARE_DELEGATE_RetVal_OneParam(ReturnType, DelegateName, ParamType);
//ReturnType:委托将要返回的值的类型。
//DelegateName:委托的名称,这个名称将用于在代码中引用这个委托类型。
//ParamType:委托将要接受的参数的类型。

如需声明委托,请使用下文所述的宏。请根据与委托相绑定的函数(或多个函数)的函数签名来选择宏。每个宏都为新的委托类型名称、函数返回类型(如果不是 void 函数)及其参数提供了参数。当前,支持以下使用任意组合的委托签名:

  • 返回一个值的函数。
  • 声明为常函数。
  • 最多4个"载荷"变量。
  • 最多8个函数参数。

注意:委托函数支持与UFunctions相同的说明符,但使用 UDELEGATE 宏而不是 UFUNCTION

(2)定义委托类型变量

在ALearnSingleDelegateActor类内定义变量

public:FLearnSingleDelegatePrintLocation SingleDelegatePrintLocation;FLearnSingleDelegateGetLocation SingleDelegateGetLocation;

(3)通过委托变量绑定委托函数

为方便在ALearnSingleDelegateActor类头文件再创建一个类,此处命名为LearnLocationActor(继承于Actor)

UCLASS()
class ALearnLocationActor : public AActor
{GENERATED_BODY()public:ALearnLocationActor();protected:virtual void BeginPlay() override;void PrintLocation();FVector GetLocation(FString InStr);//此处类型看委托声明处,与其相对应.
};

在此默认函数中创建根组件来便于观察委托操作 ,并对其他函数进行定义

ALearnLocationActor::ALearnLocationActor()
{RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("LocationRoot"));
}void ALearnLocationActor::PrintLocation()
{FVector MyLocation = GetActorLocation();UE_LOG(LogTemp, Warning, TEXT("[%s]__PrintMyLocation:[%s]"), *FString(__FUNCTION__), *MyLocation.ToString());//用于被绑定时观察步骤实现
}FVector ALearnLocationActor::GetLocation(FString InStr)
{FVector MyLocation = GetActorLocation();UE_LOG(LogTemp, Warning, TEXT("[%s]__GetMyLocation:[%s]"), *FString(__FUNCTION__), *MyLocation.ToString());return MyLocation;
}

 此处绑定函数

void ALearnLocationActor::BeginPlay()
{AActor *ActorPtr = UGameplayStatics::GetActorOfClass(this, ALearnSingleDelegateActor::StaticClass());if (ALearnSingleDelegateActor* SingleDelegateActorPtr=Cast<ALearnSingleDelegateActor>(ActorPtr)){//通过SingleDelegatePrintLocation此委托变量使用BindUObject函数模板绑定委托并调用一次绑定函数SingleDelegateActorPtr->SingleDelegatePrintLocation.BindUObject(this,&ALearnLocationActor::PrintLocation);SingleDelegateActorPtr->SingleDelegateGetLocation.BindUObject(this, &ALearnLocationActor::GetLocation);}
}

 官方模板函数

(4) 执行委托

为了观察实现步骤,我在LearnSingleDelegateActor类声明函数暴露给蓝图

	UFUNCTION(BlueprintCallable, Category = "Learn")void CallLocationActorPrint();UFUNCTION(BlueprintCallable, Category = "Learn")void CallLocationActorGet();

并对其进行定义

void ALearnSingleDelegateActor::CallLocationActorPrint()
{//第一种写法if (SingleDelegatePrintLocation.IsBound()){SingleDelegatePrintLocation.Execute();//SingleDelegatePrintLocation.Unbind();解绑操作}//第二种写法(建议用此写法)SingleDelegatePrintLocation.ExecuteIfBound();
}void ALearnSingleDelegateActor::CallLocationActorGet()
{FVector MyRecetivedLocation = SingleDelegateGetLocation.Execute(TEXT("My Single Delegate Actor"));UE_LOG(LogTemp, Warning, TEXT("[MyRecetivedLocation]__MyLocation:[%s]"), *MyRecetivedLocation.ToString());
}

 注意:对于无返回值的委托,可调用ExecuteIfBound()函数,但需注意输出参数可能未初始化。

(5)观察实现步骤(只做演示)

1、将两个类拖入场景中

2、在关卡蓝图处使用函数(此处是使用键盘1、2分别去激活函数)

3、启动关卡,并在输出日志观察

2.多播

3.动态单播

4.动态多播

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

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

相关文章

代替Spinnaker 的 POINTGREY工业级相机 FLIR相机 Python编程案例

SpinnakerSDK_FULL_4.0.0.116_x64 是一个用于FLIR相机的SDK&#xff0c;主要用于图像采集和处理。Spinnaker SDK主要提供C接口&#xff0c;无法直接应用在python环境。本文则基于Pycharm2019python3.7的环境下&#xff0c;调用opencv,EasySpin,PySpin,的库实现POINTGREY工业级相…

Linux:自定义Shell

本文旨在通过自己完成一个简单的Shell来帮助理解命令行Shell这个程序。 目录 一、输出“提示” 二、获取输入 三、切割字符串 四、执行指令 1.子进程替换 2.内建指令 一、输出“提示” 这个项目基于虚拟机Ubuntu22.04.5实现。 打开终端界面如图所示。 其中。 之前&#x…

在幸狐picomax SDK里面添加app

本次以onvifserver为例&#xff0c;在在幸狐picomax SDK里面添加app 具体步骤 修改编译器&#xff0c;把CCOMPILE&#xff0c; CPPCOMPILE&#xff0c; LINK 改为对应得编译器 把all 提到前面&#xff0c;保证在make得时候第一个执行得是all标签 install 分几步 创建out文件夹…

如何更改手机GPS定位

你是否曾想过更改手机GPS位置以保护隐私、玩游戏或访问受地理限制的内容&#xff1f;接下来我将向你展示如何使用 MagFone Location Changer 更改手机GPS 位置&#xff01;无论是在玩Pokmon GO游戏、发布社媒贴子&#xff0c;这种方法都快速、简单且有效。 第一步&#xff1a;下…

基于信号量与共享内存实现客户与服务器进程通信

基于信号量与共享内存实现客户与服务器进程通信 发送进程 代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <semaphore.h>#define SH…

【AI大模型引领变革】探索AI如何重塑软件开发流程与未来趋势

文章目录 每日一句正能量前言流程与模式介绍【传统软件开发 VS AI参与的软件开发】一、传统软件开发流程与模式二、AI参与的软件开发流程与模式三、AI带来的不同之处 结论 AI在软件开发流程中的优势、挑战及应对策略AI在软件开发流程中的优势面临的挑战及应对策略 结论 后记 每…

机器学习的全面解析:从基础到应用

引言&#xff1a;机器学习的核心地位 机器学习&#xff08;Machine Learning, ML&#xff09;是人工智能&#xff08;AI&#xff09;的核心分支&#xff0c;它通过算法使计算机能够从数据中学习并进行预测或决策。机器学习技术在许多领域都有广泛应用&#xff0c;包括推荐系统、…

Chapter 2 - 16. Understanding Congestion in Fibre Channel Fabrics

Transforming an I/O Operation to FC frames A read or write I/O operation (Figure 2-28) between an initiator and a target undergoes a series of transformations before being transmitted on a Fibre Channel link. 启动程序和目标程序之间的读取或写入 I/O 操作(图…

如何解决Java EasyExcel 导出报内存溢出

如何解决Java EasyExcel 导出报内存溢出 EasyExcel大数据量导出常见方法 1. 分批写入 EasyExcel支持分批写入数据&#xff0c;可以将数据分批加载到内存中&#xff0c;分批写入Excel文件&#xff0c;避免一次性将大量数据加载到内存中。 示例代码&#xff1a; String fileNa…

Qt 的事件投递机制:从基础到实战

在 Qt 开发中&#xff0c;事件系统是核心概念之一&#xff0c;几乎每一个 GUI 应用程序都依赖于它来响应用户操作和系统通知。对于有一定 Qt 基础但首次接触事件投递 (QCoreApplication::postEvent) 的开发者而言&#xff0c;理解事件投递机制尤为重要。这篇博客将带你从基本概…

QDialog中,reject()和close()区别

1. reject()函数 reject()是QDialog类中的一个槽函数&#xff0c;用于以“拒绝”的方式关闭对话框。它通常与对话框的“取消”操作相关联。当调用reject()时&#xff0c;会发出rejected()信号。 行为细节&#xff1a; 从模态对话框的角度来看&#xff0c;当模态对话框调用reje…

【036】基于51单片机五子棋游戏机【Proteus仿真+Keil程序+报告+原理图】

☆、设计硬件组成&#xff1a;51单片机最小系统LCD12864液晶显示按键控制。 1、设计采用STC89C51/52、AT89C51/52、AT89S51/52作为主控芯片&#xff0c;采用LCD12864液晶作为显示&#xff1b; 2、游戏有 人机对战 和 玩家对战 两种模式&#xff0c;玩家白子先下&#xff1b; …

HTML通过JavaScript获取访问连接,IP和端口

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>Get IP Address</title> <script> function displayURL() { var url window.location.href; // 获取当…

VMWARE虚拟交换机的负载平衡算法

一、基于源虚拟端口的路由 虚拟交换机可根据 vSphere 标准交换机或 vSphere Distributed Switch 上的虚拟机端口 ID 选择上行链路。 基于源虚拟端口的路由是 vSphere 标准交换机和 vSphere Distributed Switch 上的默认负载平衡方法。 ESXi主机上运行的每个虚拟机在虚拟交换…

slam里的体素滤波

SLAM系统通常需要处理大量的传感器数据&#xff0c;如激光雷达&#xff08;LiDAR&#xff09;、相机等获取的数据&#xff0c;这些数据往往包含了大量的冗余信息和噪声。为了提高SLAM系统的效率和准确性&#xff0c;数据预处理是非常重要的一步&#xff0c;体素滤波就是一种常用…

web——sqliabs靶场——第十二关——(基于错误的双引号 POST 型字符型变形的注入)

判断注入类型 a OR 1 1# 发现没有报错 &#xff0c;说明单引号不是闭合类型 测试别的注入条件 a) OR 1 1# a)) OR 1 1# a" OR 11 发现可以用双引号闭合 发现是")闭合 之后的流程还是与11关一样 爆破显示位 先抓包 是post传参&#xff0c;用hackbar来传参 unam…

AI时代,百度的三大主义

现实主义、长期主义、理想主义。 定焦One&#xff08;dingjiaoone&#xff09;原创 作者 | 苏琦 郑浩钧 编辑 | 魏佳 “人工智能很像是一次新的工业革命&#xff0c;这意味着它不会三五年就结束&#xff0c;也不会一两年就出现‘超级应用’&#xff0c;它更像是三五十年对于整…

C++基础入门篇

C入门 第一个C程序 首先C兼容c语言&#xff0c;所以由c语言实现的内容仍然可以在C中实现&#xff0c;但是c语言的文件后缀是.c但是C的后缀是.cpp。vs对于cpp文件使用C编译器编译&#xff0c;linux需要用g编译而不是gcc #include<stdio> int main() {printf("hello…

基于YOLOv11的火焰实时检测系统(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

100多种【基于YOLOv8/v10/v11的目标检测系统】目录&#xff08;pythonpyside6界面系统源码可训练的数据集也完成的训练模型 摘要&#xff1a; 本文提出了一种基于YOLOv11算法的火灾检测系统&#xff0c;利用1852张图片&#xff08;1647张训练集&#xff0c;205张验证集&#…

Python入门(10)--面向对象进阶

Python面向对象进阶 &#x1f680; 1. 继承与多态 &#x1f504; 1.1 继承基础 class Animal:def __init__(self, name, age):self.name nameself.age agedef speak(self):passdef describe(self):return f"{self.name} is {self.age} years old"class Dog(Anim…