Fork me on GitHub

9/26/2010

[C++] 利用函數指標(funtion pointer)實現委派機制(delegate)

這篇文章記錄一下函數指標如何使用 以及 在委派機制上的實現方式。

所謂函數指標,顧名思義就是一個指向函數的指標,看起來他的用途似乎像是要把函數拿來傳遞用,也就是說可以把一個函數指標當做參數丟進另一個函數。

如下程式碼所示,有一個輸出 bool,輸入 int 的函式叫做 action,如果我們希望將他傳遞到 test 當中,然後再由 test 決定該 action 的輸入參數,這時候函數指標就派上用場了!

#include <iostream>
using namespace std;

bool action(int i) {
    cout << "action: " << i << endl;
    return 0;
}

// define pFun is a function pointer of (out: bool in: int)
typedef bool (*pFun)(int); 

void test(pFun p1, int i) {
    (*p1)(i);
}

int main() { 
    test(&action, 1);
    return 0;
}

除此之外由於 C++ 沒有所謂的委派,而函數指標另外一個最大的功用就拿來實現委派。當有兩個物件彼此之間需要溝通 (例:A 物件的某個 A-1 方法需要觀察 B 物件的 B-1 欄位來決定其行為),這時候就可以幫 B 物件建立一個委派,這個委派不斷的觀察 B 物件的狀態,然後告訴 A 物件要做怎樣的行動。

如下程式碼,有一個 Subject 物件和 Observer 物件,當 Subject 物件當中的 somethingHappen 方法啟動的時候 (可以把它想做一個事件),就會引發 Observer 物件當中的 action 函式!

#include <iostream>
using namespace std;

class Observer {
public:
 
 bool action(int p);
 
};

bool Observer::action(int p) {
 
 std::cout << "print by member function pointer" << std::endl;
 
 return true;
}

class Subject {
 
public:
 
 bool (Observer::*memberFunPtr)(int); // member function pointer
 Observer* m_observer;
 
 void attach (Observer* observer);
 void somethingHappen();
 
 
};

void Subject::attach (Observer* observer) {
 m_observer = observer;
 memberFunPtr = &Observer::action;
}

void Subject::somethingHappen() {
 ((m_observer)->*(memberFunPtr))(1);
}


int main() 
{ 
 Subject mySubject;
 Observer myObserver;
 
 mySubject.attach(&myObserver);
 
 mySubject.somethingHappen();
 
    return 0; 
} 

截至目前為止我對於 Delegate 的理解大概是,他不是什麼特別的語法,只是一種概念。沒有這種機制的話,兩個物件彼此間要溝通,或是互相修改彼此的成員變數,會利用 composition 的方式實現 (也就是在A物件當中包含有B物件,B物件當中包含有A物件)。

透過函數指標,可以降低物件之間的耦合程度,例:原本你想用 B 物件的 B-1 方法修改 A 物件的 private 成員 A-1,那麼勢必要將 A 物件傳入 B-1 方法,甚至還要將 A-1 成員改成 public 才有辦法讓 B-1 存取;如果使用委派,則可以設定一個 A-2 方法取代 B-1 方法,並將 A-2 方法以函數指標傳進 B-1 方法當中 (連帶要將 A 物件的參考傳進去),需要的時候在由 B-1 引發 A-2 函數,也不需要修改 A-1 成員的屬性。

其實我也還不是很懂,或許未來實作上有遇到在來補充一下好了!參考資料有許多精闢的使用範例,搭配泛型甚至可以做到和 C# 當中 Delegate 一樣的效果!

參考資料:
- 函式指標的用途
- What are the advantages of delegates?
- Member Function Pointers and the Fastest Possible C++ Delegates
- Generic Observer Pattern and Events in C++
- Passing member function pointer to member object in c++

......

No comments:

Post a Comment