函數存放在記憶體的代碼地區內,它們同樣有地址,我們如何能獲得函數的地址呢?
如果我們有一個int test(int a)的函數,那麼,它的地址就是函數的名字,這一點如同數組一樣,數組的名字就是數組的起始地址。
定義一個指向函數的指標用如下的形式,以上面的test()為例:
int (*fp)(int a);//這裡就定義了一個指向函數的指標
函數指標不能絕對不能指向不同類型,或者是帶不同形參的函數,在定義函數指標的時候我們很容易犯如下的錯誤。
int *fp(int a);//這裡是錯誤的,因為按照結合性和優先順序來看就是先和()結合,然後變成了一個返回整形指標的函數了,而不是函數指標,這一點尤其需要注意!
下面我們來看一個具體的例子:
#include <iostream>
#include <string>
using namespace std;
int test(int a);
void main(int argc,char* argv[])
{
cout<<test<<endl;//顯示函數地址
int (*fp)(int a);
fp=test;//將函數test的地址賦給函數學指標fp
cout<<fp(5)<<"|"<<(*fp)(10)<<endl;
//上面的輸出fp(5),這是標準c++的寫法,(*fp)(10)這是相容c語言的標準寫法,兩種同意,但注意區分,避免寫的程式產生移植性問題!
cin.get();
}
int test(int a)
{
return a;
}
typedef定義可以簡化函數指標的定義,在定義一個的時候感覺不出來,但定義多了就知道方便了,上面的代碼改寫成如下的形式:
#include <iostream>
#include <string>
using namespace std;
int test(int a);
void main(int argc,char* argv[])
{
cout<<test<<endl;
typedef int (*fp)(int a);//注意,這裡不是生命函數指標,而是定義一個函數指標的類型,這個類型是自己定義的,類型名為fp
fp fpi;//這裡利用自己定義的類型名fp定義了一個fpi的函數指標!
fpi=test;
cout<<fpi(5)<<"|"<<(*fpi)(10)<<endl;
cin.get();
}
int test(int a)
{
return a;
}
函數指標同樣是可以作為參數傳遞給函數的,下面我們看個例子,仔細閱讀你將會發現它的用處,稍加推理可以很方便我們進行一些複雜的編程工作。
//-------------------該例以上一個例子作為基礎稍加了修改-----------------------------
#include <iostream>
#include <string>
using namespace std;
int test(int);
int test2(int (*ra)(int),int);
void main(int argc,char* argv[])
{
cout<<test<<endl;
typedef int (*fp)(int);
fp fpi;
fpi=test;//fpi賦予test 函數的記憶體位址
cout<<test2(fpi,1)<<endl;//這裡調用test2函數的時候,這裡把fpi所儲存的函數地址(test的函數地址)傳遞了給test2的第一個形參
cin.get();
}
int test(int a)
{
return a-1;
}
int test2(int (*ra)(int),int b)//這裡定義了一個名字為ra的函數指標
{
int c=ra(10)+b;//在調用之後,ra已經指向fpi所指向的函數地址即test函數
return c;
}
利用函數指標,我們可以構成指標數組,更明確點的說法是構成指向函數的指標數組,這麼說可能就容易理解的多了。
#include <iostream>
#include <string>
using namespace std;
void t1(){cout<<"test1";}
void t2(){cout<<"test2";}
void t3(){cout<<"test3";}
void main(int argc,char* argv[])
{
void* a[]={t1,t2,t3};
cout<<"比較t1()的記憶體位址和數組a[0]所儲存的地址是否一致"<<t1<<"|"<<a[0]<<endl;
cout<<a[0]();//錯誤!指標數組是不能利用數組下標操作調用函數的
typedef void (*fp)();//自訂一個函數指標類型
fp b[]={t1,t2,t3}; //利用自訂類型fp把b[]定義趁一個指向函數的指標數組
b[0]();//現在利用指向函數的指標數組進行下標操作就可以進行函數的間接調用了;
cin.get();
}
仔細看上面的例子可能不用我多說大家也會知道是怎麼一會事情了,最後我們做一個重點小結,只要記住這一點,對於理解利用函數指標構成數組進行函數間接調用就很容易了!
void* a[]={t1,t2,t3};
cout<<"比較t1()的記憶體位址和數組a[0]所儲存的地址是否一致"<<t1<<"|"<<a[0]<<endl;
cout<<a[0]();//錯誤!指標數組是不能利用數組下標操作調用函數的
上面的這一小段中的錯誤行,為什麼不能這麼調用呢?
前一篇教程我們已經說的很清楚了,不過在這裡我們還是複習一下概念,指標數組元素所儲存的只是一個記憶體位址,既然只是個記憶體位址就不可能進行a[0]()這樣地址帶括弧的操作,而函數指標不同它是一個例外,函數指標只所以這麼叫它就是因為它是指向函數指向記憶體的代碼區的指標,它被系統授予允許與()括弧操作的權利,進行間接的函數調用,既然函數指標允許這麼操作,那麼被定義成函數指標的數組就一定是可以一樣的操作的。
在C++類中使用函數指標。
//形式3:typedef 傳回型別(類名::*新類型)(參數表)
class CA
{
public:
char lcFun(int a){ return; }
};
CA ca;
typedef char (CA::*PTRFUN)(int);
PTRFUN pFun;
void main()
{
pFun = CA::lcFun;
ca.(*pFun)(2);
}
在這裡,指標的定義與使用都加上了“類限制”或“對象”,用來指明指標指向的函數是那個類的這裡的類對象也可以是使用new得到的。比如:
CA *pca = new CA;
pca->(*pFun)(2);
delete pca;
而且這個類對象指標可以是類內部成員變數,你甚至可以使用this指標。比如:
類CA有成員變數PTRFUN m_pfun;
void CA::lcFun2()
{
(this->*m_pFun)(2);
}
一句話,使用類成員函數指標必須有“->*”或“.*”的調用。