UE4委託

Forest_1010發表於2020-12-21

01 委託(代理)

委託,又稱代理,本質是一個特殊類的物件,它內部可以儲存(一個或多個)函式指標、呼叫引數和返回值。

委託的作用如同函式指標,但它更安全(支援編譯期型別檢查),而且更易於使用。

使用委託,通過對委託的一個執行就可以呼叫到物件的函式。

02 概念

代理:在你不知道物件是什麼的時候,也可以執行物件中的函式,delegate代理為兩個物件之間建立起了通訊,當我需要呼叫物件中的成員時,可我們不知道物件是誰,這時只需要打電話給這個中介delegate即可。委託的功能類似與藍圖中的發報機。

代理主要有三個特性:繫結、呼叫、解除繫結。

03 UE4支援代理型別

  1. 單播代理:支援繫結單個函式
  2. 多播代理:支援繫結多個函式
  3. 動態代理:可序列化的Uobject

04 單播代理的使用

主要的代理型別有四種:
  • 不帶形參,不帶返回值
  • 帶形參,不帶返回值
  • 帶返回值,不帶形參
  • 帶返回值,帶形參的
代理建立方式:

虛幻4有著自己定義的一套delegate,需要通過delegate巨集建立。

//宣告委託 不帶形參,不帶返回值(它可以繫結的這個函式必須是沒有引數也沒有返回值的) 
DECLARE_DELEGATE(FDelegateTestA);
//宣告委託 帶形參,不帶返回值,類似的一共有9個巨集,最大帶9個形參 如:DECLARE_DELEGATE_NineParams
DECLARE_DELEGATE_OneParam(FDelegateTestB,bool);
//宣告委託帶 帶返回值,不帶形參
DECLARE_DELEGATE_RetVal(bool,FDelegateTestC);
//宣告委託 帶返回值,帶形參的,類似的一共有9個巨集,最大帶9個形參 如:DECLARE_DELEGATE_NineParams
DECLARE_DELEGATE_RetVal_OneParam(int32,FDelegateTestD,FString&);

目前虛幻4巨集最多可以帶9個形參,如:DECLARE_DELEGATE_OneParam一直到DECLARE_DELEGATE_NineParams

單播代理案列:不帶引數的代理,繫結C++原生類

繫結UE4物件,後面是繫結的函式

先宣告兩個類並繫結代理

#include "CoreMinimal.h"
//宣告委託
DECLARE_DELEGATE(FDelegateTestA);

//宣告ClassA類
class ClassA 
{
public:
//宣告代理
	FDelegateTestA DelegateTestA;
  
//呼叫代理
	void Eexcute()
	{
		//呼叫代理,先判斷是否繫結了,繫結上了再執行代理。
		DelegateTestA.ExecuteIfBound();
	}
};

//宣告ClassB類
class ClassB 
{
public:
	//建構函式,繫結代理
	ClassB(ClassA* NewClass_a)
	if (NewClass_a)
	{
		m_classA = NewClass_a;
		m_classA->DelegateTestA.BindRaw(this, &ClassB::ExecuteA);//繫結事件ExecuteA
        }
	void ExecuteA()
	{
		Print_F(TEXT("Hello world"));
	}
	//解構函式,解除繫結
	~ClassB()
	{
		if (m_classA)
		{
			m_classA->DelegateTestA.Unbind();
			m_classA->Execute();
			delete m_classA;
			m_classA = nullptr;
                 }
private:
	ClassA* m_classA;
};

呼叫代理

//假設為程式入口
void BeginPlay()
{
	//建立ClassA指標
	ClassA* NewClassA = new ClassA();
	//建立ClassB指標,構建函式
	ClassB* NewClassB = new ClassB(NewClassA);
	//呼叫代理Execute(),Execute會呼叫ClassB中的Execute()A函式
        //NewClassA不知道有物件NewClassB的,存在卻可以呼叫NewClassB的成員
        //代理為ClassA類和ClassB之間建立通訊
	NewClassA->Execute();
	//釋放指
	delete NewClassB;
	NewClassA = nullptr;
	NewClassB = nullptr;
}

結果

//螢幕會列印“Hello world”,ClassA在不知道物件ClassB情況下呼叫了ClassB的成員

05 動態代理的使用

動態委託可以序列化,其函式可按命名查詢,但其執行速度比常規委託慢。

宣告
DECLARE_DYNAMIC_DELEGATE[
繫結
輔助巨集說明
BindDynamic( UserObject, FuncName )用於在動態委託上呼叫BindDynamic()的輔助巨集。自動生成函式命名字串。
執行
執行函式描述
Execute不檢查其繫結情況即執行一個委託
ExecuteIfBound檢查一個委託是否已繫結,如是,則呼叫Execute
IsBound檢查一個委託是否已繫結,經常出現在包含 Execute 呼叫的程式碼前

06 多播代理的使用

多播委託擁有大部分與單播委託相同的功能。它們只擁有對物件的弱引用,可以與結構體一起使用,可以四處輕鬆複製等等。
就像常規委託一樣,多播委託可以遠端載入/儲存和觸發;但多播委託函式不能使用返回值。它們最適合用來 四處輕鬆傳遞一組委託。

事件是一種特殊型別的多播委託,它在訪問"Broadcast()"、"IsBound()"和"Clear()"函式時會受到限制。

宣告
宣告巨集說明
DECLARE_MULTICAST_DELEGATE[_RetVal, ...]( DelegateName )建立一個多播委託。
DECLARE_DYNAMIC_MULTICAST_DELEGATE[_RetVal, ...]( DelegateName )建立一個動態多播委託。
繫結

多播委託可以繫結多個函式,當委託觸發時,將呼叫所有這些函式。因此,繫結函式在語義上與陣列更加類似。

函式說明
“Add()”將函式委託新增到該多播委託的呼叫列表中。
“AddStatic()”新增原始C++指標全域性函式委託。
“AddRaw()”新增原始C++指標委託。原始指標不使用任何型別的引用,因此如果從委託下面刪除了物件,則呼叫此函式可能不安全。呼叫Execute()時請小心!
“AddSP()”新增基於共享指標的(快速、非執行緒安全)成員函式委託。共享指標委託保留對物件的弱引用。
“AddUObject()”新增基於UObject的成員函式委託。UObject委託保留對物件的弱引用。
“Remove()”從該多播委託的呼叫列表中刪除函式(效能為O(N))。請注意,委託的順序可能不會被保留!
“RemoveAll()”從該多播委託的呼叫列表中刪除繫結到指定UserObject的所有函式。請注意,委託的順序可能不會被保留!

"RemoveAll()"將刪除繫結到所提供指標的所有已註冊委託。切記,未繫結到物件指標的原始委託不會被該函式所刪除!

執行

多播委託允許您附加多個函式委託,然後通過呼叫多播委託的"Broadcast()"函式一次性同時執行它們。多播委託簽名不得使用返回值。

在多播委託上呼叫"Broadcast()"總是安全的,即使是在沒有任何繫結時也是如此。唯一需要注意的是,如果您使用委託來初始化輸出變數,通常會帶來非常不利的後果。

呼叫"Broadcast()"時繫結函式的執行順序尚未定義。執行順序可能與函式的新增順序不相同。

函式說明
“Broadcast()”將該委託廣播給所有繫結的物件,但可能已過期的物件除外。

相關文章