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;
}
沒有留言:
張貼留言