1.指標指到函式(函式指標) (Pointers to Functions)
2.指標指到物件的成員函式 (Pointer to Member Function)
3.指標指到物件的資料成員 (Pointer to Data Member)
4.指標指到 Class 的 Static Member
※函式指標 (Function Pointer)
C 語言指標可以指到一個變數的記憶體位址。
而 function block 也占有記憶體空間,因此指標也可以指到函式的記憶體位址,
指到函式記憶體位址的指標,稱為函式指標(function pointer)。
函式指標的宣告與呼叫執行
函式指標的宣告,需注意
1.與函式的回傳型態相同
2.與函式的參數數量、參數型態相同
宣告格式:
函式回傳型態 (*指標名稱) (參數1型態, 參數2型態, ...)調用格式:(使用函式指標呼叫執行函式)
指標名稱 (參數1, 參數2, ...) // 也可以寫成 (*指標名稱) (參數1, 參數2, ...)
註:
1.當函式名稱之後沒有緊跟著呼叫運算子"()",則函式名稱可視為指標。
2.取址運算子"&",作用在函式名稱上時,得到的也是相同的指標,所以 fn 和 &fn 是一樣的。
範例:
#include <iostream> using namespace std; int fn1(char x, int y){ //... return 0; } int fn2(double x){ //... return 0; } int main() { // 函式指標宣告 int (*fptr) (char, int); // fptr 宣告為 Function Pointer // 設定 fptr 指向 fn1 函式的記憶體位址 fptr = fn1; // OK // fptr = fn2; // Error! 參數個數、型態不同 fptr('a', 3); // 呼叫執行 (*fptr)('a', 3); // 呼叫執行 也可以這樣寫 return 0; }
函式指標的用處
方便在程式執行階段,根據不同狀況,執行不同的函數。
範例:
#include <iostream> using namespace std; int add(int x, int y){ return x + y; } int sub(int x, int y){ return x - y; } int main() { int (*fptr) (int, int); fptr = NULL; // 根據不同狀況,選擇使用 add 或 sub 函式 char r = '+'; switch(r){ case '+': fptr = add; break; case '-': fptr = sub; break; } cout << fptr(3, 2) << endl; // 執行結果:5 return 0; }
在陣列中存放函式指標
將函數指標的宣告當做陣列的型別,此陣列即可存放函式指標。
#include <iostream> using namespace std; int add(int x, int y){ return x + y; } int sub(int x, int y){ return x - y; } int main() { typedef int (*fptr) (int, int); // 之後索引用來存放ASCII字元,ASCII有128個字元,128個元素都初始化為 NULL fptr fptrAry[128] = {NULL}; // 上一行也可直接寫成 int (*fptrAry[128]) (int x, int y) = {NULL}; fptrAry['+'] = add; fptrAry['-'] = sub; cout << fptrAry['+'](3, 2) << endl; // 5 cout << fptrAry['-'](3, 2) << endl; // 1 return 0; }
函數指標的比較
函數指標也可以用比較運算子,來判斷是否相等。
範例:
#include <iostream> using namespace std; int add(int x, int y){ return x + y; } int main() { int (*fptr) (int, int); fptr = add; if(fptr == add){ // 相等 }else{ // 不相等 } return 0; }
函數指標之間的轉型
函數指標可以轉型成其他型別的函數指標
範例:
#include <iostream> using namespace std; int fn1(int x, int y){ return x + y; } int fn2(int x){ return x; } int main() { typedef int (*fptr1) (int, int); fptr1 p1= fn1; typedef int (*fptr2) (int); // 將 p1 轉型為 fptr2 fptr2 p1Tmp1 = (fptr2) p1; // 再轉回 fptr1 fptr1 p1Tmp2 = (fptr1) p1Tmp1; // cout << p1Tmp1(1) << endl; // 錯誤,得到無法預期的結果 // 轉回原來的型別後,會跟之前的結果一樣 cout << p1Tmp2(1,2) << endl; // 3 return 0; }
※指標指到物件的成員函式 (Pointer to Member Function)
指標要指到物件的 member function 時,宣告和調用時,都跟指到一般的 function 不太一樣。
宣告格式:
函式回傳型態 (類別名稱::*指標名稱) (參數1型態, 參數2型態, ...)宣告時,必須標明屬於哪一個類別。
調用格式:
(物件實例.*指標名稱) (參數1, 參數2, ...)調用時,要經由物件實例來調用。
範例:
#include <iostream> using namespace std; class Test{ public: int mm(int x, int y) { return x + y; } // member function 不是放在個別 object 的空間, // 而是所有同類別物件共享同一個 member function }; int main() { Test t; int (Test::*p)(int,int); // p 是成員函式指標 p = &Test::mm; // 將 p 指到 Test 類別的 mm() 函式 /* 也可用 typedef 改寫成 typedef int (Test::*MyPtr)(int, int); MyPtr p = &Test::mm; */ cout << (t.*p)(2,3)<< endl; // 5 return 0; }
※指標指到物件的資料成員函式 (Pointer to Data Member)
宣告格式:
型態 類別名稱::*指標名稱宣告時,必須標明屬於哪一個類別。
調用格式:
物件實例.*指標名稱調用時,要經由物件實例來調用。
範例:
#include <iostream> using namespace std; class Test{ public: int a; }; int main() { int Test::*p = &Test::a; /* 也可用 typedef 改寫成 typedef int Test::*MyPtr; MyPtr p = &Test::a; */ Test t1; // 要先有實體物件,才能調用 t1.*p = 10; Test t2; // 要先有實體物件,才能調用 t2.*p = 20; cout << t1.*p << endl; // 10 cout << t2.*p << endl; // 20 return 0; }
※指標指到 Class 的 Static Member
指標指到類別裡面靜態成員時,用法跟一般變數指標、一般函數指標一樣。
範例:
#include <iostream> using namespace std; class Test{ public: static int a; static int mm() { return a; } }; int Test::a = 10; int main() { // 跟使用一般變數指標一樣 int * ptr; ptr = &Test::a; *ptr = 20; cout << Test::a << endl; // 20 // 跟使用一般函式指標一樣 int (*fptr)(); fptr = &Test::mm; cout << Test::mm() << endl; // 20 return 0; }
沒有留言:
張貼留言