C++ Delegate
使用Delegate
(委托)可以起到类之间的解耦操作,具有对象闭包的特性。同时也是UE4C++
中经常用到的特性之一,这里为了自己更好的理解写下该篇博文帮助之后复习。
一.单播代理
template<class retType,class ...paramTypes>
class DelegateBase{
public:
virtual retType Execute(paramTypes ...params)=0;
};
//绑定成员函数
template<class objectType, class retType,class ...paramsType>
class DelegateObject :public DelegateBase<retType, paramsType...>
{
public:
DelegateObject(objectType* Inobj, retType(objectType::*InFunc)(paramsType...)):objPtr(Inobj), bindFunc(InFunc){}
virtual retType Execute(paramsType... params) {
return (objPtr->*bindFunc)(params...);
}
private:
objectType* objPtr;
retType(objectType::* bindFunc)(paramsType...);
};
//绑定普通函数
template<class retType,class ...paramTypes>
class DelegateFunction:public DelegateBase<retType,paramTypes...>
{
public:
DelegateFunction(retType(*InFunc)(paramTypes...)):bindFunc(InFunc){};
virtual retType Execute(paramTypes...params){
return (*bindFunc)(params...);
}
private:
retType(*bindFunc)(paramTypes...);
};
struct testobj{
const char* RunDelegate(int val,string str){
cout<<"str:"<<str<<endl;
cout<<"val:"<<val<<endl;
return str.c_str();
}
};
string testfunction(int val,const char* str){
cout<<"str:"<<str<<endl;
cout<<"val:"<<val<<endl;
string tempstr(str);
return tempstr;
}
//测试代码
int main(){
testobj objRef;
DelegateObject<testobj,const char*,int,string>delegateObj(&objRef,&testobj::RunDelegate);
delegateObj.Execute(10,"Unreal");
DelegateFunction<string,int,const char*>delegateFunctor(&testfunction);
delegateFunctor.Execute(50,"Unity");
return 0;
}
使用函数指针来实现对函数的调用,另一种方式是使用std::function
与std::bind
结合的方式进行使用,该方法会在之后UE4
委托中实现。同时这里的Delegate
类都继承了一个基类DelegateBase
,是为了之后使用"工厂"来进行Delegate
的统一化,即使用一个类就能实现所有运用Delegate
的场景,而不是像现在这样,委托成员函数就需要实例化对应绑定成员函数的代理。
使用工厂生产单播代理
template<class retType,class ...paramTypes>
class Delegate{
public:
Delegate():delegatePtr(nullptr){};
template<class objType>
Bind(objType* InObj,retType(objType::*InFunc)(paramTypes...))
{
checkDelete();
delegatePtr = new DelegateObject<objType,retType,paramTypes...>(InObj,InFunc);
}
Bind(retType(*InFunc)(paramTypes...))
{
checkDelete();
delegatePtr = new DelegateFunction<retType,paramTypes...>(InFunc);
}
void checkDelete(){
if(delegatePtr){
delete delegatePtr;
delegatePtr = nullptr;
}
}
retType Execute(paramTypes... params){
return delegatePtr->Execute(params...);
}
private:
DelegateBase<retType,paramTypes...>*delegatePtr;
};
//测试代码
int main(){
testobj objRef;
Delegate<const char*,int,string>delegate;
delegate.Bind<testobj>(&objRef,&testobj::RunDelegate);
delegate.Execute(20,"Cocos");
Delegate<string,int,const char*>delegate2;
delegate2.Bind(&testfunction);
delegate2.Execute(40,"REEngine");
return 0;
}
也可以模仿UE4
的写法,使用宏定义对Delegate
进行创建:
#define DELEGATE(delegateName,retType,...) Delegate<retType,__VA_ARGS__>delegateName;
//测试代码
DELEGATE(test,string,int,const char*);
test.Bind(&testfunction);
test.Execute(40,"REEngine");
二.多播代理
多播代理可以一次绑定多个函数对象,以广播的形式通知所有代理函数。知道这个特性我们可以写下如下代码(注意:多播代理无法接收返回值):
#include<vector>
template<class retType,class ...paramTypes>
class MultiCastDelegate{
public:
typedef Delegate<retType,paramTypes...> DelegateType;
MultiCastDelegate(){};
template<class objType>
Add(objType* InObj,retType(objType::*InFunc)(paramTypes...)){
delegateContainer.push_back(DelegateType());
DelegateType& InDelegate = delegateContainer.back();
InDelegate.Bind(InObj,InFunc);
}
Add(retType(*InFunc)(paramTypes...)){
delegateContainer.push_back(DelegateType());
DelegateType& InDelegate = delegateContainer.back();
InDelegate.Bind(InFunc);
}
BroadCast(paramTypes... params){
for(auto& elem:delegateContainer){
elem.Execute(params...);
}
}
private:
vector<Delegate<retType,paramTypes...>> delegateContainer;
};
const char* testFunc01(int val,string str){
cout<<"testFunc01"<<endl;
return str.c_str();
}
const char* testFunc02(int val,string str){
cout<<"testFunc01"<<endl;
return str.c_str();
}
struct testobj01{
const char* testobjFunc01(int val,string str){
cout<<"testobjFunc01"<<endl;
return str.c_str();
}
};
struct testobj02{
const char* testobjFunc02(int val,string str){
cout<<"testobjFunc02"<<endl;
return str.c_str();
}
};
//测试代码
int main(){
MultiCastDelegate<const char*,int,string>delegate;
delegate.Add(&testFunc01);
delegate.Add(&testFunc02);
testobj01 obj1;
testobj02 obj2;
delegate.Add<testobj01>(&obj1,&testobj01::testobjFunc01);
delegate.Add<testobj02>(&obj2,&testobj02::testobjFunc02);
delegate.BroadCast(10,"Unreal");
return 0;
}