function函數回調+bind詳解
文章目錄
一.bind函數適配器詳解
前言.C語言與C++中函數指針回顧
double divide(double x, double y) { return x / y; }
void test0()
{
//C++
function<double(double, double)> func1 = divide;
cout << func1(10, 2) << endl;
//C
double (*func2)(double, double) = divide;
cout << func2(12,3) << endl;
typedef double(*Func)(double,double);
Func func3 = divide;
cout << func3(15,5) << endl;
}
1.function + bind 綁定普通函數
bind可以綁定函數中的參數再進行使用,比C語言中的更爲方便。
同時需要注意:bind實質上是將函數入口進行了綁定
void test1()
{
using namespace placeholders;
function<double()> func1 = bind(divide, 10, 2);
cout << func1() << endl;
function<double(double)> func2 = bind(divide, _1, 2);
cout << func2(6) << endl;
function<double(double)> func3 = bind(divide, 6, _1);
cout << func3(1) << endl;
function<double(double, double)> func4 = bind(divide, _1, _2);
cout << func4(4, 2) << endl;
auto func5 = bind<int>(divide, 12.5, 3); //相當於 (int)divide(12.5, 3)
cout << func5() << endl;
}
2.綁定類中的成員
首先要明白,直接將類中的成員函數賦值給函數指針是行不通的,因爲成員函數中有隱含的this指針,是無法一併傳給函數指針的。
如果是直接想綁定類中的成員函數的話:
1). 要麼這個函數必須是static修飾(這樣的話成員函數就不再擁有this指針,可以直接傳遞給函數指針,指針指向函數入口)
2). 要麼在bind該函數的時候將this指針一同傳入(也就是傳入一個實例化的類對象就可以了)
class myclass
{
public:
double add(double x, double y)
{
return x + y;
}
};
void test2()
{
myclass my;
//傳入my的作用在於傳入隱含的this指針
function<double(double,double)> func1 = bind(&myclass::add, my, 2, 3);
cout << func1(1,2) << endl;
}
struct myStruct
{
double a, b;
double add()
{
return a + b;
}
};
//需要注意,func() 與 function<> 裏面的參數個數,類型必須相同的,不能因爲綁定了就少寫
void test3(){
myStruct my{1,2};
//func1調用成員函數add
function<double()> func1 = bind(&myStruct::add, my);
cout << func1() << endl;
//此時的this指針是通過轉遞的方式, 而不是通過綁定的方式,反正只要傳入this指針就行了,func2調用成員函數add
function<double(myStruct)> func2 = bind(&myStruct::add, placeholders::_1);
cout << func2(my) << endl;
//輸出myStruct中的a, func3調用成員變量a
function<double(myStruct)> func3 = bind(&myStruct::a, my);
cout << func3(my) << endl;
}
3. cref,ref與bind結合使用
ref可以理解爲傳入引用
cref 則是const reference
void f(int& n1, int& n2, const int& n3)
{
std::cout << "In function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
++n1; // increments the copy of n1 stored in the function object
++n2; // increments the main()'s n2
// ++n3; // compile error
}
void test4()
{
int n1 = 1, n2 = 2, n3 = 3;
std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3));
n1 = 10;
n2 = 11;
n3 = 12;
std::cout << "Before function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
bound_f();
std::cout << "After function: " << n1 << ' ' << n2 << ' ' << n3 << '\n';
}
二.沒有繼承關係的情況下使用bind實現多態
Figure, Rectangle Circle 沒有繼承關係的類 實現多態
利用 bind 回調函數, Figure基類中註冊回調函數,實現多態時再進行調用就可以了,本質上是屬於bind註冊回調函數。
#include <iostream>
#include <functional>
#include <vector>
#include <iterator>
#include <algorithm>
#include <unordered_map>
#include <functional>
#define pi 3.1415926
using namespace std;
typedef function<void()> figureCallBack;
typedef function<double()> areaCallBack;
class Figure
{
public:
void setfigureFunc(figureCallBack cb1)
{
_cb1 = cb1;//註冊回調函數
}
void setareaFunc(areaCallBack cb2)
{
_cb2 = cb2;//註冊回調函數
}
void displayFigure()
{
_cb1();
}
double displayArea()
{
_cb2();
}
private:
figureCallBack _cb1;
areaCallBack _cb2;
};
class Rectangle
{
public:
Rectangle(int width, int length)
: _width(width), _length(length)
{
}
void displayFigure()
{
cout << "Rectangle" << endl;
}
double displayArea()
{
return _width * _length;
}
private:
int _width;
int _length;
};
class Circle{
public:
Circle(double radius)
:_radius(radius)
{
}
void displayFigure(){
cout << "Circle" << endl;
}
double displayArea(){
return pi * _radius * _radius;
}
private:
double _radius;
};
void display(Figure &f)
{
f.displayFigure();
cout << "Area = " << f.displayArea() << endl;
}
int main()
{
Rectangle rectangle(3, 4);
Circle circle(2);
Figure f;
//矩形
figureCallBack fn1 = bind(&Rectangle::displayFigure, &rectangle);
areaCallBack fn2 = bind(&Rectangle::displayArea, &rectangle);
f.setfigureFunc(fn1);
f.setareaFunc(fn2);
display(f);
//圓形
fn1 = bind(&Circle::displayFigure, circle);
fn2 = bind(&Circle::displayArea, circle);
f.setfigureFunc(fn1);
f.setareaFunc(fn2);
display(f);
return 0;
}
三.mem_fn函數 將成員函數轉換爲函數對象
struct MyStruct
{
int val;
void print()
{
cout << "this is print" << endl;
}
void printval(int i)
{
cout << "this is printval " << i << endl;
}
};
void test1()
{
MyStruct my{10};
auto func1 = mem_fn(&MyStruct::print);
func1(my); //傳入my是因爲必須傳入this指針
auto func2 = mem_fn(&MyStruct::printval);
func2(my, 2);
auto func3 = mem_fn(&MyStruct::val);
cout << func3(my) << endl;
}
class Data{
public:
Data(int data)
:_data(data)
{
}
void display(){
cout << _data << endl;
}
private:
int _data;
};
void test2(){
vector<Data> vec{Data(1), Data(2), Data(3)};
for_each(vec.begin(), vec.end(), mem_fn(&Data::display));//因爲本身就是在Data類的內部,所以不再需要傳入this指針
}
四.bind結合算法
使用算法與函數結合的方法總結:
void display(int i)
{
cout << i << endl;
}
struct Mydisplay{
void display(int i ){
cout << i << endl;
}
bool operator()(int i){
cout << i << endl;
return true;
}
};
void test3()
{
vector<int> vec{1, 2, 3, 4, 5};
//1.使用Lambda表達式
// for_each(vec.begin(), vec.end(), [](int x){cout << x << endl;});
//2.使用普通函數
//for_each(vec.begin(), vec.end(), display);
//3.bind綁定普通函數
// for_each(vec.begin(), vec.end(), bind(display, 1));
//4.bind綁定類成員函數
// Mydisplay my;
// for_each(vec.begin(), vec.end(), bind(&Mydisplay::display, my, placeholders::_1));
//5.使用函數對象
// for_each(vec.begin(), vec.end(), Mydisplay());
}
五.function+bind綜合程序
#include <functional>
#include <iostream>
struct Foo
{
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_ + i << '\n'; }
int num_;
};
void print_num(int i)
{
std::cout << i << '\n';
}
struct PrintNum
{
void operator()(int i) const
{
std::cout << i << '\n';
}
};
int main()
{
// store a free function
std::function<void(int)> f_display = print_num;
f_display(-9);
// store a call to a member function
std::function<void(const Foo &, int)> f_add_display = &Foo::print_add;
const Foo foo(314159);
f_add_display(foo, 1);
// store a call to a function object
std::function<void(int)> f_display_obj = PrintNum();
f_display_obj(18);
// store the result of a call to std::bind
std::function<void()> f_display_31337 = std::bind(print_num, 31337);
f_display_31337();
// store a call to a member function and object
using std::placeholders::_1;
std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
f_add_display2(2);
// store a call to a member function and object ptr
std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
f_add_display3(3);
}