定義使用函式指標
阿新 • • 發佈:2019-01-24
且不論語法,有兩種不同形式的指標函式: 一個是指向普通的C函式的指標和C++的靜態成員函式,另外一個是指向C++的非靜態成員函式的指標。這兩者的基本區別是所有指向非靜態成員函式的指標都 需要這個隱含定義:指向本類的一個This指標。注意:這兩種函式指標彼此不相容。
既然一個函式指標實際上和一個變數沒有什麼區別,定義它的時候也就沒有什麼特殊。下面的例子中我們定義3個函式指標,名字是pt2Function, pt2Member 和 pt2ConstMember.
它們指向的函式,輸入一個 float和兩個char 型別的變數並返回一個 int 型別的變數. 對於C++程式例子,我們的指標指向的的函式,是一個叫做 TMyClass 的 類的非靜態成員函式。
[1] = &TMyClass::DoIt;
funcArr1[1] = funcArr2[0] = &TMyClass::DoMore;
/* more assignments */
// calling a function using an index to address the member function pointer
// note: an instance of TMyClass is needed to call the member functions
TMyClass instance;
cout << (instance.*funcArr1[1])(12, 'a', 'b') << endl;
cout << (instance.*funcArr1[0])(12, 'a', 'b') << endl;
cout << (instance.*funcArr2[1])(34, 'a', 'b') << endl;
cout << (instance.*funcArr2[0])(89, 'a', 'b') << endl;
}
// 1 define a function pointer and initialize to NULL
int (*pt2Function)(float, char, char) = NULL; //
C
int (TMyClass::*pt2Member)(float, char, char) = NULL; //
C++
int (TMyClass::*pt2ConstMember)(float, char, char) const =
NULL; // C++
2 函式呼叫規範
通常你不需要考慮一個函式的呼叫規範:編譯器預設的使用__cdecl,如果你不特別指出用哪個的話。呼叫規範告訴編譯器如何傳 遞引數以及如何產生函式名。一些其他的呼叫規範可以舉例為:__stdcall, __pascal和__fastcall.
注意:使用不同調用規範的函式指標彼此不相容。
// 2 define the calling convention
void __cdecl DoIt(float a, char b, char c); //
Borland and Microsoft
void DoIt(float a, char b, char c) __attribute__((cdecl)); //
GNU GCC
3 為函式指標分派一個地址
將函式的地址分派給函式指標很容易,在函式名字之前冠以取址符&就可以了。
// 3 assign an address to the function pointer
// Note: Although you may ommit the address operator on most compilers
// you should always use the correct way in order to write portable code.
// C
int DoIt (float a, char b, char c){ printf("DoIt\n"); return a+b+c;
}
int DoMore(float a, char b, char c)const{ printf("DoMore\n"); return a-b+c;
}
pt2Function = DoIt; // short form
pt2Function = &DoMore; // correct assignment using address operator
// C++
class TMyClass
{
public:
int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<<
endl; return a+b+c;};
int DoMore(float a, char b, char c) const
{ cout << "TMyClass::DoMore" << endl; return a-b+c; };
/* more of TMyClass */
};
pt2ConstMember = &TMyClass::DoMore; // correct assignment using address operator
pt2Member = &TMyClass::DoIt; // note: <pt2Member> may also legally point to &DoMore
4 比較函式指標
你可以和通常方式一樣使用比較符號(==, !=)。下面的例子中我們檢查變數 pt2Function 和 pt2Member ,它們分別指向的函式 DoIt 和 TMyClass::DoMore.
如果指向正確就會輸出代表爭取的字串。
// 4 comparing function pointers
// C
if(pt2Function >0){ // check if initialized
if(pt2Function == &DoIt)
printf("Pointer points to DoIt\n"); }
else
printf("Pointer not initialized!!\n");
// C++
if(pt2ConstMember == &TMyClass::DoMore)
cout << "Pointer points to TMyClass::DoMore" << endl;
5 使用函式指標呼叫函式
在C語言中我們可以通過 * 符號來呼叫函式指標,也可以不使用函式名而代以函式指標的名字。C++使用兩個符號 * 和 ->* 來呼叫類的非靜態函式指標。如果呼叫在其他成員函式中發生,那麼就得加上this指標。
// 5 calling a function using a function pointer
int result1 = pt2Function (12, 'a', 'b'); //
C short way
int result2 = (*pt2Function) (12, 'a', 'b'); //
C
TMyClass instance1;
int result3 = (instance1.*pt2Member)(12, 'a', 'b'); //
C++
int result4 = (*this.*pt2Member)(12, 'a', 'b'); //
C++ if this-pointer can be used
TMyClass* instance2 = new TMyClass;
int result4 = (instance2->*pt2Member)(12, 'a', 'b'); //
C++, instance2 is a pointer
delete instance2;
6 如何像傳遞一個引數一樣傳遞函式指標
你可以在呼叫一個函式的時候把函式指標當作引數來傳遞。在回撥函式中尤其要使用到這個技術。下邊這個例子演示瞭如何把指標傳遞給一個函式,這個 函式使用一個 float 和兩個 char 型別的引數並有一個int型別的返回值。
//------------------------------------------------------------------------------------
// 6 How to Pass a Function Pointer
// <pt2Func> is a pointer to a function which returns an int and takes a float and two char
void PassPtr(int (*pt2Func)(float, char, char))
{
int result = (*pt2Func)(12, 'a', 'b'); //
call using function pointer
cout << result << endl;
}
// execute example code - 'DoIt' is a suitable function like defined above in 2.1-4
void Pass_A_Function_Pointer()
{
cout << endl << "Executing 'Pass_A_Function_Pointer'" << endl;
PassPtr(&DoIt);
}
7 如何返回一個函式指標
看上去有點怪,但是一個函式指標可以作為一個函式的返回值。下面的例子中提供了兩種把函式指標作為返回值的解決方案。這個函式輸入兩個float類 型的引數,返回一個float型別的值。
//------------------------------------------------------------------------------------
// 7 How to Return a Function Pointer
// 'Plus' and 'Minus' are defined above. They return a float and take two float
// Direct solution: Function takes a char and returns a pointer to a
// function which is taking two floats and returns a float. <opCode>
// specifies which function to return
float (*GetPtr1(const char opCode))(float, float)
{
if(opCode == '+')
return &Plus;
else
return &Minus; // default if invalid operator was passed
}
// Solution using a typedef: Define a pointer to a function which is taking
// two floats and returns a float
typedef float(*pt2Func)(float, float);
// Function takes a char and returns a function pointer which is defined
// with the typedef above. <opCode> specifies which function to return
pt2Func GetPtr2(const char opCode)
{
if(opCode == '+')
return &Plus;
else
return &Minus; // default if invalid operator was passed
}
// Execute example code
void Return_A_Function_Pointer()
{
cout << endl << "Executing 'Return_A_Function_Pointer'" << endl;
// define a function pointer and initialize it to NULL
float (*pt2Function)(float, float) = NULL;
pt2Function=GetPtr1('+'); // get function pointer from function 'GetPtr1'
cout << (*pt2Function)(2, 4) << endl; // call function using
the pointer
pt2Function=GetPtr2('-'); // get function pointer from function 'GetPtr2'
cout << (*pt2Function)(2, 4) << endl; // call function using
the pointer
}
8 如何使用函式指標陣列
使用函式指標陣列非常有意思,這個技術提供了一種從索引中選擇函式的方法。實現的語法看上去很複雜,經常導致理解錯誤。下面的例子中我們可以看 到兩種定義和使用函式指標陣列的方法。前一種使用 typedef ,後一種直接定義陣列。使用哪一種全憑你的興趣。
//------------------------------------------------------------------------------------
// 8 How to Use Arrays of Function Pointers
// C ---------------------------------------------------------------------------------
// type-definition: 'pt2Function' now can be used as type
typedef int (*pt2Function)(float, char, char);
// illustrate how to work with an array of function pointers
void Array_Of_Function_Pointers()
{
printf("\nExecuting 'Array_Of_Function_Pointers'\n");
// define arrays and ini each element to NULL, <funcArr1> and <funcArr2> are arrays
// with 10 pointers to functions which return an int and take a float and two char
// first way using the typedef
pt2Function funcArr1[10] = {NULL};
// 2nd way directly defining the array
int (*funcArr2[10])(float, char, char)
= {NULL};
// assign the function's address - 'DoIt' and 'DoMore' are suitable functions
// like defined above in 1-4
funcArr1[0] = funcArr2[1] = &DoIt;
funcArr1[1] = funcArr2[0] = &DoMore;
/* more assignments */
// calling a function using an index to address the function pointer
printf("%d\n", funcArr1[1](12, 'a', 'b')); //
short form
printf("%d\n", (*funcArr1[0])(12, 'a', 'b')); //
"correct" way of calling
printf("%d\n", (*funcArr2[1])(56, 'a', 'b'));
printf("%d\n", (*funcArr2[0])(34, 'a', 'b'));
}
// C++ -------------------------------------------------------------------------------
// type-definition: 'pt2Member' now can be used as type
typedef int (TMyClass::*pt2Member)(float, char, char);
// illustrate how to work with an array of member function pointers
void Array_Of_Member_Function_Pointers()
{
cout << endl << "Executing 'Array_Of_Member_Function_Pointers'" << endl;
// define arrays and ini each element to NULL, <funcArr1> and <funcArr2> are
// arrays with 10 pointers to member functions which return an int and take
// a float and two char
// first way using the typedef
pt2Member funcArr1[10] = {NULL};
// 2nd way of directly defining the array
int (TMyClass::*funcArr2[10])(float, char, char)
= {NULL};
// assign the function's address - 'DoIt' and 'DoMore' are suitable member
// functions of class TMyClass like defined above in 2.1-4
funcArr1[0] = funcArr2nd use an array of function pointers in C and C++. The first way uses a typedef, the second way directly defines the array. It's up to you which way you prefer.
[1] = &TMyClass::DoIt;
funcArr1[1] = funcArr2[0] = &TMyClass::DoMore;
/* more assignments */
// calling a function using an index to address the member function pointer
// note: an instance of TMyClass is needed to call the member functions
TMyClass instance;
cout << (instance.*funcArr1[1])(12, 'a', 'b') << endl;
cout << (instance.*funcArr1[0])(12, 'a', 'b') << endl;
cout << (instance.*funcArr2[1])(34, 'a', 'b') << endl;
cout << (instance.*funcArr2[0])(89, 'a', 'b') << endl;
}