委托

在C++对象上引用和执行成员函数的数据类型。

Windows
MacOS
Linux

利用委托可以泛型但类型安全的方式在C++对象上调用成员函数。可使用委托动态绑定到任意对象的成员函数,然后在该对象上调用函数,即使调用程序不知对象类型也可进行操作。

复制委托对象绝对安全。可利用值传递委托,但其须在堆上分配内存,因此通常并不推荐此操作。应尽量固定利用引用传递委托。

同时支持单投射和多投射委托,及可安全序列化到硬盘的“动态”委托。

声明委托

使用提供的声明宏之一来声明委托。所用宏由要绑定到委托的函数的签名决定。系统预定义各种泛型函数签名组合,可在从中声明委托类型、填充返回值及所需参数类型的类型名。当前支持以下使用任意组合的委托签名:

  • 返回值的函数

  • 最多4个“负载”变量

  • 最多8个函数参数

  • 声明为“const”的函数

使用此表格查找要用于声明委托的生命宏。

函数签名

声明宏

void Function()

DECLARE_DELEGATE( DelegateName )

void Function( <Param1> )

DECLARE_DELEGATE_OneParam( DelegateName, Param1Type )

void Function( <Param1>, <Param2> )

DECLARE_DELEGATE_TwoParams( DelegateName, Param1Type, Param2Type )

void Function( <Param1>, <Param2>, ...)

DECLARE_DELEGATE_<Num>Params( DelegateName, Param1Type, Param2Type, ...)

<RetVal> Function()

DECLARE_DELEGATE_RetVal( RetValType, DelegateName )

<RetVal> Function( <Param1> )

DECLARE_DELEGATE_RetVal_OneParam( RetValType, DelegateName, Param1Type )

<RetVal> Function( <Param1>, <Param2> )

DECLARE_DELEGATE_RetVal_TwoParams( RetValType, DelegateName, Param1Type, Param2Type )

<RetVal> Function( <Param1>, <Param2>, ...)

DECLARE_DELEGATE_RetVal_<Num>Params( RetValType, DelegateName, Param1Type, Param2Type, ...)

同时还提供以上宏的变体,用于多投射、动态和包裹委托:

  • DECLARE_MULTICAST_DELEGATE...

  • DECLARE_DYNAMIC_DELEGATE...

  • DECLARE_DYNAMIC_MULTICAST_DELEGATE...

  • DECLARE_DYNAMIC_DELEGATE...

  • DECLARE_DYNAMIC_MULTICAST_DELEGATE...

委托签名声明可存在于全局作用域、在命名空间,甚至是类声明中(但无法存在于函数主体中)。

参见%Programming/UnrealArchitecture/Delegates/Dynamic:title% and 多播委托,了解声明此类委托的更多相关信息。

绑定委托

委托系统理解某些类型的对象,使用此类对象时将启用附加功能。将委托绑定到UObject或共享指针类的成员,委托系统可保留对该对象的弱引用,因此对象在委托下方被销毁时,可通过调用 IsBound()ExecuteIfBound() 函数进行处理。注意各类受支持对象的特殊绑定语法。

函数

描述

Bind()

绑定到现有委托对象。

BindStatic()

绑定原始C++指针全局函数委托。

BindRaw()

绑定原始C++指针委托。原始指针不使用任何类型的引用,因此如对象在委托下方被删除,引用原始指针可能不安全。需谨慎调用Execute()!

BindSP()

绑定基于指针的共享成员函数委托。共享指针委托会保留对对象的弱引用。可使用 ExecuteIfBound() 进行调用。

BindUObject()

绑定基于UObject的成员函数委托。UObject委托会保留对对象的弱引用。可使用 ExecuteIfBound() 进行调用。

UnBind()

取消绑定此委托。

参见 DelegateSignatureImpl.inl(位于 ..\UE4\Engine\Source\Runtime\Core\Public\Templates\),了解此类函数的变体、参数和实现。

负载数据

绑定到委托时,可同时传递负载数据。其为调用时被直接传到绑定函数的任意变量。此操作十分有用,利用其可在绑定时将参数存储在委托内。所有委托类型(除“动态”外)均自动支持负载变量。此范例将两个自定义变量(一个布尔,一个int32)传递到委托。之后调用该委托时,此类参数将被传到绑定函数。须始终接受委托类型参数后的额外变量参数。

MyDelegate.BindRaw( &MyFunction, true, 20 );

执行委托

通过调用委托的 Execute() 函数执行绑定到委托的函数。执行前须检查委托是否已绑定。此操作是为了使代码更安全,因为有时委托可能含有未初始化且被后续访问的返回值和输出参数。执行未绑定的委托在某些情况下确实可能导致内存混乱。可调用 IsBound() 检查是否可安全执行委托。同时,对于无返回值的委托,可调用 ExecuteIfBound(),但需注意输出参数可能未初始化。

执行函数

描述

Execute()

ExecuteIfBound()

IsBound()

参见多播委托,了解执行多投射委托的相关细节。

用法示例

假设类拥有可在任何地方随意调用的方法:

class FLogWriter
{
    void WriteToLog( FString );
};

要调用WriteToLog函数,需创建该函数签名的委托类型。为此,首先需使用以下宏声明委托。例如,以下是一个简单的委托类型:

DECLARE_DELEGATE_OneParam( FStringDelegate, FString );

此将创建名为“FStringDelegate”的委托类型,该类型使用“FString”类型的单个参数。

此为在类中使用此“FStringDelegate”的方法范例:

class FMyClass
{
    FStringDelegate WriteToLogDelegate;
};

利用此操作,类可保有指向任意类中的方法的指针。该类唯一真正了解的信息就是,此委托是其的函数签名。

如要分配委托,现在只需创建委托类的实例,将拥有该方法的类作为模板参数传递。同时还需传递对象的实例和方法的实际函数地址。因此,现在需创建“FLogWriter”类的实例,然后创建该对象实例“WriteToLog”方法的委托:

TSharedRef< FLogWriter > LogWriter( new FLogWriter() );

WriteToLogDelegate.BindSP( LogWriter, &FLogWriter::WriteToLog );

此操作可将委托动态绑定到类的方法!很简单,对吧?

注意:绑定到的对象由共享指针拥有,因此 BindSP 的SP部分代表共享指针。此外,还有不同对象类型的版本,例如BindRaw()和BindUObject()。

FMyClass现在可调用“WriteToLog”方法,甚至无需了解“FLogWriter”类的任何信息!要调用委托,只需使用“Execute()”方法:

WriteToLogDelegate.Execute( TEXT( "Delegates are spiffy!") );

如将函数绑定到网络前调用Execute(),将触发断言:多数情况下,建议进行以下操作:

WriteToLogDelegate.ExecuteIfBound( TEXT( "Only executes if a function was bound!") );
Select Skin
Light
Dark

欢迎来到全新虚幻引擎4文档站!

我们正在努力开发新功能,包括反馈系统,以便您能对我们的工作作出评价。但它目前还未正式上线。如果您对此页面有任何意见与在使用中遭遇任何问题,请前往文档反馈论坛告知我们。

新系统上线运行后,我们会及时通知您的。

发表反馈意见