(图片来源网络,侵删)
std::bind是C++11中一个函数模版,就像函数适配器,接受一个可调用对象(callable object),生成一个新的可调用对象通过它,我们可以实现类似传统的函数指针,函数回调等功能,并且能够降低代码的复杂度本文首先详细说明std::bind的基本用法以及解释使用过程中疑问点,然后再介绍如何利用传统函数指针搭建基础架构,再说明如何用std::bind来代替函数指针,最后介绍如何用std::bind来实现函数回调的功能一、std::bind的基本用法首先看下std::function, 它就是std::bind返回的新的可调用对象如下图,定义实现了普通加法函数Add, 然后将该函数指针赋值给std::function类型的变量,这里可以注意到,使用了Add和&Add进行赋值两者是等效的,这是因为使用Add的时候,会隐式转换成函数指针运行程序之后的输出信息,可以看出std::function类型的变量的使用与普通函数的使用是一样的我们不直接采用普通函数对std::function进行赋值,而是采用stb::bind,首先看下简单的实例,其中std::placeholders::_1和std::placeholders::_2是占位符,代表函数的入参如果调用的时候,需要传递具体实参,那么就需要使用placeholders来占位这里需要注意std::placeholders::_1并不是代表函数的第一个入参数,至于为什么,请继续往下阅读,下面将会通过实例进行阐述如果函数的第二个入参是一个固定值,那么第一个入参就需要使用占位符std::placeholders::_1,如下所示,函数第二个参数固定位数值5,那么使用std::function类型变量的时候,也只需要传递一个参数,该参数代表Add函数的第一个参数如果Add函数的第一个入参是一个固定值,那么第二个入参就需要使用占位符std::placeholders::_1(注意不是std::placeholders::_2),如下所示,函数第一个参数固定位数值6,那么使用std::function类型变量的时候,也只需要传递一个参数,该参数代表Add函数的第二个参数当然,如果函数Add的两个参数都是固定值,那么使用std::function类型变量的时候,就不需要参数了这里有个小技巧,如果不想要书写std::function那么繁琐的信息表示,那么可以采用auto代替,但是注意不要滥用auto.二、std::bind的扩展上面说明的是stb::bind使用普通函数的方法,那么如果是类的成员函数呢?应该如何使用呢?首先s td::bind的第一个参数是类成员函数指针,第二个参数为类对象的指针,其他的用法与使用普通函数的用法是一样的为了说明std::bind参数值是默认按照值传递的,首先实现函数Print, 该函数的入参是一个引用,函数内部将参数自增1,然后输出打印信息接着再通过输出std::bind使用前后日志信息来确认是否是按照值传递从输入的打印信息看,std::bind使用前后的信息没有发生变化,说明std::bind是默认按照值传递的如果想要按照引用来传递变量,应该如何操作呢,那么就是std::ref登场的时候,std::ref是用于包装引用传递的值从输出打印信息看,采用std::ref传递变量之后,std::bind使用前后的信息发生变化了另外补充一点,std::cref用于包装const引用传递的值三、传统函数指针函数指针变量用于存储函数指针,以便后续的调用有时候可以利用它实现多个消息对象的处理,并且一定程度满足开闭原则首先实现抽象基类JAbstractBaseTest,接着再实现继承JAbstractBaseTest的两个子类JObjA和JObjB完成上面的测试类,接着实现基础的框架,定义函数指针CreateObj,该函数指针用于动态创建对象,然后再分别实现初始化创建对象的函数指针映射表以及通过id从映射表中获取函数对象的两个函数使用调用方式如下,通过id获取对象指针,然后执行对象的run函数通过这样的方式,可以做到主体循环不变,如果需要添加新的对象处理,那么只要实现新的类,然后添加到映射表中即可四、std::bind代替函数指针std::bind和std::function的结合,可以实现函数指针的功能通过using Funtor = std::function<void (void)>来实现类似函数指针的声明其中Funtor表示std::function<void (void)>的别名然后在初始化表函数InitTab中,通过使用std::bind将类的函数成员一一映射到map中调用JDebugBind的方式如下,只需要传递函数的id给函数RunTest,即可执行到对应的函数同样的,后续如果想要添加新的功能,那么只要实现新的函数,并且将其添加到map中即可五、std::bind实现函数回调函数回调在编程实现是一个特别重要的特性,它经常会在一些架构中使用到而std::bind是可以实现函数回调的特性的下图实现的类JDebugCallback中,构造函数接受一个类型为std::function的参数之后,将其赋值给类的成员函数m_callback,后续调用函数Start的时候,Start函数内部再调用m_callback,从而实现函数回调这里只是一个简单的例子说明,可能还不能充分看到函数回调的强大希望这里作为一个引入,后续在实际工作中,再慢慢的体会最后看下怎么使用JDebugCallback类,实现类两个函数CallBack01和CallBack02,然后通过std::bind传递给JDebugCallback,接着JDebugCallback对象调用Start来执行传递进来的函数五、总结至此,C++11提供的std::bind的用法和扩展已经介绍完毕,虽然工作中有各种各样的需求场景,但是只要掌握了知识的基本原理,就能够以不变应万变本文介绍了std::bind的各种基本应用场景,并结合了例子进行说明,相信应该已经说明白了
0 评论