RECORDING MY FANTASY

Tuesday, April 03, 2007

函数指针 条款14

/*
* 条款14
* 函数指针
*
* 我们可以声明一个指向特定类型函数的指针
*/
void (*fp)(int);//指向函数的指针

/*括号是必不可少的,它表明fp是指向一个返回值为void的函数的指针*/

extern int f(int);

extern void g(long);

extern void h(int);
//...
fp = f; //错误!&f的类型为int (*)(int), 而不是void (*)(int);
fp = g; //错误!&g的类型为void (*)(long), 而不是void (*)(int);
fp = h; //正确!
fp = &h;//正确!
/* 将一个函数的地址初始化或者赋值给一个指向函数的指针的时候,无需显式地取得函数
* 地址,编译器知道隐式地获得函数的地址,因此这种情况下&是可省的,通常忽略不用
*/

/* 类似的,为了调用函数指针所指向的函数而对指针进行解引用操作也是没有必要的,编译
* 器可以帮你解引用
*/

(*fp)(12); //显式地解引用
fp(12); //隐式得解引用,结果相同

/* 和void *指针可以指向任何类型的数据不同,不存在可以指向任何类型函数的通用指针;
* 还要注意,非静态成员函数的地址不是一个指针,因此不可以将一个函数指针指向一个
* 非静态成员函数
*/

/* 函数指针的一个传统用法就是回调(callback).
* 一个回调就是一个可能的动作,这个动作在初始化阶段配置,以便在将来可能发生的事件进
* 行响应。打个比方,如果我们希望救火,那么最好在开始阶段就计划好如何做出反应
*/

extern void stopDropRoll();
inline void jumpIn();

//...
void (*fireAction)() = 0;

//...
if(!fatallist) {//如果你关心失火了
//那么设置适当的动作以防万一
if(nearWater)
fireAction = jumpIn;
else
fireAction = stopDropRoll;
}

/* 一旦决定了要执行的动作,代码中的令一部分就可以专注于是否以及何时去执行动作,而
* 无需关心这个动作是什么了
*/
if( ftemp >= 451 ) {//如果着火了
if(fireAction)
fireAction();//执行之
}
/* 注意,一个函数指针指向一个内联函数是合法的,然而,通过函数指针调用内联函数不会
* 导致内联式的函数调用;编译器只能生成间接的/非内联的函数代码
*/

/* 另外,函数指针持有个重载函数的地址也是合法的,指针的类型被用在各种不同的候选函数中
* 挑选最佳匹配的函数
*/
void jumpIn();
void jumpIn(bool canSwim);
//...
fireAction = jumpIn;

No comments: