boost::function用法

来源:互联网 发布:网络语音肝是啥意思 编辑:程序博客网 时间:2024/05/18 23:15

1.回调基础

对于回调,目前c++支持的有回调函数,函数对象,lambda函数三种方式。

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。对于函数对象和lambda函数也是类似的使用方法。

一个排序的函数可以这样定义:

template <typename T>
void sort(int a[], int n, T fun)
{
...
fun(a, b);
...
}


函数指针:

typedef bool(*compare_ptr)(int a, int b);
bool compare(int a, int b)
{
return a > b;
}

调用时sort(a, 10, compare);


函数对象:重载其()操作符

class Compare
{
bool operator ()(int a, int b)
{
return a > b;
}

};

使用方法可以为sort(a, 10, Compare()),使用时将产生一个临时的对象。


lambda函数:

这样使用sort: sort(a, 10, [](int a, int b){return a >b;})


2.boost function 统一三种回调方式

上面的模板函数sort已经统一了三者的调用,但是表现的很不直观。

boost function也是一个模板类,用这个类的对象来封装上述三者,达到回调统一的效果。

定义一个boost::function的对象:

typedef boost::function<bool(int, int)> COMPARE_FUN;

COMPARE_FUN boost_fun;

其定义方式可以看出这是一个类模板,<返回值(参数1,参数2,...)>

我们可以这样使用:

排序函数的定义为 void sort(int a[], int n,COMPARE_FUN  fun);

可以将函数指针,函数对象,lambda函数赋值给boost::function

函数指针:boost_fun = compare;

函数对象:boost_fun  = Compare();

lambda函数:boost_fun = [](int a, int b)(return a > b);


3.函数对象拷贝

boost::funtion的强大作用有一点是于对类和对象的操作

boost::function在绑定函数对象时,其实是对每一个对象都进行了一次拷贝

也就是boost::function会拥有一个单独的函数对象,看下面这个例子

class FunObject
{
int m_total;
public:
FunObject():m_total(0)
{
}

int operator()(int addition)
{
m_total += addition;
return m_total;
}

void print_me()
{
std::cout << m_total << std::endl;
}
};


int main()
{
FunObject ob;
ob.print_me();

boost::function<int(int)> fun_1;
fun_1 = ob;
std::cout << fun_1(100)<< std::endl;
ob.print_me();


boost::function<int(int)> fun_2;
fun_2 = ob;
std::cout << fun_2(100) << std::endl;
ob.print_me();
}

结果是:

0

100

0

100

0

boost::function并没有对原来的对象产生改变,因为它拷贝了一份对象。

boost::ref用来让boost::function对象持有原来的引用:fun = boost::ref(ob);


4.类的成员函数

对于类的成员函数,boost也提供了相关的类模板进行处理。

其实,对于c++成员函数,也只是隐藏了this指针的C函数,不难想到,这一块的类模板第一个参数必须是类的对象,引用或者指针。

boost::function<void(FunObject&)> fun_1;
boost::function<void(FunObject*)> fun_2;

fun_1 = &FunObject::print_me;
fun_2 = &FunObject::print_me;

FunObject ob;
fun_1(ob);
fun_2(&ob);


5.boost::bind

boost::bind返回一个boost::function对象,function与bind的配合使用,能设计出扩展性很强的程序模块。

看下面这个例子:

class A
{
int m_a;
int m_b;
public:
A():m_a(1), m_b(2){}


void add(int a, int b)
{
m_a += a;
m_b += b;
std::cout << m_a << std::endl;
std::cout << m_b << std::endl;
}
};


int main()
{
A ob;
boost::function<void(int a, int b)> fun = boost::bind(&A::add, &ob, _1, _2);
fun(10, 20);
}

boost::bind绑定成员函数,第一个参数是函数的地址,后面的参数按照顺序为函数的参数。_1,_2是相关的宏,表示调用时使用的参数的顺序,fun(10,20) 10是_1位置的参数, 20是_2位置的参数。

比如可以这样写:

A ob;
boost::function<void(A*, int a, int b)> fun = boost::bind(&A::add,  _1, _2, _3);
那么调用的时候得fun(&ob, 10, 20);

也可以这样:

A ob;
boost::function<void(A*, int a, int b)> fun = boost::bind(&A::add,  _1, _2, 20);
那么调用的时候得fun(&ob, 10);

有没有觉得很神奇,如果是这样的申明add(int a, int b, int c)

还可以这样写:

A ob;
boost::function<void(int a, int b)> fun = boost::bind(&A::add, &ob, _1, _2, 30);
fun(10, 20);

boost::function与bind的结合,可以帮助我们使用自己想要的参数,不局限于定义好的函数申明。


小结

1.boost::function可以实现回调方式的统一,bing可以控制自定义参数,可以方便设计出易于扩展的程序。

2.存在额外消耗,对于所有的回调都组织成了一个function对象,同时function对象里还存在着一些拷贝,特别是函数对象的拷贝。


0 0
原创粉丝点击