1、函数指针的引出
假设我们需要写个函数
sort( start, end, compare );
对start 和end 之间的数组元素进行排序compare 定义了比较数组中两个字符串的比较操作。如果我们需要比较的数组是string类型,那么排序方式,也许是按照字典序列,也许是串长度,也许是出现频率,那么怎么方便的进行比较呢?
众所周知,c语言的一大精髓就是指针,那么对此,我们同样可以引入指针来解决。这里的ag真人游戏的解决方案就是函数指针:讲第三个参数compare 设为函数指针并由它指定要使用的比较函数。从而方便的进行各种比较。
2、函数指针的使用
1)声明
怎么声明一个函数指针呢?
int (*pf)( const string &, const string & ); // ok: 正确
如上,声明了一个函数指针,注意的是,解引用操作符* 应与返回类型关联所以在这种情况下是与类型名int 关联而不是pf 要想让解引用操作符与pf 关联,所以括号是必需的,而不能声明为:
int *pf( const string &, const string & );
2)初始化、赋值和调用
a. 函数指针可以用0 来初始化或赋值以表示该指针不指向任何函数。
b.直接去想要调用的函数名,如add,注意,这里没有括号。为什么呢?我们知道不带下标操作符的数组名会被解释成指向首元素的指针当一个函数名没有被调用操作符修饰时会被解释成指向该类型函数的指针,例如表达式
lexicocompare;
被解释成类型
int (*)( const string &, const string & );
的指针,这里,lexicocompare定义如下:
#include
int lexicocompare( const string &s1, const string &s2 ) {
return s1.compare(s2);
}
c.将取地址操作符作用在函数名上也能产生指向该函数类型的指针因此lexicocompare和&lexiocompare 类型相同
对于初始化和赋值的示例如下:
int (*pfi)( const string &, const string & ) = lexicocompare;//初始化
pfi = lexicocompare;//赋值
看到这个赋值,楼主想到2个地方,一个是在严蔚敏版数据结构的源代码中,bfs和dfs中的visit函数,都是定义为的函数指针,当时的定义为:
void(*visitfunc)(char* v); /* 函数变量(全局量) */
传参时如本例提出,将参数作为函数指针传入
void dfstraverse(algraph g,void(*visit)(char*))
另外一个,是在flex的actionscrip中的addenentlisten(),如
addeventlistener(event.close, closehandler);
closehandler则是作为函数指针传入,虽然在as入门书上讲是引用,不过引用,不就是弱化版指针呢么?(其实对于引用,c primer有一句简要的概括:
引用是没有指针语法的指针。比如调用时指针用->,引用用点操作符)。
3、问题的解决
下面用函数指针解决开始提出的sort问题,funcp.h代码如下:
#include
#include
using namespace std;
typedef int ( *pfi2s )( const string &, const string & );
int lexicocompare( const string &s1, const string &s2 )
{
return s1.compare(s2);
}
void sort( string *s1, string *s2,pfi2s compare = lexicocompare )
{
// 递归的停止条件
if ( s1 < s2 )
{
string elem = *s1;
string *low = s1;
string *high = s2 1;
for (;;)
{
while ( compare( * low, elem ) < 0 && low < s2) ;
while ( compare( elem, *--high ) < 0 && high > s1) ;
if ( low < high )
low->swap(*high);
else break;
} // end, for(;;)
s1->swap(*high);
sort( s1, high - 1, compare );
sort( high 1, s2, compare );
} // end, if ( s1 < s2 )
}
main.cpp如下:
#include "funcp.h"
string as[10] = { "a", "light", "drizzle", "was", "falling",
"when", "they", "left", "the", "museum" };
int main()
{
// 调用 sort(), 使用缺省实参作比较操作
sort( as, as sizeof(as)/sizeof(as[0]) - 1 );
// 显示排序之后的数组的结果
for ( int i = 0; i < sizeof(as)/sizeof(as[0]); i )
cout << as[ i ].c_str() << endl;
return 0;
}
程序使用了typedef使程序可读性更强,并提供了默认参数(关于默认参数这种偷懒的东东,理解为初始化对话框内容这样,以后可改,只是提供初值。只是这样的初始化,很符合常规思维,理念上更可取)
4、一些注意的问题
在指向函数类型的指针之间不存在隐式类型转。也就是,只有当赋值操作符左边指针的参数表和返回类型与右边函数或指针的参数表和返回类型完全匹配时初始化和赋值才是正确的如果不匹配则将产生编译错误消息。在灵活性上,更注重了安全性,高级货啊!
关于函数指针,还可以参考https://www.coonote.com/cplusplus-note/c-fun-pointer.html这个简单明了,很清晰易懂。