從for_each開始提及 回調函數與仿函數

#include <iostream>
#include <algorithm>
using namespace std;
//回調函數
void call_back(char elem)
{
 cout << elem << endl;
}
//仿函數
struct Functor
{
 void operator() (char elem) 
 {
  cout << elem << endl;
 } 
};
int main()
{
 string strA = "hello";
 string strB = "world";
 
 for_each(strA.begin(),strA.end(),Functor());
 cout<<"===========GAP==============="<<endl;
 for_each(strB.begin(),strB.end(),call_back);
 getchar();
 return 0;
}

h
e
l
l
o
===========GAP===============
w
o
r
l
dios

可能會有疑問二者有什麼區別?shell

假如我要for_each遍歷的不是字符串而是int類型的vector呢?函數

是否是又要重寫一個int類型做爲參數的回調函數,那若是有N種類型的容器遍歷豈不是要寫N個回調函數或N個仿函數類?this

非也!!!spa

C++有類模板 也有 函數模板 一樣能夠用於回調code

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
//模板函數
template<typename T>
void call_back(T elem)
{ 
 cout<< elem <<endl;
}
//仿函數
template<typename T>
class Functor
{
public:
 Functor()
  :m_val(0)
 {
  cout<< "Functor()" <<endl;
 }
 ~Functor()
 {
  cout<<"~Functor()"<<endl;
 }
 void operator() (T elem) 
 {
  Do(elem);
 }
 
 //舉個栗子
 void Do(T elem)
 {
  m_val+=elem;
  cout<<elem<<"/"<<m_val<<endl;
 }
private:
 T m_val;
};
 
int main()
{
 vector<int> vec;
 vec.push_back(1);
 vec.push_back(2);
 vec.push_back(3);
 vec.push_back(4);
 vec.push_back(5);
 for_each(vec.begin(),vec.end(),call_back<int>);
 cout<<"===========GAP==============="<<endl; 
 for_each(vec.begin(),vec.end(),Functor<int>());
 return 0;
}

1
2
3
4
5
===========GAP===============
Functor()
1/1
2/3
3/6
4/10
5/15
~Functor()
~Functor()
~Functor()orm

 

三次析構的緣由:對象

先附上for_each的源碼(VC2008)繼承

template<class _InIt,class _Fn1>
inline _Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)
{ // perform function for each element
 _DEBUG_RANGE(_First, _Last);
 _DEBUG_POINTER(_Func);
 _CHECKED_BASE_TYPE(_InIt) _ChkFirst(_CHECKED_BASE(_First));
 _CHECKED_BASE_TYPE(_InIt) _ChkLast(_CHECKED_BASE(_Last));
 for (; _ChkFirst != _ChkLast; ++_ChkFirst)
  _Func(*_ChkFirst);
 return (_Func);
}
Functor<int>() 產生臨時對象傳參(值) 構造一次,析構一次 
for_each參數值傳遞,拷貝構造一次,析構一次(函數內部)
for_each返回仿函數的對象(值),拷貝構造一次,析構一次
由於沒有重載拷貝構造函數 因此打印出第一次建立臨時對象時的普通構造函數
實際上在這個過程當中一共產生過三個仿函數對象

 

若是把代碼改變下:element

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

template<typename T>
class Functor
{
public:
 Functor()
  :m_val(0)
 {
  cout<< "Functor()"<<this<<endl;
 }
 Functor(Functor& that)
 {
  this->m_val = that.m_val;
  cout<< "Copy Functor()" <<this<<endl;
 }
 ~Functor()
 {
  cout<<"~Functor()"<<this<<endl;
 }
 void operator() (T elem) 
 {
  Do(elem);
 }
 
 //舉個栗子
 void Do(T elem)
 {
  m_val+=elem;
  cout<<elem<<"/"<<m_val<<endl;
 }
 T getVal()
 {
  return m_val;
 }
private:
 T m_val;
};
 
int main()
{
 vector<int> vec;
 vec.push_back(1);
 vec.push_back(2);
 vec.push_back(3);
 vec.push_back(4);
 vec.push_back(5);

 Functor<int> func;
 Functor<int>& ref = for_each(vec.begin(),vec.end(),func);
 cout<<ref.getVal()<<endl;
 
 return 0;
}

運行結果

Functor()0032F800           //main函數中的實參仿函數對象
Copy Functor()0032F68C  //值傳遞 對【實參對象】拷貝構造了形參對象

1/1
2/3
3/6
4/10
5/15
Copy Functor()0032F7E8 //返回對象的值類型  對【形參對象】拷貝構造

~Functor()0032F68C       //析構形參對象
15
~Functor()0032F7E8       //析構返回值對象
~Functor()0032F800      //析構實參對象

如今一目瞭然了吧!

 

 我的認爲使用回調函數高效 由上面的例子能夠看出 構造1次 拷貝構造2次 析構3次  是有代價的

 

最後回到仿函數和回調函數

區別在於:

  1. 使用仿函數能夠聲明在業務相關的類內部 縮小做用域

  2. 使用仿函數能夠使用類的成員屬性和成員函數

  3. 仿函數是一個 能夠使用面向對象的各類機制(封裝 繼承 多態)

  4. 若使用回調函數 那麼只能聲明爲某個類的靜態成員函數或全局函數,使用類內部的資源須要用一些手段傳參,沒有直接使用成員函數便捷

相關文章
相關標籤/搜索