为什么使用委托


  UE4中的委托使得在UE4中不同类之间相互调用其方法变得更加方便和通用,而在UE4中,已经为我们声明好了许多的宏定义来让我们来声明这些委托。而声明的委托方法有以下两种情况。



绑定的函数没有返回值:

  若函数不需要传入参数,则使用:DECLARE_DELEGATE(DelegateName),其中,DelegateName为委托的名字。

  若函数需要传入一个参数,则使用:DECLARE_DELEGATE_OneParam(DelegateName, Param1Type),其中,DelegateName为委托的名字,Param1Type为传入的参数。

  若函数需要传入两个参数,则使用:DECLARE_DELEGATE_TwoParams(DelegateName, Param1Type, Param2Type),其中,DelegateName为委托的名字,Param1Type,Param2Type为传入的参数。

  若函数需要传入多个参数,则使用:DECLARE_DELEGATE_Params(DelegateName, Param1Type, Param2Type, ... ),其中,DelegateName为委托的名字,Param1Type,Param2Type,... 为传入的参数。


绑定的函数有返回值:

  若函数不需要传入参数,则使用:DECLARE_DELEGATE_RetVal(RetValType, DelegateName),其中,RetValType为绑定的函数返回值的类型,DelegateName为委托的名字。

  若函数需要传入一个参数,则使用:DECLARE_DELEGATE_RetVal_OneParam(RetValType, DelegateName, Param1Type),其中,RetValType为绑定的函数返回值的类型,DelegateName为委托的名字,Param1Type为传入的参数。

  若函数需要传入两个参数,则使用:DECLARE_DELEGATE_RetVal_TwoParams(RetValType, DelegateName, Param1Type, Param2Type),其中,RetValType为绑定的函数返回值的类型,DelegateName为委托的名字,Param1Type,Param2Type为传入的参数。

  若函数需要传入多个参数,则使用:DECLARE_DELEGATE_RetVal_Params(RetValType, DelegateName, Param1Type, Param2Type, ... ),其中,RetValType为绑定的函数返回值的类型,DelegateName为委托的名字,Param1Type,Param2Type,... 为传入的参数。



委托的绑定方法如下:

  BindRaw():绑定原始的C++指针,需要传入绑定的类的指针和这个类下要绑定的方法的引用。

  BindUObject():绑定UObject对象指针,即任何一个UE4类的指针,需要传入绑定的类的指针和这个类下要绑定的方法的引用。

  BindUFunction():当绑定的方法是由UFUNCTION()声明的时候,我们可以使用UE4的反射机制来绑定这个委托,这个时候需要传入任何一个UE4类的指针和方法的名称(FName)进行反射机制的调用。

  BindSP():绑定一个UE4封装好的智能指针,如TSharedRef。



如何去调用一个委托:

  Execute():不进行检测是否绑定,直接调用,括号内传入的参数要与委托绑定的参数类型和数量一致。

  ExecuteIfBound():进行检测是否绑定,绑定后才调用,括号内传入的参数要与委托绑定的参数类型和数量一致。



如何去检测一个委托是否绑定:

  直接调用IsBound()即可




使用案例:

  我们在MyClassB类中有一个函数BFunction(int i);但是我们想让这个BFunction让MyClassA调用,于是我们需要在MyClassA类的头文件中声明和定义这个委托:


  // 声明这个委托					
  DECLARE_DELEGATE_OneParam(FMyClassADelegate, int)
  
  UCLASS()
  class COURSE_API AMyClassA : public AActor {
      pubilc:
          // 委托的定义
          FMyClassADelegate MyClassADeleate;
  }
					

  于是我们可以在项目的任意位置在调用这个委托之前的位置绑定这个委托对应的函数


  // 绑定这个委托			
  AMyClassA* ClassA;
  ClassA->MyClassADeleate.BindUObject(ClassA, &MyClassB::BFunction);
					

  这个时候我们在MyClassA.cpp中的任意位置就可以调用这个委托,并且可以不用了解MyClassB类中的任何信息。


  // 调用这个委托,只需传入的参数一致即可
  int i = 0;
  MyClassADeleate.ExecuteIfBound(i);