C++ -函式指標 (function pointer)
1. 普通的函式指標
函式指標 function pointer,是一個指標,指向某「特定函式型別」,函式型別由其「返回型別和參數列」決定,函式名稱並非型別的一部分。
宣告 pf 是一個函式指標,指向一個「回傳 int 且接收 2 個 int」的函式
int (*pf)(int a, int b);
這是型別,就像 int 一樣,是個型別,很笨重又不易使用,所以通常會用 typedef 定義其同義字。
typedef int (*numHandle)(int a, int b);
numHandle 是一個「函式指標的型別名稱」,該型別是個指標,指標所指的函式會「回傳 int 且接收 2 個 int」。一旦需要使用這個型別,可以寫 numHandle 而不需每次寫出完整的型別定義。
當單純使用函式名稱而不進行呼叫時,這名稱自動被視為一個函式指標。
int HandleBig(int a, int b);
任何對 HandleBig 的使用,都會被視為一個「指標」。型別是:
int (*)(int a, int b);
範例:main.cpp
#include <iostream>
using namespace std;
typedef int (*numHandle)(int a, int b);
int HandleBig(int a, int b);
int HandleSmall(int a, int b);
int HandleNum(int a, int b, numHandle handleFun);
int main()
{
numHandle pf1 = 0;
numHandle pf2 = HandleBig;
pf1 = pf2;
numHandle pf3 = &HandleBig;
//使用函式指標呼叫函式
cout<<pf2(3, 4)<<endl;
cout<<(*pf3)(3, 1)<<endl;
//把函式指標當參數傳遞
cout<<HandleNum(4, 9, pf3)<<endl;
cout<<HandleNum(4, 9, HandleSmall)<<endl;
system("pause");
return 0;
}
int HandleNum(int a, int b, numHandle handleFun)
{
return (*handleFun)(a, b);
}
int HandleBig(int a, int b)
{
if(a > b)
return a;
return b;
}
int HandleSmall(int a, int b)
{
if(a < b)
return a;
return b;
}
2. 類別(class)裡的函式指標
直接使用範例
numberhandle.h
class CNumberHandle;
typedef int (CNumberHandle::*NUMHANDLE)(int a, int b);
class CNumberHandle
{
private:
NUMHANDLE m_pfNumHandleRule[30];
int HandleBig(int a, int b);
int HandleSmall(int a, int b);
public:
CNumberHandle();
int Handle(int a, int b, int nRule);
};
numberhandle.cpp
#include "numberhandle.h"
CNumberHandle::CNumberHandle()
{
for(int i = 0 ; i < 30 ; i++)
m_pfNumHandleRule[i] = 0;
m_pfNumHandleRule[0] = &CNumberHandle::HandleBig;
m_pfNumHandleRule[1] = &CNumberHandle::HandleSmall;
}
int CNumberHandle::Handle(int a, int b, int nRule)
{
return (this->*m_pfNumHandleRule[nRule])(a, b);
}
int CNumberHandle::HandleBig(int a, int b)
{
if(a > b)
return a;
return b;
}
int CNumberHandle::HandleSmall(int a, int b)
{
if(a < b)
return a;
return b;
}
main.cpp
#include <iostream>
#include "numberhandle.h"
using namespace std;
int main()
{
CNumberHandle* pNumHandle = new CNumberHandle;
cout << pNumHandle->Handle(3, 4, 0) << endl;
cout << pNumHandle->Handle(3, 4, 1) << endl;
delete pNumHandle;
system("pause");
return 0;
}
函式指標的致命缺點是:無法對參數和回傳值的型態進行檢查。
因為函數已經退化成指標,指標是不帶有這些型態資訊的。少了型態檢查,當參數或返回值不一致時,會造成嚴重的錯誤。編譯器和虛擬機器並不會幫我們找出函式指標這樣的致命錯誤。所以,許多新的程式語言不支援函數指標,而改用其他方式。
參考資料
http://caterpillar.onlyfun.net/Gossip/CppGossip/FunctionPointer.html
http://caterpillar.onlyfun.net/Gossip/CppGossip/MemberFunctionPtr.html