定义
#define FUNC_CONCAT( ... ) __VA_ARGS__
#define DECLARE_DYNAMIC_DELEGATE( DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, , FUNC_CONCAT( *this ), void )
定义一个动态单播,UHT会根据BODY_MACRO_COMBINE生成一个FILE_ID_LINE_DELEGATE宏,这个函数留到后面说。
先看FUNC_DECLARE_DYNAMIC_DELEGATE 宏定义
#define FUNC_DECLARE_DYNAMIC_DELEGATE( TWeakPtr, DynamicDelegateName, ExecFunction, FuncParamList, FuncParamPassThru, ... ) \
class DynamicDelegateName : public TBaseDynamicDelegate<TWeakPtr, __VA_ARGS__> \
{ \
public: \
DynamicDelegateName() \
{ \
} \
\
/** Construction from an FScriptDelegate must be explicit. This is really only used by UObject system internals. */ \
explicit DynamicDelegateName( const TScriptDelegate<>& InScriptDelegate ) \
: TBaseDynamicDelegate<TWeakPtr, __VA_ARGS__>( InScriptDelegate ) \
{ \
} \
\
/** Execute the delegate. If the function pointer is not valid, an error will occur. */ \
inline void Execute( FuncParamList ) const \
{ \
/* Verify that the user object is still valid. We only have a weak reference to it. */ \
checkSlow( IsBound() ); \
ExecFunction( FuncParamPassThru ); \
} \
/** Execute the delegate, but only if the function pointer is still valid */ \
inline bool ExecuteIfBound( FuncParamList ) const \
{ \
if( IsBound() ) \
{ \
ExecFunction( FuncParamPassThru ); \
return true; \
} \
return false; \
} \
};
声明一个动态委托, 并使用包装代理方法(DelegateName##_DelegateWrapper)执行委托.
再看看基类TBaseDynamicDelegate,基类里有个重要的方法,我们在用宏定义绑定函数时遇到过,就是AddDynamic宏, 它实际上被宏定义为成员函数__Internal_BindDynamic
template <typename TWeakPtr, typename RetValType, typename... ParamTypes>
class TBaseDynamicDelegate : public TScriptDelegate<TWeakPtr>
{
public:
template< class UserClass >
class TMethodPtrResolver
{
public:
typedef RetValType (UserClass::*FMethodPtr)(ParamTypes... Params);
};
template< class UserClass >
void __Internal_BindDynamic( UserClass* InUserObject, typename TMethodPtrResolver< UserClass >::FMethodPtr InMethodPtr, FName InFunctionName )
{
check( InUserObject != nullptr && InMethodPtr != nullptr );
this->Object = InUserObject;
// Store the function name. The incoming function name was generated by a macro and includes the method's class name.
this->FunctionName = InFunctionName;
ensureMsgf(this->IsBound(), TEXT("Unable to bind delegate to '%s' (function might not be marked as a UFUNCTION or object may be pending kill)"), *InFunctionName.ToString());
}
};
#define BindDynamic( UserObject, FuncName ) __Internal_BindDynamic( UserObject, FuncName, STATIC_FUNCTION_FNAME( TEXT( #FuncName ) ) )
TBaseDynamicDelegate继承自TScriptDelegate, TScriptDelegate里定义了绑定对象和函数名, 还有最重要的ProcessDelegate函数
template <typename TWeakPtr = FWeakObjectPtr>
class TScriptDelegate
{
public:
void BindUFunction( UObject* InObject, const FName& InFunctionName )
{
Object = InObject;
FunctionName = InFunctionName;
}
void Unbind()
{
Object = nullptr;
FunctionName = NAME_None;
}
template <class UObjectTemplate>
void ProcessDelegate( void* Parameters ) const
{
checkf( Object.IsValid() != false, TEXT( "ProcessDelegate() called with no object bound to delegate!" ) );
checkf( FunctionName != NAME_None, TEXT( "ProcessDelegate() called with no function name set!" ) );
UObjectTemplate* ObjectPtr = static_cast< UObjectTemplate* >( Object.Get() ); // Down-cast
checkSlow( !ObjectPtr->IsPendingKill() );
// Object *must* implement the specified function
UFunction* Function = ObjectPtr->FindFunctionChecked( FunctionName );
// Execute the delegate!
ObjectPtr->ProcessEvent(Function, Parameters);
}
protected:
TWeakPtr Object;
FName FunctionName;
friend class FCallDelegateHelper;
};
对于ProcessDelegate, 通过在绑定到委托的对象上调用命名函数来执行委托. 在调用此函数之前,应始终先通过调用IsBound() 来验证委托是否可以安全执行.
通常,永远不要直接调用此函数. 而是在派生类上调用Execute().
意思就是说, ProcessDelegate应该在我们自定义的DynamicDelegateName类执行Execute(), 通过上面代码描述知道,Execute内部执行的是ExecFunction函数, 也就是宏定义里的DelegateName##_DelegateWrapper函数.
DelegateName##_DelegateWrapper函数的定义,就是UHT为我们在generated.h头文件里生成的
#define Hello_Source_Hello_Public_MyObject_h_9_DELEGATE \
static inline void FMyTestDynamicDelegate_DelegateWrapper(const FScriptDelegate& MyTestDynamicDelegate) \
{ \
MyTestDynamicDelegate.ProcessDelegate<UObject>(NULL); \
}
可以看到, 生成的MyDelegateDemo_Source_MyDelegateDemo_MyClass_h_17_DELEGATE宏里, 就是一个FMyTestDynamicDelegate_DelegateWrapper函数, 它内部调用了ProcesDelegate函数.
MyClassDelegate_DelegateWrapper的参数是一个FScriptDelegate类引用, 通过宏定义我们知道,我们在Execute的时候传了一个FuncParamPassThru参数, 而FuncParamPassThru参数的定义是
#define FUNC_CONCAT( ... ) __VA_ARGS__
FUNC_CONCAT( *this )
因此, 我们将this指针解引用然后传过去.
FMyTestDynamicDelegate_DelegateWrapper的参数是一个FScriptDelegate参数, 而我们的代理类是一个TScriptDelegate的子类,点FScriptDelegate然后F12, 然后在WeakObjectPtr.h里,看到了typedef定义
// Typedef script delegates for convenienceconvenience.
typedef TScriptDelegate<> FScriptDelegate;
这是返回值为void的动态单播类型,类似的还有一个带返回值的动态单播FUNC_DECLARE_DYNAMIC_DELEGATE_RETVAL,唯一区别就是这个宏指定了返回值RetValType.