boost::function用法

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對象裏還存在着一些拷貝,特別是函數對象的拷貝。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章