现在的位置: 首页 > 综合 > 正文

C和C++的函数指针语法

2013年10月03日 ⁄ 综合 ⁄ 共 13972字 ⁄ 字号 评论关闭

    
777人阅读
     评论(0)    
收藏    
举报
    

1  定义一个函数指针

且不论语法,有两种不同形式的指针函数: 一个是指向普通的C函数的指针和C++的静态成员函数,另外一个是指向C++的非静态成员函数的指针。这两者的基本区别是所有指向非静态成员函数的指针都需要这个隐含定义:指向本类的一个This指针。注意:这两种函数指针彼此不兼容。

既然一个函数指针实际上和一个变量没有什么区别,定义它的时候也就没有什么特殊。下面的例子中我们定义3个函数指针,名字是pt2Function,
pt2Memberpt2ConstMember. 它们指向的函数,输入一个 float和两个char 类型的变量并返回一个
int 类型的变量. 对于C++程序例子,我们的指针指向的的函数,是一个叫做 TMyClass 的类的非静态成员函数。



// 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 比较函数指针

你可以和通常方式一样使用比较符号(==, !=)。下面的例子中我们检查变量 pt2Functionpt2Member ,它们分别指向的函数 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;
}
 

1  定义一个函数指针

且不论语法,有两种不同形式的指针函数: 一个是指向普通的C函数的指针和C++的静态成员函数,另外一个是指向C++的非静态成员函数的指针。这两者的基本区别是所有指向非静态成员函数的指针都需要这个隐含定义:指向本类的一个This指针。注意:这两种函数指针彼此不兼容。

既然一个函数指针实际上和一个变量没有什么区别,定义它的时候也就没有什么特殊。下面的例子中我们定义3个函数指针,名字是pt2Function,
pt2Memberpt2ConstMember. 它们指向的函数,输入一个 float和两个char 类型的变量并返回一个
int 类型的变量. 对于C++程序例子,我们的指针指向的的函数,是一个叫做 TMyClass 的类的非静态成员函数。



// 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 比较函数指针

你可以和通常方式一样使用比较符号(==, !=)。下面的例子中我们检查变量 pt2Functionpt2Member ,它们分别指向的函数 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;
}
 

抱歉!评论已关闭.