栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

UE4委托

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

UE4委托

UE4 委托

​ 委托是一种可在C++对象上调用成员函数,并可以动态绑定到任意对象的成员函数,之后在该对象上调用函数。可以降低类之间的耦合度,在UE4中共支持三种类型的委托。

  • 单播委托
  • 多播委托
  • 动态委托
1. 声明委托
  • 单播
声明方式描述
DECLARE_DELEGATE(DelegateName)绑定void Function() 类型的函数
DECLARE_DELEGATE_oneParam(DelegateName,Param1Type)绑定void Function(Param1)类型的函数
DECLARE_DELEGATE_TowParams(DelegateName,Param1Type,Param2Type)绑定void Function(Param1,Param2)类型的函数
DECLARE_DELEGATE_RetVal_TowParams(RetValType,DelegateName,Param1Type,Param2Type)绑定RetType Function(Param1,Param2)类型的函数
//实例代码
DECLARE_DELEGATE(FDelegateName1NoParam);
DECLARE_DELEGATE_TwoParams(FDelegateName2,float,const FString&);
DECLARE_DELEGATE_RetVal_TwoParams(int32,FDelegateName3,int,const FString&);
  • 多播

    多播相较于单播,宏的变化为:DECLARE_MULTICAST_DELEGATE....同时需要注意多播是没有返回值的。

声明方式描述
DECLARE_MULTICAST_DELEGATE(DelegateName)绑定void Function() 类型的函数
DECLARE_MULTICAST_DELEGATE_TwoParams绑定void Function(Param1,Param2)类型的函数
// 实例代码
// 多播代理
// 多播代理上绑定的函数的执行顺序是不固定的
// 多播代理无返回值
DECLARE_MULTICAST_DELEGATE(FMultiDelegateNoParam);
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiDelegate2,int32,const FString&)
  • 动态单/多播

​ 动态单/多播委托是一个可以进行序列化利用反射暴露给蓝图的代理,需要注意的是,如果需要传入参数,在代理声明的时候,类型后面需要定义变量名(因为需要暴露给蓝图,变量是需要显示调用的)。

声明方式描述
DECLARE_DYNAMIC_DELEGATE(DelegateName)绑定void Function() 类型的函数
DECLARE_DYNAMIC_DELEGATE_RetVal_oneParam(RetVal,DelegateName,ParamType1,Param1Name)绑定RetValFunction(Param1)类型的函数
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(DelegateName,ParamType1,Param1Name,ParamType2,Param2Name)绑定void Function(Param1,Param2)类型的函数
// 动态代理 可以暴露给blueprint使用
// 动态单播
DECLARE_DYNAMIC_DELEGATE(FDynamicDelegate1);
// 如果有参数 类型后需要定义变量名 因为可以暴露在BluePrints中 所以需要名字
DECLARE_DYNAMIC_DELEGATE_RetVal_TwoParams(int32,FDynamicDelegate2,int32,intVal,const FString&,str);
// 动态多播 注意同样没有返回值
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDynamicDelegate3,int32,val,const FString&,str);
2. 绑定委托
  • 单播
API描述
BindLambda(FunctorType&& Intype)绑定一个Lambda表达式
BindRaw(UserClass* user,MembFunctor* Infunctor)绑定一个原生C++成员方法
BindSp(TSharedPtr&UserPtrRef,MembFunctor* Infunctor)绑定一个共享指针
BindSatic(StaticFunctionPtr* Infunctor)绑定一个静态函数
BindSp(TSharedPtr&UserPtrRef,MembFunctor* Infunctor)绑定一个线程安全的共享指针
BindUFunction(UserClass*user,const FName& InFunctionName)绑定一个被UFUNCTION()宏修饰的函数
BindUObject(UserClass*user,MembFunctor* Infunctor)绑定一个继承自UObejct类的成员方法

示例代码:

void ADelegateActor::SingleDelegateTest()
{
	DelegateInstance1.BindUObject(this,&ADelegateActor::DelegateFunction);

	DelegateInstance1.BindLambda([this](int32 val,const FString& str)->int32
	{
		return 0;
	});

	// 绑定原生C++类
	FTestObject objectInstance;
	DelegateInstance1.BindRaw(&objectInstance,&FTestObject::delegateFunc);

	// 绑定共享指针,一般创建纯C++ 用TSharedPtr用于管理线程
	TSharedPtr sharedPtr1 = MakeShareable(new FTestObject);
	DelegateInstance1.BindSP(sharedPtr1.ToSharedRef(),&FTestObject::delegateFunc);

	// 绑定静态函数
	DelegateInstance1.BindStatic(&FTestObject::delegateFunc2);

	// 绑定一个安全线程的共享指针
	TSharedPtr sharedPtr2 = MakeShareable(new FTestObject);
	DelegateInstance1.BindThreadSafeSP(sharedPtr2.ToSharedRef(),&FTestObject::delegateFunc);

	// 绑定一个方式,通过Name查找,用到了反射。同时这个函数需要加上UFUNCTION()宏
	//	UFUNCTION()
	//  int32 delegateFunc3(int32 val,const FString& str){return 0;}
	DelegateInstance1.BindUFunction(this,FName("delegateFunc3"));
}
  • 多播

​ 多播绑定函数和单播不同的地方为,它可以绑定多个函数对象,用的函数是Add+BindTargetName,需要注意的是多播没有返回值。

示例代码:

MultiDelegateInstance1.AddUObject(this,&ADelegateActor::MultiDelegateFunc);
MultiDelegateInstance1.AddLambda([](int val,const FString& str){});
.........
  • 动态单播/多播

示例代码:

UFUNCTION()
void MultiDelegateFunc(int32 val,const FString& str){}

UFUNCTION()
int32 delegateFunc3(int32 val,const FString& str){return 0;}

// 动态单播
DynamicSigledelegateRef.BindDynamic(this,&ADelegateActor::delegateFunc3);
// 动态多播
// 注意动态多播绑定的方法一定要有UFUNCTION宏,因为需要用到反射的功能
dynamultiDelegateRef.AddDynamic(this,&ADelegateActor::MultiDelegateFunc);
3. 调用委托
  • 单播

​ 通过Execute和ExecuteIfBound进行调用,区别是ExecuteIfBound调用时会判断有没有进行了绑定再进行调用,但是返回值是bool。所以用ExecuteIfBound调用绑定的函数对象必须没有返回值。

示例代码:

if(DelegateInstance1.IsBound())
{
    DelegateInstance1.Execute(20,TEXT("Unreal"));
}
//DelegateInstance1.ExecuteIfBound(); 返回值为bool

//解绑
DelegateInstance1.Unbind();
  • 多播

    多播通过BoardCast()可以通知调用所有绑定的函数对象。

示例代码:

MultiDelegateInstance1.Broadcast(10,"Unreal");
  • 动态单播/多播

    • 在C++中进行调用
    // 动态单播
    
    DynamicSigledelegateRef.BindDynamic(this,&ADelegateActor::delegateFunc3);
    DynamicSigledelegateRef.Execute(10,"Unreal");
    // 动态多播
    // 注意动态多播绑定的方法一定要有UFUNCTION宏,因为需要用到反射的功能
    
    dynamultiDelegateRef.AddDynamic(this,&ADelegateActor::MultiDelegateFunc);
    dynamultiDelegateRef.Broadcast(10,"Unreal");
    
    • 在蓝图中进行调用

      单播在蓝图中调用需要利用UFUNCTION()宏进行修饰,并将自己作为形参传入函数。

    UFUNCTION(BlueprintCallable)
    void DynamicSingleDelegateTest(FDynamicDelegate2 delegateRef);
    

    在蓝图中调用:

​ 多播在蓝图中调用可以直接使用UPROPERTY()宏中的BlueprintAssignable的属性修饰符修饰,注意:该修饰符只能用于动态多播委托

UPROPERTY(BlueprintAssignable)
FDynamicDelegate3 dynamicMultiDelegate;

在蓝图中调用:

4. C++实现UE4委托

​ 借用侯捷老先生的话,知道一个东西,却不明白它的原理,不高明!,所以为了能更好的理解UE4委托,于是模仿UE4创建代理绑定以及调用的方式,自己用C++写了一套很简单的委托。

  • 实现单播无返回值无参数委托
class FDelegateDefault{
public:
	FDelegateDefault():functor(nullptr){};

	template
	void BindRaw(ObjectType* InObejct,void(ObjectType::*InFunc)(void)){
		functor = std::bind(InFunc,InObejct);
	}

	void BindLambda(function Infunctor){
		functor = std::move(Infunctor);
	}

	void Execute(){
		functor();
	}
	bool ExecuteIfBound(){
		if(IsBound()){
			Execute();
			return true;
		}
		return false;
	}
	bool IsBound(){
		return functor?true:false;
	}

private:
	functionfunctor;
};


class testObject{
public:
	void testFunc(){
		cout<<"test default delegate"< 
  • 实现单播多参有返回值的委托
template
class FDelegatebase{
public:
	virtual retType Execute(paramTypes...params)=0;
};


template
class FDelegateObject:public FDelegatebase{
public:
	FDelegateObject():Functor(nullptr),Object(nullptr){};
	FDelegateObject(objectType* InObejct,retType(objectType::*InFunctor)(paramTypes...)):Object(InObejct),Functor(InFunctor){};

	virtual retType Execute(paramTypes...params)override{
		if(Functor&&Object){
			return (Object->*Functor)(params...);
		}
	}
private:
	objectType* Object;
	retType(objectType::*Functor)(paramTypes...);
};


template
class FDelegateLambda:public FDelegatebase{
public:
	FDelegateLambda():functor(nullptr){};
	FDelegateLambda(function InFunctor){
		functor = std::move(InFunctor);
	}
	virtual retType Execute(paramTypes...params)override{
		if(functor){
			return functor(params...);
		}
	}
private:
	functionfunctor;
};



template
class FDelegateParams{
public:
	FDelegateParams():delegatePtr(nullptr){}

	~FDelegateParams(){
		if(delegatePtr){
			delete delegatePtr;
			delegatePtr = nullptr;
		}
	}


	template
	void BindRaw(objectType* InObejct,retType(objectType::*InFunc)(paramTypes...)){
		prepareforBind();
		delegatePtr = new FDelegateObject(InObejct,InFunc);
	}


	void BindLambda(function InFunc){
		prepareforBind();
		delegatePtr = new FDelegateLambda(InFunc);
	}

	retType Execute(paramTypes...params){
		if(delegatePtr){
			return delegatePtr->Execute(params...);
		}
	}

	bool ExecuteIfBound(paramTypes...params){
		if(delegatePtr){
			Execute(params...);
		}
	}

	bool IsBound(){
		return delegatePtr?true:false;
	}

protected:
	void prepareforBind(){
		if(delegatePtr){
			delete delegatePtr;
			delegatePtr = nullptr;
		}
	}

private:
	FDelegatebase* delegatePtr;
};

class testObject{
public:
	const char* testFunc2(int val,string str){
		cout<<"val:"<FDelegateName;

int main(){
	testObject obj;
	DECLARE_DELEGATE_RetVal_Params(Delegate,const char*,int,string);
	Delegate.BindRaw(&obj,&testObject::testFunc2);
	Delegate.Execute(10,"Unreal");

	Delegate.BindLambda([](int val,string str)->const char*{
		cout<<"Bind Lambda"< 

多播的实现,大同小异。有兴趣的可以看我之前C++委托中实现多播委托的方式。这里不予讨论。C++委托_WLSTLA-CSDN博客

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/443724.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号