C++高级开发之可调用对象、function、bind(1):https://developer.aliyun.com/article/1415893
std::bind 绑定器
要使用这个函数模板,在 cpp文件前面要包含如下头文件#include
std::bind能够将对象以及相关的参数绑定到一起,绑定完成后可以直接调用,也可以用
std::function进行保存,在需要的时候调用。该函数模板的一般使用格式如下:
std::bind(待绑定的函数对象/函数指针/成员函数指针,绑定参数1...绑定参数n);
std::bind有两个意思:
- 将可调用对象和参数绑定到一起,构成一个仿函数,所以可以直接调用
- 如果函数有多个参数,可以绑定部分参数,其他的参数在调用的时候指定
具体演示:在main函数中加入如下代码:
void myfunc1(int x, int y, int z) { cout << "x=" << x << ",y=" << y << ",z=" << z << endl; }
在主函数中,加入如下代码
//表示绑定函数myfunc1的第一,二,三个参数值为:10 20 30,返回值auto表示我们不关心它返回的是啥类型, //实际它返回的也是个仿函数类型对象,可以直接调用,也可以赋给std::function auto bf1 = std::bind(myfunc1, 10, 20, 30); bf1();
上述范例非常简单,在 std::bind中,就可以直接给 myfunc1指定各参数。
具体演示2:
//表示绑定函数myfunc1的第三个参数为30,而myfunc1的第一,二个参数分别由调用bf2时的第一,二个参数指定, _1、_2...、_20这种是标准库里定义的,占位符的含义,类似这样的参数有20个, //够我们用了,这里这个placeholders::_1表示这个位置(当前该placeholders::_1所在的位置)将在函数调用时,被传入的第一个参数所代替。 auto bf2 = std::bind(myfunc1, placeholders::_1, placeholders::_2, 30); bf2(5, 15);
直接调用也可以
std::bind(myfunc1, placeholders::_1, placeholders::_2,30)(10, 20);
再看一例:
在 cpp文件前面增加 myfun2函数的定义。
void myfunc2(int& x, int& y) { x++; y++; }
在main函数中加入如下代码。注释很关键
int a = 2; int b = 3; auto bf4 = std::bind(myfunc2, a, placeholders::_1); bf4(b); //执行后a=2,b=4。这说明:bind对于预先绑定的函数参数是通过值传递的,所以这个a实际上是值传递的。 //bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的,所以这个b实际上是引用传递的 cout << "a: "<<a<<"b:"<<b << endl;
在看一例:
在 cpp文件中增加 CQ类定义
class CQ { public: CQ() { printf("CQ::CQ()构造函数执行,this=%p\n", this); } CQ(const CQ&) { printf("CQ::CQ(const CQ&)拷贝构造函数执行,this=%p\n", this); } ~CQ() { printf("CQ::~CQ()析构函数执行,this=%p\n", this); } public: void myfunpt(int x, int y) { cout << "x=" << x << ",y=" << y << endl; m_a = x; } int m_a = 0; //成员变量 };
在main函数中,加入如下代码:
CQ cq; //一个类对象 auto bf5 = std::bind(&CQ::myfunpt, cq, placeholders::_1, placeholders::_2); //类函数有绝对地址,和对象无关,但要被调用必须有类对象参数 bf5(10, 20);//对成员函数的调用
注意上面代码中,std::bind的第二个参数 cq会导致生成一个临时的 CQ对象std::bind是将该临时对象和相关的成员函数以及多个参数绑定到一其,后续对 myfunpt成员函数的调用修改的是这个临时的 CQ对象的额m_a,并不影响真实的 cq对象的 m_a值。
如果将 std::bind的第二个参数 cq前面增加 &,这样就不会导致生成一个临时的CQ对象,后续的修改就是直接对cq对象的修改了。
在main函数中继续计入代码,观察 bind和 function的配合使用
//bind 和 function配合使用(bind返回值直接赋给 std::function类型) CQ cq; std::function<void(int, int)> bfc6 = std::bind(&CQ::myfunpt, cq, std::placeholders::_1, std::placeholders::_2); bfc6(10, 20);
cq->bind->function(构造->拷贝->拷贝)
加入饮用之后能够明显看到效率的提高
总结
因为有了占位符,所以 std::bind的使用就变得非常灵活。可以直接绑定函数的所有参数,也可以使用 std::placeholders来决定bind所在位置的参数将会属于调用发生时的第几个参数。
std::bind 的思想实际上是一种延迟计算的思想,将可调用对象保存起来,然后后在需要的时候在调用。
- std::function 一般要绑定一个可调用对象,类成员函数不能被绑定。而 std::bind更加强大,成员函数、成员变量等都能绑定。现在通过 std::function和std::bind的配合,所有的可调用对象都有了统一的操作方法。