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



