1. 程式人生 > >定義使用函式指標

定義使用函式指標

且不論語法,有兩種不同形式的指標函式: 一個是指向普通的C函式的指標和C++的靜態成員函式,另外一個是指向C++的非靜態成員函式的指標。這兩者的基本區別是所有指向非靜態成員函式的指標都 需要這個隱含定義:指向本類的一個This指標。注意:這兩種函式指標彼此不相容。 既然一個函式指標實際上和一個變數沒有什麼區別,定義它的時候也就沒有什麼特殊。下面的例子中我們定義3個函式指標,名字是pt2Functionpt2Member 和 pt2ConstMember. 它們指向的函式,輸入一個 float和兩個char 型別的變數並返回一個 int 型別的變數. 對於C++程式例子,我們的指標指向的的函式,是一個叫做 TMyClass 的 類的非靜態成員函式。

// 1 define a function pointer and initialize to NULL
int (*pt2Function)(floatcharchar) = NULL; // C

int (TMyClass::*pt2Member)(floatcharchar) = NULL; // C++
int
 (TMyClass::*pt2ConstMember)(floatcharcharconst = 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)(floatcharchar))
{
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))(floatfloat)
{
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)(floatfloat);

// 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)(floatfloat) = NULL;

pt2Function=GetPtr1('+'); // get function pointer from function 'GetPtr1'
cout << (*pt2Function)(24) << endl; // call function using the pointer


pt2Function=GetPtr2('-'); // get function pointer from function 'GetPtr2'
cout << (*pt2Function)(24) << 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)(floatcharchar);

// 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])(floatcharchar) = {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)(floatcharchar);

// 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])(floatcharchar) = {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;
}