UE4 _C++_代理(委托)—— 使用层

我们经常会在UE4中使用到代理委托,用于降低模块之间的耦合度

即模块之间的调用,不需要知道被调用模块的实现细节,仅通过将函数指针绑定到委托即可实现调用。

本文将讲解如何在UE4中创建C++代理委托

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

=============================================

创建(静态)单播代理(Standard delegate)

绑定单个响应函数声明代理(签名)DECLARE_DELEGATE(DelegateName) // 无函数参数,无函数返回值 // DelegateName 这是我们自定义的代理类型,即委托签名 DECLARE_DELEGATE_OneParam(DelegateName, Param1Type) // 有一个函数参数,无函数返回值 // Param1Type 这是参数类型 DECLARE_DELEGATE_<Num>Params(DelegateName, Param1Type, Param2Type, ...) // 有多个函数参数,无函数返回值 // 支持最多8个函数参数 DECLARE_DELEGATE_RetVal(RetValType, DelegateName) // 无函数参数,有函数返回值 // RetValType 这是函数返回值类型,最多支持一个函数返回值 DECLARE_DELEGATE_RetVal_<Num>Params(RetValType, DelegateName, Param1Type, Param2Type, ...) // 有多个函数参数,有函数返回值

2. 定义代理

DelegateName MyStandardDelegate; // MyStandardDelegate 这是我们自定义的单播代理

3. 绑定委托

这里的安全是指在执行代理时,是否可以进行安全的判断,然后再执行。绑定UObject函数BindUObject是通过“函数指针”绑定MyStandardDelegate.BindUObject(this, &AMyTPCharacter::FuncNoParam); //this只能是继承自UObject的类,绑定继承UObject类的对象函数绑定原始C++函数MyStandardDelegate.BindRaw(&MyT, &MyTest::TestFunc); //MyT是声明的MyTest对象 //绑定到一个原始的C++类函数绑定到一个原始的C++指针全局函数代理上。原始指针不使用任何引用,所以如果从代理的底层删除了该对象,那么调用它可能是不安全的。因此,当调用Execute()时一定要小心!绑定UFUNCTION函数BindUFunction是通过“函数名字”动态绑定UFUNCTION()//可以声明BlueprintCallable等其他标记 void TestUFunc(FString str); MyStandardDelegate.BindUFunction(this,"TestUFunc"); //绑定this指向对象类蓝图函数绑定智能指针////绑定指针方式1 struct FTestSharedPtr :public TSharedFromThis<FTestSharedPtr> { void test() { } void bind(FTestDel& del) { del.BindSP(this, &FTestSharedPtr::test); }; }; 绑定指针方式2 void MyTest::TestFunc(FString Str) { if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 30, FColor::Blue, Str); } } TSharedPtr<MyTest> MyT_SPtr; MyStandardDelegate.BindSP(MyT_SPtr.ToSharedRef(), &MyTest::TestFunc); //绑定一个基于共享指针的成员函数代理。共享指针代理保持到您的对象的弱引用。您可以使用 ExecuteIfBound() 来调用它们。绑定静态函数static void Static_Func(FString Str) { // ...... } MyStandardDelegate.BindStatic(Static_Func); // 绑定全局静态函数 // MyStandardDelegate是自定义委托绑定Lambdaauto LambdaFunc = [&](FString str) { // ...... }; MyStandardDelegate.BindLambda(LambdaFunc); // 绑定lambda表达式 // DelegateLambda是自定义委托Lambda表达式:C++之Lambda表达式 - 季末的天堂 - 博客园​www.cnblogs.com/jimodetiantang/p/.html

4. 代理执行

执行方式1// MyStandardDelegate 这是我们自定义的单播代理 if(MyStandardDelegate.IsBound()) { MyStandardDelegate.Execute(); }执行方式2// MyStandardDelegate 这是我们自定义的单播代理 MyStandardDelegate.ExecuteIfBound(); // 如果代理的函数签名是没有返回值的,如 void(arg),那么使用这个ExecuteIfBound()

5. 代理解绑

MyStandardDelegate.UnBind();

创建(静态)多播代理(MultiCast delegate)

绑定多个响应函数与单播代理的区别在于它们对目标为弱引用,可以和结构体一起使用,可以很方便地进行拷贝,等等。和普通代理一样,多播代理可被载入/保存,并远程触发;但是,多播代理的函数无法使用返回值。最好将它们用于方便地传递代理集合。事件 是特定类型的多播代理,同时具有对Broadcast(), IsBound(), 和 Clear()函数的受限访问。多播代理在代理触发时可能会调用多个函数绑定。因此,绑定函数在语句中看起来更为像是数组。多播代理允许您附加多个函数代理,然后通过调用多播代理的 Broadcast() 函数一次性执行所有函数代理。多播代理的签名不能使用返回值。绑定函数的执行顺序是不确定的。可能并不按照函数的添加顺序执行。任何时候在多播代理上调用 Broadcast() 函数都是安全的,即时它没有绑定任何函数也可以。唯一需要注意的时候是您使用代理初始化输出变量时,这样做一般是非常不好的。声明代理//声明多播委托,与单播委托一样支持多参数传入,动态多播代理的名称开头须为F,否则会编译报错 DECLARE_MULTICAST_DELEGATE(FMulticastD_NoParam);//声明无参数多播 DECLARE_MULTICAST_DELEGATE_OneParam(FMulticastD_1Param, FString);//声明一个参数多播

2. 定义代理

//多播 FMulticastD_NoParam DelegateMulticastD_NoParam; FMulticastD_1ParamDelegateMulticastD_1Param;

3. 绑定代理

FDelegateHandle MyDelegateHandle; MyDelegateHandle = DelegateMulticastD_NoParam.AddUObject(this,&AMulticastDelegateListener::ToggleLight);

4. 代理执行

//执行多播 DelegateMulticastD_NoParam.Broadcast(); DelegateMulticastD_1Param.Broadcast(FString("@1Param!!!"));

5. 代理解绑

将函数从这个多播代理的调用列表中移除(性能为O(N))。请注意代理的顺序可能不会被保留!DelegateMulticastD_NoParam.Remove(MyDelegateHandle);将所有函数从与特定UserObject绑定的多播代理的调用列表中移除。请注意代理的顺序可能不会被保留!RemoveAll()将会移除所有与提供的指针绑定的注册代理! 不与对象指针绑定的原始代理将不会被此函数移除!DelegateMulticastD_NoParam.RemoveAll();

创建动态单播代理(Dynamic standard delegate)

支持序列化,可以作为函数参数,在蓝图中作为函数参数使用声明动态单播代理// Declare dynamic standard delegate class DECLARE_DYNAMIC_DELEGATE(FDyStandardDelegate); // TestFunction for dynamic standard delegate UFUNCTION(BlueprintCallable) void TestFunc_DynamicStandardDelegate(const FDyStandardDelegate& MyDyStandardDelegate) { UE_LOG(LogTemp, Error, TEXT("Dynamic standard delegate!")); }

2. 动态单播代理绑定代理

蓝图绑定动态单播代理-蓝图表现C++绑定只能绑定UFUNCTION标记的函数// TestFunction for dynamic standard delegate bind ufunction UFUNCTION() void TestFunc_DynamicStandardDelegate_BindUFunction() { UE_LOG(LogTemp, Error, TEXT("Dynamic standard delegate bind ufuntion!")); } const FDyStandardDelegate& MyDyStandardDelegateBindUFuntion MyDyStandardDelegateBindUFuntion.BindUFunction(this, "TestFunc_DynamicStandardDelegate_BindUFunction");

3. 动态单播代理执行

if (MyDyStandardDelegateBindUFuntion.IsBound()) { MyDyStandardDelegateBindUFuntion.Execute(); }

4. 动态单播代理解绑

MyDyStandardDelegateBindUFuntion.Unbind();

创建动态多播代理(Dynamic multicast delegate)

支持序列化,可以作为类变量(但需要加上 BlueprintAssignable 关键字),因此可以在蓝图中使用声明多播代理(类内或全局均可)// 声明一个无参数、无返回值的代理 DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnTestOneDelegate); // 声明一个有一个参数、无返回值的代理 DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTestTwoDelegate, bool, bTest); // UE4提供了已经提供了很多代理声明类型 // 包括多参数、多返回值的,可自己选择需要的,这里就不一一列举提供了注:声明代理参数格式(如下):一个参数(代理名, 参数类型, 参数名)二个参数(代理名, 参数类型, 参数名, 参数类型, 参数名)多个参数格式以此类推...

2. 根据声明的代理,声明对应代理类型的成员变量(头文件,类内),在蓝图上绑定分配

// Declare dynamic multicast delegate class DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDyMulticastDelegate); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDyMulticastDelegateOneParam, FString, Str); // Declare dynamic standard delegate object UPROPERTY(BlueprintAssignable) FDyMulticastDelegate MyDyMulticastDelegate; UPROPERTY(BlueprintAssignable) FDyMulticastDelegateOneParam MyDyMulticastDelegateOneParam;

3. 绑定动态多播代理

绑定到动态多播代理上的代理,只能是“动态单播代理”蓝图绑定(BindEvent节点,从声明代理的类中找到)C++绑定// TestFunction for dynamic multicast delegate UFUNCTION(BlueprintCallable) void TestFunc_DynamicMulticastDelegate(const FDyStandardDelegate& MyDyStandardDelegate1, const FDyStandardDelegate& MyDyStandardDelegate2) { UE_LOG(LogTemp, Error, TEXT("Dynamic multicast delegate!")); MyDyMulticastDelegate.Add(MyDyStandardDelegate1); MyDyMulticastDelegate.Add(MyDyStandardDelegate2); }

4. 动态多播代理执行

MyDyMulticastDelegate.Broadcast();

5. 动态多播代理解绑

移除单个代理通过代理签名移除代理MyDyMulticastDelegate.Remove(MyDyStandardDelegate1);移除UObject的全部代理通过UObject对象移除全部代理MyDyMulticastDelegate.RemoveAll(this); // this 一般就是传入UObject本身

======================================================

以上就是个人对UE4代理的全部总结啦!!!

如果有不正确的地方,还请大佬指点!!!

=====================================================

TamronCoder/UE_Delegate​github.com/TamronCoder/UE_Delegate

看在添上源码(UE4.25)的份上,如果对你有帮助,记得给我点个赞哈!