赞
踩
本文章只是我个人在学习虚幻引擎过程中的理解,不一定正确,若有说的不对的地方,欢迎指正。
以下引用的源码在Engine\Source\Runtime\Core\Public\Delegates\文件夹下的文件内均可找到
静态单播的我们以分析DECLARE_DELEGATE_OneParam作为突破口。
先来看看他的基本定义:
#define DECLARE_DELEGATE_OneParam( DelegateName, Param1Type ) FUNC_DECLARE_DELEGATE( DelegateName, void, Param1Type )
可以看出代理最终封装为宏,传入两个宏参数——代理名(DelegateName),参数类型(Param1Type )。再传给FUNC_DECLARE_DELEGATE宏,再来看看它的定义:
#define FUNC_DECLARE_DELEGATE( DelegateName, ... ) \
typedef TBaseDelegate<__VA_ARGS__> DelegateName;
FUNC_DECLARE_DELEGATE接受代理名(DelegateName)和可变参数(那三个点就是可变参数)。它用类型重定义关键字(typedef),把传入可变参数(VA_ARGS)作为模板参数的模板类TBaseDelegate,类型重定义为DelegateName。
可能有些拗口。用通俗的语言解释就是,给传入了模板参数的模板类重新起个名字,这个名字就是我们传进来的代理名(DelegateName),使用代理的第一个步骤声明代理中(《UE4 代理(Delegate)的使用》文章中说过三个步骤),生成代理对象其实就是声明一个TBaseDelegate类的实例。
现在让我们来看看TBaseDelegate模板类的大致定义:
template <typename WrappedRetValType, typename... ParamTypes> class TBaseDelegate : public FDelegateBase { public: //…… //一系列创建代理的函数(CreateStatic、CreateLambda、CreateWeakLambda、CreateRaw、CreateSP、CreateThreadSafeSp、CreateUFunction、CreateUObject) //…… public: //…… //一系列绑定函数(BindStatic、BindLambda、BindRaw、BindSP、BindThreadSafeSP、BindUFunction、BindUObject) //…… public: //执行函数 RetValType Execute(ParamTypes... Params); };
可以看到模板类TBaseDelegate继承自FDelegateBase(等下来说),模板类里定义了一系列的创建函数(Create**)和我们熟悉的绑定函数(**Bind),还实现了执行代理的方法——Execute。
这些函数的细节部分在下一个小标题再说,现在先来看看FDelegateBase的实现:
class FDelegateBase { public: //…… bool IsBound( ) const { //Do Something } //…… void Unbind( ) { //Do Something } //…… };
FDelegateBase实现了判断是否绑定的方法(IsBound)和解除绑定的方法(Unbind)。来看看类图:
还记得前文所说的TBaseDelegate模板类实现的那些绑定函数吗?我们在代理声明步骤生成了一个TBaseDelegate的类实例,在绑定函数步骤调用了它的绑定函数(Bind~)。绑定函数的实现大致相同,我们以BindUObject为例,先来看看引擎源码:
template <typename UserClass, typename... VarTypes>
inline void BindUObject(UserClass* InUserObject, typename TMemFunPtrType<true, UserClass, RetValType (ParamTypes..., VarTypes...)>::Type InFunc, VarTypes... Vars)
{
*this = CreateUObject(InUserObject, InFunc, Vars...);
}
可以看出BindUobject是模板函数:
有两个模板参数——绑定函数所在类的类型(UserClass)和传给绑定函数的一系列参数的类型(VarTypes);
有三个函数参数——绑定函数所在类的实例(InUserObject)、绑定函数(InFunc)、传给绑定函数的一系列参数(Vars)。
BindUobject调用CreateUObject(前文提到过),传入自身所有参数。CreateUObject根据传入的参数创建并返回一个TBaseDelegate的实例赋值给this指针,进去看看CreateUObject:
TBaseDelegate<RetValType, ParamTypes...> CreateUObject(UserClass* InUserObject, typename TMemFunPtrType<true, UserClass, RetValType (ParamTypes..., VarTypes...)>::Type InFunc, VarTypes... Vars)
{
TBaseDelegate<RetValType, ParamTypes...> Result;
TBaseUObjectMethodDelegateInstance<true , UserClass, TFuncType, VarTypes...>::Create(Result, InUserObject, InFunc, Vars...);
return Result;
}
CreateUObject先创建一个TBaseDelegate类实例(Result)用来存放结果,使用TBaseUObjectMethodDelegateInstance内的Create方法,修改Result的数据,最终返回Result。
关于TBaseUObjectMethodDelegateInstance,在TBaseDelegate类内创建函数(Create**)和绑定函数(**Bind)的上方,有关于TBaseUObjectMethodDelegateInstance一系列子类的代码(源码中每一个都写成一行,我整理成熟悉的格式):
template <typename UserClass, typename Var1Type>
struct TUObjectMethodDelegate_OneVar : TBaseUObjectMethodDelegateInstance<false, UserClass, TFuncType, Var1Type>
{
typedef TBaseUObjectMethodDelegateInstance<false, UserClass, TFuncType, Var1Type> Super;
TUObjectMethodDelegate_OneVar(UserClass* InUserObject, typename Super::FMethodPtr InMethodPtr, Var1Type Var1)
: Super(InUserObject, InMethodPtr, Var1)
{}
};
注:源码不少,只列举其中之一,具体可去源文件查看
根据代理函数参数的个数定义了不同的TBaseUObjectMethodDelegateInstance子类,在CreateUObject函数中,根据传入的参数自动匹配合适的TBaseUObjectMethodDelegateInstance子类,进去看看它的源码和”亲戚“:
template <bool bConst, class UserClass, typename WrappedRetValType, typename... ParamTypes, typename... VarTypes> class TBaseUObjectMethodDelegateInstance<bConst, UserClass, WrappedRetValType (ParamTypes...), VarTypes...> : public IBaseDelegateInstance<typename TUnwrapType<WrappedRetValType>::Type (ParamTypes...)> { // …… public: TBaseUObjectMethodDelegateInstance(UserClass* InUserObject, FMethodPtr InMethodPtr, VarTypes... Vars) : UserObject(InUserObject) , MethodPtr (InMethodPtr) , Payload (Vars...) , Handle (FDelegateHandle::GenerateNewHandle) { // …… } // …… protected: // Pointer to the user's class which contains a method we would like to call. TWeakObjectPtr<UserClass> UserObject; // C++ member function pointer. FMethodPtr MethodPtr; // Payload member variables (if any). TTuple<VarTypes...> Payload; // …… };
TBaseUObjectMethodDelegateInstance其实是真正保存绑定函数和函数所在类的地方,构造函数接收Create传过来的参数并保存——UserObject记录函数所在类的实例、MethodPtr记录绑定函数、Payload记录参数。
到这里绑定就基本完成了,现在再来看看执行(Execute):
FORCEINLINE RetValType Execute(ParamTypes... Params) const
{
TDelegateInstanceInterface* LocalDelegateInstance = GetDelegateInstanceProtected();
return LocalDelegateInstance->Execute(Params...);
}
GetDelegateInstanceProtected函数获取前面提到的保存绑定函数的TBaseUObjectMethodDelegateInstance子类实例,再调用其中的Execute方法传入参数,该方法借助保存参数的类型——TTuple,调用ApplyAfter,并传入保存绑定函数指针来调用绑定函数:
virtual RetValType Execute(ParamTypes... Params) const override final
{
// ……
return Payload.ApplyAfter(TMemberFunctionCaller<MutableUserClass, FMethodPtr>(MutableUserObject, MethodPtr), Params...);
}
好了,用了这么多笔墨只讲了个单播 ,浅析了一下单播代理中的DECLARE_DELEGATE_OneParam,了解了它其他类型的单播也是这个实现思路,一一列出太冗余了,可以的话还是希望大家能去源码看看。
笔者越看越佩服虚幻引擎的开发者,真的把C++用的出神入化,由于笔者水平有限,可能很多地方没讲清楚,本章就到这,谢谢观看 。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。