怎样声明指向函数的指针呢? 用函数指针作为实参的参数会是什么样呢 ?下面是函数lexicoCompare()的定义; 它按字典序比较两个字符串:
#include <string>
int lexicoCompare( const string &s1, const string &s2 )
{
return s1.compare(s2);
}
如果字符串 s1 和 s2 中的所有字符都相等, 则 lexicoCompare()返回 0 否则 如果第一 个参数表示的字符串小于第二个参数表示的字符串 则返回一个负数 如果大于 则返回一
个正数 函数名不是其类型的一部分, 函数的类型只由它的返回值和参数表决定。指向 lexicoCompare()的指针必须指向与 lexicoCompare()相同类型的函数(带有相同的返回类型和 相同的参数表) 让我们试一下 :
int *pf( const string &, const string & ); // 喔! 差一点
这几乎是正确的 ,问题是编译器把该语句解释成名为 pf 的函数的声明, 它有两个参数 并且返回一个 int*型的指针 。参数表是正确的 但是返回值不是我们所希望的。 解引用操作
符 * 应与返回类型关联, 所以在这种情况下, 是与类型名 int 关联, 而不是 pf。 要想让解 引用操作符与 pf 关联 括号是必需的 :
int (*pf)( const string &, const string & ); // ok: 正确
这个语句声明了 pf 是一个指向函数的指针 。该函数有两个参数和 int 型的返回值, 即指向函数的指针, 它与 lexicoCompare()的类型相同。 下列函数与 lexicoCompare()类型相同 ,都可以用 pf 来指向 :
int sizeCompare( const string &, const string & );
但是 calc()和 gcd()与前面两个函数的类型不同 不能用 pf 来指 。
int calc( int , int );
int gcd( int , int );
可以如下定义 pfi 它能够指向这两个函数:
int (*pfi)( int, int );
省略号是函数类型的一部分 ,如果两个函数具有相同的参数表 ,但是一个函数在参数表尾有省略号 ,则它们被视为不同的函数类型 指向这两个函数的指针类型也不同 .
int printf( const char*, ... );
int strlen( const char* );
int (*pfce)( const char*, ... ); // 可以指向 printf()
int (*pfc)( const char* ); // 可以指向 strlen()
函数返回类型和参数表的不同组合 代表了各不相同的函数类型 。
初始化和赋值
我们知道 ,不带下标操作符的数组名会被解释成指向首元素的指针 。当一个函数名没有被调用操作符修饰时, 会被解释成指向该类型函数的指针。 例如表达式
lexicoCompare;
被解释成类型
int (*)( const string &, const string & );
的指针。
将取地址操作符作用在函数名上也能产生指向该函数类型的指针, 因此 lexicoCompare 和&lexioCompare 类型相同 ,指向函数的指针可如下被初始化
int (*pfi)( const string &, const string & ) = lexicoCompare;
int (*pfi2)( const string &, const string & ) = &lexicoCompare;
指向函数的指针可以如下被赋值
pfi = lexicoCompare;
pfi2 = pfi;
只有当赋值操作符左边指针的参数表和返回类型与右边函数或指针的参数表和返回类型完全匹配时, 初始化和赋值才是正确的。 如果不匹配, 则将产生编译错误消息, 在指向函数 类型的指针之间不存在隐式类型转换,例如:
int calc( int, int );
int (*pfi2s)( const string &, const string & ) = 0;
int (*pfi2i)( int, int ) = 0;
int main()
{
pfi2i = calc; // ok
pfi2s = calc; // 错误: 类型不匹配
pfi2s = pfi2i; // 错误: 类型不匹配
return 0;
}
函数指针可以用 0 来初始化或赋值 以表示该指针不指向任何函数 。
调用
指向函数的指针可以被用来调用它所指向的函数 ,调用函数时, 不需要解引用操作符无论是用函数名直接调用函数, 还是用指针间接调用函数, 两者的写法是一样的。 例如 :
#include <iostream>
int min( int*, int );
int (*pf)( int*, int ) = min;
const int iaSize = 5;
int ia[ iaSize ] = { 7, 4, 9, 2, 5 };
int main()
{
cout << "Direct call: min: " << min( ia, iaSize ) << endl;
cout << "Indirect call: min: " << pf( ia, iaSize ) << endl;
return 0;
}
int min( int* ia, int sz )
{
int minVal = ia[ 0 ];
for ( int ix = 1; ix < sz; ++ix )
if ( minVal > ia[ ix ] )
minVal = ia[ ix ];
return minVal;
}
调用
pf( ia, iaSize );
也可以用显式的指针符号写出:
(*pf)( ia, iaSize );
这两种形式产生相同的结果, 但是第二种形式让读者更清楚该调用是通过函数指针执行的 。如果函数指针的值为 0 则两个调用都将导致运行时刻错误 ,只有已经被初始化
或赋值的指针( 引用到一个函数 )才可以被安全地用来调用一个函数 。