欢迎光临散文网 会员登陆 & 注册

C++委托

2022-11-28 13:13 作者:有个小小杜  | 我要投稿

委托在开发过程中的重要性

        在游戏开发过程中,委托是一个必不可少东西,它可以动态绑定和解绑函数,可以使我们在开发过程中不必要过多的关注我们需要调用的对象,只需要关注调用的时刻,在SDL或者Win32开发中,其中窗体应用程序基本会使用循环来处理消息通知,而在消息通知中我们在获取到通知之后,该做什么事这个部分,就可以充分的利用委托来帮我们做。

例如:

        这种方式是没有委托的方式,十分不不友好,因为在窗体处理消息时,需要获取实例A,B,C的指针,来通过鼠标左键点击来处理A,B,C的逻辑,这使得我们每次在添加一个物体的鼠标逻辑时,都需要修改一次消息处理的代码。

        当有了委托之后,消息处理函数不必关心调用的是什么逻辑,就通过委托(Delegate)广播需要实现左键点击操作的函数,当我们要添加一个物体进行左键点击操作时,只需要将物体的函数绑定到委托上,就需要修改消息处理的逻辑。

委托的实现原理以及实现

        在虚幻游戏引擎提供的功能中,有一项就是委托,我们可以方便的使用委托这个功能开发各种逻辑,但是原生C++是没有委托的,如果我们使用原生C++开发程序时,自己造一个委托的轮子,在以后开发C++程序的过程中都可以用上。

        委托的本质就是一个结构体或一个类,里面封装了一些功能比如Bind(),UnBind(),包括重载了()运算符,等功能,类中的成员变量其中就有指向函数的指针,通过函数指针来调用我们绑定的函数,如果是多播委托(一个委托可以绑定多个函数),里面会有函数指针的表,遍历表里所有的函数指针来达到一次性调用多个函数的目的。

        再来,我们委托绑定的函数可以为不同参数,也可能为不同的返回值,在这里我们就需要用C++模板的知识了,我们定义一个委托类模板,通过不同模板参数来实例化不同的模板类,按照这个思路,我们开始来实现吧。

  • 先定义一个委托实现的接口:

        定义一个接口IDelegate模板,绑定的函数有返回值和有传入参数,所以定义模板参数ReturnT为返回值类型,...ArgsT为传入参数类型。将operator()定义为纯虚函数,继承这个接口的类必须实现operator()函数,实现Delegate的多态,因为委托可能会绑定类成员函数,也可能会绑定非类成员函数。

  • 继承接口定义实现委托的类:

        继承IDelegate来定义类成员函数委托模板DynamicDelegate,要调用一个类成员函数,必须得有类的实例,类成员函数的指针,模板参数多了一个ClassT,ClassT为类成员函数所属于的类的类型。DynamicDelegate的成员变量为类实例的指针,类成员函数的函数指针,通过实现IDelegate接口的operator()函数,来调用类的成员函数。

        继承IDelegate来定义非类成员函数委托模板StaticDelegate,StaticDelegate的成员变量为非类成员函数的函数指针,通过实现IDelegate接口的operator()函数,来调用类的成员函数。

  • 实现单播委托:

        定义单播委托模板,单播委托(一个委托只能绑定一个函数),成员变量为一个IDelegate指针(我选择了用智能指针unique_ptr指向IDelegate实例,这是垃圾回收相关的问题,这里不展开讨论)。IDelegate指针可以指向DynamicDelegate 和StaticDelegate 这两个委托类,不用关心指针指向的是类成员函数委托还是非类成员函数委托,因为IDelegate::operator()是虚函数。Bind()和Clear()实现了绑定函数和解绑函数的操作,Bind()函数重载了两个版本,一个用于绑定类成员函数,一个用于绑定非类成员函数,Invoke()用来执行委托的单播,作用和operarot()一样。(函数具体实现在文末尾的链接里)

  • 实现多播委托:

        定义多播委托模板,多播委托(一个委托绑定多个函数),和单播委托不一样的地方就是,多播委托绑定多个函数时需要多个IDelegate指针,我们就用C++标准库的容器vector来存储这多个IDelegate指针。AddFunc()和RemoveFunc()实现了添加函数绑定和移除函数绑定的操作,并针对类成员函数和非类成员函数重载了两个版本,Clear()实现了对所有函数绑定的清空,BroadCast()负责遍历IDelegate指针依次调用绑定的函数,作用和operator()一样。(函数具体实现在文末尾的链接里)

  • 添加宏定义:

        用过虚幻引擎的小伙伴们应该都知道,虚幻引擎无论是单播,多播,还是动态委托基本都是通过宏来声明的,我添加这个宏定义也是为了让我更方便的定义一个委托。

DECLARE_FUNCTION_DELEGATE(委托名,返回值,参数...)来定义单播委托。

DECLARE_FUNCTION_MULTICAST_DELEGATE(委托名,参数...)来定义多播委托。

测试结果

        通过DECLARE_FUNCTION_MULTICAST_DELEGATE(FAddDelegate, int, int)定义了多播委托FAddDelegate,声明一个多播委托OnAdd,绑定对象a函数,对象b的函数,和全局函数,执行多播,结果如下:


C++委托运行结果

既然原生C++没有委托,那我们就试着造一个轮子吧。

C++委托源代码链接:https://github.com/YGXXD/Cpp-Delegate

C++委托的评论 (共 条)

分享到微博请遵守国家法律