【C/C++】【C++11】可调用对象/function/bind
可调用对象
函数指针
void myfunc(int tv)
{
cout << tv << endl;
}
int main()
{
void (*func)(int) = myfunc; //定义函数指针并赋值;
func(10); //调用函数,可调用对象;
}
仿函数
具有operator()成员函数的类对象
仿函数functor:行为类似于函数;仿函数通过在类中重载()运算符实现,又成为函数对象,能起到函数功能的类;
class Fc
{
public:
void operator()(int tv)
{
cout << tv << endl;
}
};
int main()
{
Fc fc;
fc(20);
}
可被转换为函数指针的类对象
// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//auto类型推断,auto应用场合
#include <iostream>
#include <algorithm>
using namespace std;
class Test
{
public:
using func_p = void(*)(int); //定义一个函数指针类型;
static void fun(int tv) //静态成员函数;
{
cout << tv << endl;
}
operator func_p()
{
return fun;
}
};
int main()
{
Test t;
t(50); //先调用func_p,在调用静态成员 func_p;//等价于t.operator Test::func_p()(20);
t.operator Test::func_p()(20);
return 0;
}
类成员函数指针
// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//auto类型推断,auto应用场合
#include <iostream>
#include <algorithm>
using namespace std;
class Fc
{
public:
void operator()(int tv)
{
cout << tv << endl;
}
void func(int tv)
{
cout << tv << endl;
}
public:
int m_a;
};
int main()
{
Fc fc;
void (Fc:: *func_p)(int) = &Fc::func; //类成员函数指针变量func_p定义并给初值;
(fc.*func_p)(68);
return 0;
}
总结
- 看成对象;
- 可以对其使用()调用运算符;
std::function(可调用对象包装器)
- std::function是个类模板,用来装各种可调用对象,不能装类成员函数指针;
- 头文件 functional
- 通过给std::function指定模板参数,它就能用统一的方式处理函数
绑定普通函数
#include <iostream>
#include <functional>
using namespace std;
void func(int tv)
{
cout << tv << endl;
}
int main()
{
std::function<void(int) > f = func;
f(100);
return 0;
}
绑定类的静态成员函数
// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//auto类型推断,auto应用场合
#include <iostream>
#include <functional>
using namespace std;
class Fc
{
public:
void operator()(int tv)
{
cout << tv << endl;
}
void func(int tv)
{
cout << tv << endl;
}
static int static_func(int tv)
{
cout << tv << endl;
return tv;
}
public:
int m_a;
};
int main()
{
std::function<int(int) > f = Fc::static_func;
f(100);
return 0;
}
绑定仿函数
// other.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
//auto类型推断,auto应用场合
#include <iostream>
#include <functional>
using namespace std;
class Fc
{
public:
void operator()(int tv)
{
cout << tv << endl;
}
void func(int tv)
{
cout << tv << endl;
}
static int static_func(int tv)
{
cout << tv << endl;
return tv;
}
public:
int m_a = 0;
};
int main()
{
Fc t;
std::function<void(int) > f = t;
f(100);
return 0;
}
范例1
#include <iostream>
#include <functional>
using namespace std;
class Other
{
std::function<void()> callba;
public:
Other(const std::function<void()>& f) :callba(f)
{
int i;
i = 1;
}
void run_call(void)
{
callba();
}
};
class Another
{
public:
void operator()(void)
{
cout << "void operator()(void)" << endl;
}
};
int main()
{
Another an; //可调用对象
Other o(an); //Other需要可调用对象做参数来构造,因为operator可以转为std::fuinction<void()&>
o.run_call(); //执行Other里的run_call;
return 0;
}
范例2
#include <iostream>
#include <functional>
using namespace std;
void call_back(int x, const std::function<void(int) >& f)
{
f(x);
}
void func(int x)
{
cout << x << endl;
}
int main()
{
for (int i = 0; i < 10; ++i)
{
call_back(i, func); //func(i)
}
return 0;
}
std::bind(绑定器)
-
C++11引入的,类模板;
-
头文件 functional
-
std::bind能够将对象以及相关的参数绑定到一起,绑定后可以直接调用;也可以使用std::function进行保存,需要的时候再调用;
-
格式
std::bind(带绑定的函数对象, 参数1, 参数2, ..., 参数n);
范例1
#include <iostream>
#include <functional>
using namespace std;
void func(int x, int y, int z)
{
cout << x << " " << y << " " << z << endl;
}
int main()
{
auto b1 = std::bind(func, 10, 20, 30); //auto不关心bind的返回类型,其实bind返回的是一个仿函数类型对象,可以直接调用,也可以赋值给std::function
b1(); //执行func函数
return 0;
}
范例2
#include <iostream>
#include <functional>
using namespace std;
void func(int x, int y, int z)
{
cout << x << " " << y << " " << z << endl;
}
int main()
{
//表示绑定函数func的第三个参数为30;
//第一个和第二个参数分别由调用b1时的第一个和第二个参数指定;
//placeholders::_1 被调用的时候的第一个参数替代;
auto b1 = std::bind(func, placeholders::_1, placeholders::_2, 30);
b1(10, 20);
std::bind(func, placeholders::_1, placeholders::_2, 30)(10, 20); //直接调用
return 0;
}
范例3
#include <iostream>
#include <functional>
using namespace std;
void func(int& x, int& y, int& z)
{
x++;
y++;
z++;
cout << x << " " << y << " " << z << endl;
}
int main()
{
//表示绑定函数func的第三个参数为30;
//第一个和第二个参数分别由调用b1时的第一个和第二个参数指定;
//placeholders::_1 被调用的时候的第一个参数替代;
int a = 2, b = 3, c = 4;
auto b1 = std::bind(func, a, placeholders::_1, c);
b1(b);
cout << a << " " << b << " " << c << endl; // a和c的值没有发生改变;
//bind对于预先绑定的函数参数是通过值传递的;即a,c
//bind对于事先先绑定的参数,通过std::placeholders传递的参数,是通过引用传递的;即b
return 0;
}
范例4
#include <iostream>
#include <functional>
using namespace std;
class Test
{
public:
void func(int x, int y)
{
cout << x << " " << y << endl;
m_a = x;
cout << m_a << endl;
}
public:
int m_a = 0;
};
int main()
{
Test t;
//bind的第二个参数t,会导致调用Test的拷贝构造函数来生成一个Test类型的临时对象,作为std::bind的返回值(bind返回仿函数类型对象);
//后续的func调用修改的是临时对象的m_a; 并不影响真实t对象的m_a的值;
auto b1 = std::bind(&Test::func, t, placeholders::_1, placeholders::_2);
b1(2, 3);
//加了&,就不生成临时对象了,后续func调用修改的是t对象的m_a值,此时bind返回的这个对象其实是t对象本身(仿函数类型对象)
auto b2 = std::bind(&Test::func, &t, placeholders::_1, placeholders::_2);
b2(2, 3);
return 0;
}
范例5
#include <iostream>
#include <functional>
using namespace std;
class Test
{
public:
void func(int x, int y)
{
cout << x << " " << y << endl;
m_a = x;
cout << m_a << endl;
}
public:
int m_a = 0;
};
int main()
{
Test t;
std::function<void(int, int)> b = std::bind(&Test::func, t, std::placeholders::_1, std::placeholders::_2);
b(10, 20);
return 0;
}
范例6
#include <iostream>
#include <functional>
using namespace std;
class Test
{
public:
Test()
{
cout << "Test()" << endl;
}
Test(const Test& t)
{
cout << "Test(Test& t)" << endl;
m_a = t.m_a;
}
~Test()
{
cout << "~Test()" << endl;
}
void func(int x, int y)
{
cout << x << " " << y << endl;
m_a = x;
cout << m_a << endl;
}
public:
int m_a = 0;
};
int main()
{
Test t;
//把成员变量地址当函数一样绑定,绑定的结果放在std::function<int &(void)> 里保存,就是用一个可调用对象来保存;
std::function<int& ()> b = std::bind(&Test::m_a, t); //bind第二个参数不是引用,会导致两次Test类拷贝构造函数的执行;
//1. 利用t产生一个临时的Test对象;
//2. std::bind本身要返回一个Test对象,要返回的Test对象(仿函数)拷贝自临时的Test对象;但是std::bind执行完毕后,临时Test对象会被释放,返回的这个Test对象(仿函数)拷贝到b中;
b() = 60;
return 0;
}
范例7
#include <iostream>
#include <functional>
using namespace std;
class Test
{
public:
Test()
{
cout << "Test()" << endl;
}
Test(const Test& t)
{
cout << "Test(Test& t)" << endl;
m_a = t.m_a;
}
~Test()
{
cout << "~Test()" << endl;
}
void func(int x, int y)
{
cout << x << " " << y << endl;
m_a = x;
cout << m_a << endl;
}
public:
void operator()()
{
cout << "void operator()()" << endl;
}
public:
int m_a = 0;
};
int main()
{
auto t = std::bind(Test()); //Test是构造临时对象,然后又调用了拷贝构造函数 生成了一个可调用对象,作为std::bind的返回内容;
//bind返回仿函数类型对象,就是则会个用拷贝构造函数构造起来的对象;
t();
return 0;
}
范例8
#include <iostream>
#include <functional>
using namespace std;
void callback(int test, const std::function<void(int)>& f)
{
f(test);
}
void func(int x)
{
cout << x << endl;
}
int main()
{
auto bind_f = std::bind(func, std::placeholders::_1); //func的第一个参数由调用时候的第一个参数指定;
for (int i = 0; i < 10; i++)
{
callback(i, bind_f);
}
return 0;
}
总结
- std::bind将可调用对象和参数绑定到一起,构成一个仿函数,所以可以直接调用;
- 如果函数有多个参数,可以绑定一部分参数,其他参数在调用的时候指定;
- bind思想所谓的延迟调用,将可调用对象统一格式,保存起来,需要的时候再调用;
- std::function可以绑定要给可调用对象,类型成员不能绑定;std::bind成员函数,成员变量等等都能绑;
知识的价值不在于占有,而在于使用