UE4单播代理

UE4的单播代理

官方文档讲解请点击委托

对于委托,官方解释如下:
委托 在C++对象上引用和执行成员函数的数据类型。

委托 是一种泛型但类型安全的方式,可在C++对象上调用成员函数。可使用委托动态绑定到任意对象的成员函数,之后在该对象上调用函数,即使调用程序不知对象类型也可进行操作。复制委托对象很安全。你也可以利用值传递委托,但这样操作需要在堆上分配内存,因此通常并不推荐。请尽量通过引用传递委托。

理解:
1.委托是一种数据类型,在委托类型的实例化对象上可引用和执行成员函数;

2.定义一种委托类型对象,然后使用将函数绑定到这个代理对象上,之后,便可以通过这个代理对象调用成员函数。

UDELEGATE说明符
委托函数支持与UFunctions相同的说明符,但使用 UDELEGATE 宏而不是 UFUNCTION。例如,以下代码将 BlueprintAuthorityOnly 说明符添加到 FInstigatedAnyDamageSignature 委托中

UDELEGATE(BlueprintAuthorityOnly)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FInstigatedAnyDamageSignature, float, Damage, const UDamageType*, DamageType, AActor*, DamagedActor, AActor*, DamageCauser);

单播代理

单播代理,顾名思义,一次绑定一个函数并执行该函数的委托。

可以根据参数的个数来使用代理。最多可以有9个参数。

代理类型的声明

//单播代理,无参数无返回值,代理名为TestDelegateNoparam
DECLARE_DELEGATE(FTestDelegateNoparam);
//单播代理,两个参数,无返回值,代理名为TestDelegateTwoParams
//这个代理包含两个参数,分别为float和const FStrings&
DECLARE_DELEGATE_TwoParams(FTestDelegateTwoParams, float, const FStrings&);

//单播代理,两个参数,返回值类型为int32, 代理名为TestDelegateTwoParamsRetVal
////这个代理包含两个参数,分别为float和const FStrings&
DECLARE_DELEGATE_RetVal_TwoParams(int32, FTestDelegateTwoParamsRetVal, float, const FStrings&);

代理函数的定义

UCLASS()
class HELLOUE4_API AMyActor : public AActor
{
	GENERATED_BODY()
public:	
	// Sets default values for this actor's properties
	AMyActor();
public:
	void FunNoparam();
	void FunTwoparamNoRetVal(float a, const FString& s);
	int32 FunTwoparamRetVal(float a, const FString& s);
	
	UFUNCTION()
	int32 Fun(float a, const FString& s);
	
protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	//在类中定义两个代理成员对象
	FTestDelegateTwoParamsRetVal DelegateTwoParamsRetVal;
	FTestDelegateNoparam         DelegateNoparam;
public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
};

其cpp文件如下所示

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyActor.h"

// Sets default values
AMyActor::AMyActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

void AMyActor::FunNoparam()
{
}

void AMyActor::FunTwoparamNoRetVal(float a, const FString& s)
{
}

int32 AMyActor::FunTwoparamRetVal(float a, const FString& s)
{
	return int32(1);
}
// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	
	//有参数有返回值的代理的绑定
	DelegateTwoParamsRetVal.BindUObject(this, &AMyActor::FunTwoparamRetVal);
	//绑定后验证并执行
	if(DelegateTwoParamsRetVal.IsBound())
		DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
		
	//无参数无返回值的代理绑定
	DelegateNoparam.ExecuteIfBound();
	
}
// Called every frame
void AMyActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

其使用方法可分为三个步骤
1.声明并定义代理,并定义一个代理对象。
声明并定义代理
在这里,就像定义一种类类型一样,这里是定义了一种代理类型,也就是委托类型。
其代理类型为FTestDelegateTwoParamsRetVal,这种类型的代理反悔值为int32类型的,有两个参数,分别为float和FStrings&类型的

DECLARE_DELEGATE_RetVal_TwoParams(int32, FTestDelegateTwoParamsRetVal, float, const FStrings&);
DECLARE_DELEGATE(FTestDelegateNoparam);

代理对象的定义
实例化一个代理对象。

FTestDelegateTwoParamsRetVal DelegateTwoParamsRetVal;
FTestDelegateNoparam         DelegateNoparam;

2.代理对象的绑定
在这个步骤中,只是完将代理对象绑定到函数上,并未执行函数.

	//绑定继承自UObject类的类里面的成员函数
	//其中两个参数,第一个参数为想要使用代理的类的指针
	//第二个参数为代理的函数名,传入的是函数地址,故须对函数名引用
	DelegateTwoParamsRetVal.BindUObject(this, &AMyActor::FunTwoparamRetVal);

3.执行代理函数

	//防止代理未绑定成功而导致程序崩溃,先进行绑定判断
	if(DelegateTwoParamsRetVal.IsBound())
		//为代理对象传入参数并执行
		DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");

在执行函数部分,若是无参数类型,还可以如下操作

	DelegateNoparam.ExecuteIfBound();

代理与lambda表达式的绑定
在这里,仍然使用前面定义的代理,代理对象的定义,在void AMyActor::BeginPlay()函数中将代理对象绑定至lambda表达式

void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	//绑定lambda表达式
	//this指针为lambda捕捉本类内所有成员连梁
	//由于lambda表达式返回值为int32类型,为了便于说明,return 0;
	DelegateTwoParamsRetVal.BindLambda([this](float a, const FString& s) -> int32{
		return 0;
	});
	
	//代理执行
	if(DelegateTwoParamsRetVal.IsBound())
		DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
}

绑定原生c++类中方法
首先定义一个原生的c++类中的方法。
首先要知道,c++类中方法只存储一处,只有一份。

class FTestA{
punlic:
	int32 Fun(float a, const FString& s){
		return 0;
	}
}

仍然使用前面定义的代理,代理对象的定义。

void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	
	//定义一个类对象
	FTestA A;
	
	//代理对象的绑定
	//第一个参数为指向要绑定类对象的指针
	//第二个参数为要绑定方法的指针
	DelegateTwoParamsRetVal.BindRaw(&A,&FTestA::Fun);
	
	//代理执行
	if(DelegateTwoParamsRetVal.IsBound())
		DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
}

绑定共享指针和线程安全共享指针
在定义原生c++类FTestA中方法的基础上继续绑定共享指针

void AMyActor::BeginPlay()
{
	Super::BeginPlay();

	//绑定TSharedPtr指向对象的函数,即纯c++类的函数,
	TSharedPtr<FTestA> A1 = MakeShareable(new FTestA);
	//绑定代理
	DelegateTwoParamsRetVal.BindSP(A1.ToSharedRef(), &FTestA::Fun);
	
}

线程安全共享指针

void AMyActor::BeginPlay()
{
	Super::BeginPlay();

	//绑定一个线程安全的TSharedPtr包裹着的纯c++类里面的函数,
	TSharedPtr<FTestA, ESPMode::ThreadSafe> A2 = MakeShareable(new FTestA);
	//绑定代理
	DelegateTwoParamsRetVal.BindSP(A2.ToSharedRef(), &FTestA::Fun);
}

绑定静态函数
首先定义静态函数

static int32 Fun1(float a, const FString& s){
		return 0;
	}
	
class FTestB{
punlic:
	static int32 FunStatic(float a, const FString& s){
		return 0;
	}
}

void AMyActor::BeginPlay()函数中将代理对象绑定至静态函数

void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	//绑定代理
	DelegateTwoParamsRetVal.BindStatic(&Fun1);
}

void AMyActor::BeginPlay()函数中将代理对象绑定至类中静态函数

void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	//绑定代理
	DelegateTwoParamsRetVal.BindStatic(&FTestB::FunStatic);
}

绑定至UFUNCTION

void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	//绑定代理至UFUNCTION
	DelegateTwoParamsRetVal.BindUFunction(this, FName("fun"));
}

清除代理
代理绑定并执行完成后,要清除绑定。

void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	
	//有参数有返回值的代理的绑定
	DelegateTwoParamsRetVal.BindUObject(this, &AMyActor::FunTwoparamRetVal);
	//绑定后验证并执行
	if(DelegateTwoParamsRetVal.IsBound())
		DelegateTwoParamsRetVal.Execute(32, "Hello Delegate");
		
	//清除代理
	DelegateTwoParamsRetVal.Unbind();
	
}

posted on   hxh_space  阅读(472)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示