这几天研究了一下虚幻4的delegate,但是想要理解这个,还得从仿函数说起。仿函数的定义是:A Functor is a object which acts like a function. Basically, a class which defines operator()
.下面是一段代码例子:
class MyFunctor
{
public:
int operator()(int x) { return x * 2;}
}
MyFunctor doubler;
int x = doubler(5);
The real advantage is that a functor can hold state.(这就是仿函数的最大好处)
class Matcher
{
int target;
public:
Matcher(int m) : target(m) {}
bool operator()(int x) { return x == target;}
}
Matcher Is5(5);
if (Is5(n)) // same as if (n == 5)
{ ....}
不过上面这种玩法是很久以前的了,现在还可以使用std::function(例子二:)-----------------------------------------------
#include
#include
#include
using namespace std;
class MyCharacter
{
public:
void BeHurt01(int hurtvalue)
{
cout << "hurt01" << hurtvalue << endl;
}
void BeHurt02(int hurtvalue)
{
cout << "hurt02" << hurtvalue << endl;
}
};
class OtherCharacter
{
public:
functionThisIsDelegate;
};
int main()
{
MyCharacter mycha;
OtherCharacter othecha;
othecha.ThisIsDelegate = bind(&MyCharacter::BeHurt01, &mycha, placeholders::_1);
othecha.ThisIsDelegate(19);
return 0;
}
这样做的好处就是实现延迟调用,我先把方法绑上去,到我需要的时候再调用。这么说可能有点抽象。既然是做游戏的,可以举个例子来说明。比如我现在有个主角和一个怪物。主角打出去一拳后会对怪物造成伤害,但是这个伤害不是立刻起效的,因为需要完成动画播放,主角的出招的特效播放之后才会执行怪物受伤扣血的逻辑。这时候可以先在主角出招的时候探测周围的怪物然后给他们绑定上伤害函数。等怪物的动画播放完毕之后再判断是否要执行这个伤害操作。这个时候就需要上面那种办法了。
相对于函数指针,std::function能绑定c++里的所有可调用对象,stdfunction相当于帮我们封装了一个模板。
再来说虚幻的delegate。虚幻的delegate其实就是更高级的封装了。
首先声明几个函数和代理,注意代理的格式和函数对应
头文件:
/*Single-cast delegate declaration. No parameters*/
DECLARE_DELEGATE(MyDelegate)
/*Single-cast delegate declaration. One int32 parameter*/
DECLARE_DELEGATE_OneParam(MyIntDelegate,int32)
/*Multi-cast delegate declartion. One int32 parameter*/
DECLARE_MULTICAST_DELEGATE_OneParam(MyIntMulticastDelegate,int32)
/*Function with one int32 parameter*/
UFUNCTION()
void IntFunction(int32 x);
/*Function with one int32 parameter*/
UFUNCTION()
void SecondIntFunction(int32 x);
/*Function with one int32 parameter*/
UFUNCTION()
void ThirdIntFunction(int32 x);
/*Function with no parameters*/
UFUNCTION()
void SomeFunction();
源文件:
void ADelegateActor::IntFunction(int32 x)
{
GLog->Log("Output from IntFunction: " + FString::FromInt(x));
}
void ADelegateActor::SecondIntFunction(int32 x)
{
GLog->Log("Output from SecondIntFunction: " + FString::FromInt(x*2));
}
void ADelegateActor::ThirdIntFunction(int32 x)
{
//x to square
float power = FMath::Pow(x, 2);
GLog->Log("Third Int Function: "+FString::SanitizeFloat(power));
}
void ADelegateActor::SomeFunction()
{
GLog->Log("Some function log");
}
在beginplay函数中做如下绑定:
//Declaring a delegate of MyDelegate type
MyDelegate MyDel;
//Binding a UFUNCTION to MyDel - this will not call the function just yet.
MyDel.BindUFunction(this, FName("SomeFunction"));
//Calling the bound function of the delegate
MyDel.Execute();
//Declaring a delegate of MyIntDelegate type
MyIntDelegate IntDelegate;
//Binding two UFUNCTIONs to IntDelegate - this will not call any function just yet
IntDelegate.BindUFunction(this, FName("IntFunction"));
IntDelegate.BindUFunction(this, FName("SecondIntFunction"));
//Since the IntDelegate is a single-cast delegate it will only contain up to one function
//In this case, the IntDelegate contains the last bound function
IntDelegate.Execute(50);
//Declaring a delegate of MyIntMulticastDelegate type
MyIntMulticastDelegate Del;
//Adding three UFUNCTIONs to the delegate - this will not call any function just yet
Del.AddUFunction(this, FName("IntFunction"));
Del.AddUFunction(this, FName("SecondIntFunction"));
Del.AddUFunction(this, FName("ThirdIntFunction"));
//Calling all the bound functions with a value of 10
Del.Broadcast(10);