所謂函數指標,顧名思義就是一個指向函數的指標,看起來他的用途似乎像是要把函數拿來傳遞用,也就是說可以把一個函數指標當做參數丟進另一個函數。
如下程式碼所示,有一個輸出 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