2010年3月23日 星期二

function pointer in C++ to boost::function

Effective c++ item 35 舉了一個有趣的例子GameCharacter,

主要的精神在於利用function pointer把真正計算血量的部份,交給專門計算血量的function。達到像Strategy pattern可以隨時抽換實作內容的目的。

一開始看到後面boost時沒什麼fu,主要的原因在於自己對原本c++要怎麼delegate function的實作方式不熟,所以當後面進階的boost::function跟boost::bind的觀念導入後,心中只剩OS:這哪裡方便了?一點都不蝦阿~為了不模糊焦點,我們先不管pattern怎麼用,直接看看function pointer in standard C++的技巧。




typedef of function pointer

基本的function pointer作法

void Test(int iParam)
{
   cout << "Test Invoked\r\n";
}
Typedef void (*ptrFunction)(int)
ptrFunction pFun = Test;
pFun(3);  // call test 
// output Test Invoked
Delegate in Standard C++
寫成class 方便日後使用
class NonTypeDelegate : public Delegate  
{
public:
   void Invoke();
   NonTypeDelegate(void (*pfn)(int),int iParam);
   virtual ~NonTypeDelegate(){}
private:
   void (*m_pfn)(int);
   int m_iParam;
};
///////////NonTypeDelegate.cpp
void NonTypeDelegate::Invoke()
{
   cout << "NonTypeDelegate Invoke\r\n";
   m_pfn(m_iParam);
}

把function pointer 跟準備傳的參數存在NonTypeDelegate 裡透過Invoke呼叫。
NonTypeDelegate nTDelegate(Test,1);
nTDelegate.Invoke();  // output Test Invoked
How about class member function?
對某些人來說Global function 跟typedef很醜,還有如果今天目標是class member function怎麼辦?(這也是比較常見的狀況),有一個class A 要把自己的member function提供出去等別人callback(ex:檔案下載的進度)。
class A
{
 public:
    void Test(int iParam)
    {
       cout << "A::Test Invoked\r\n";
    }
};

我們來看看加強版加入Template的class怎麼用(越來越像boost的用法)
template < typename T>

class TypeDelegate : public Delegate
{
public:
   void Invoke();
   TypeDelegate(T &t, void (T::*pfn)(int), int iParam);
   ~TypeDelegate(){}

private:
   T m_t;
   void (T::*m_pfn)(int);
   int m_iParam;
};

template < typename T >
TypeDelegate < T > ::TypeDelegate(T &t,
                              void (T::*pfn)(int),
                              int iParam):m_t(t),
                              m_pfn(pfn),
                              m_iParam(iParam)
{
}

template < typename T >

void TypeDelegate < T > ::Invoke()
{
   cout < < "TypeDelegate Invoke\r\n";
   (m_t.*m_pfn)(m_iParam);
}

所以在main我們可以這樣用它
A a;
TypeDelegate < A > tDelegate(a,&A::Test,2);
//指定一個a 的物件與下面的member function其input的參數是2
tDelegate.Invoke();  // call A::Test function
到這邊這個形式已經很像boost::function了,boost是這樣用的。
boost::function < void(int) > f1 ;
f1 = boost::bind(&A::Test, &a, _1);
而boost還保留了傳遞參數的自由(也可以把_1改成自己想要固定的int)
f1(3);
f1(4);
f1(5);
這是我目前對boost::function的理解。
題外話  如果有興趣要玩玩看的人 這段code是在Code::Blocks上開發的 vc2005 compiler到boost::bind會crash
Reference
Function Pointers in C/C++ and boost::bind
Delegate in Standard C++

沒有留言:

張貼留言