{译}函数指针漫谈(2)

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

http://blog.csdn.net/luckheadline
1. 定义函数指针
    有两种函数指针类型:一个是C函数指针或静态C++成员函数指针;另外一个是非静态的C++成员函数指针。基本的区别是所有的非静态成员函数指针都需要一个隐藏参数:this指针是一个类的实例。记住:这两种函数指针彼此不兼容。
    因为函数指针只是一个变量,因此它必须被定义。在下面例子里我们定义了三个函数指针pt2Function, pt2Member and pt2ConstMember。他们都有三个参数(一个float型,两个char型),返回都是int型。在假定的C++例子里,这些函数都是TMyClass的非静态成员函数。
// 2.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. 调用约定(Calling Convention)
通常你没必要考虑函数的调用约定:如果你没有特别指定,编译器缺省会假定为__cdecl。调用约定会告诉编译器诸如如何传递参数或者怎样产生函数名。其它的调用约定有__stdcall, __pascal and __fastcall。调用约定属于函数签名:因此不同调用约定的函数和函数指针彼此不兼容!对于Borland和Microsoft编译器,我们要在返回类型和函数或者函数指针名之间指明具体的调用约定。对于GNU GCC,我们使用__attribute__关键字。
// 2.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. 为函数指针分配地址
    很容易就可以将一个函数的地址分配给一个函数指针。我们就简单的使用一个合适的已知函数或成员函数的名字,但是对大多数编译器我们可以选择在函数名前加上取地址符&。我们可能需要使用成员函数完整的名字,包括类名和域操作符(::)。而且,我们需要保证访问的函数确实在可以访问的域里。
// 2.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的地址。
// 2.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指针。
// 2.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. 如何将函数指针当作参数传递
    我们可以将函数指针作为函数的一个参数传递,特别如果想要传递一个指针作为callback函数。下面的代码表明如何传递一个指针给函数,函数有一个float型参数和两个char型参数,返回int型:
//------------------------------------------------------------------------------------
// 2.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型。如果想返回一个成员函数指针,我们不得不改变所有函数指针的定义/声明。
//------------------------------------------------------------------------------------
// 2.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. 如何使用函数指针数组
    操作函数指针数组非常有趣。它提供了选择一个函数作为索引的可能。它的语法很难,经常容易导致疑惑。下面是两种如何在C/C++中定义和使用函数指针数组的方式。第一种是使用typedef,第二种直接定义数组。实际中可以选择自己偏好的方式。
//------------------------------------------------------------------------------------
// 2.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 2.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
   //nd 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.

   funcArr1[0] = funcArr2[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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值