您的位置:首页 > 其它

函数指针的用法

2010-12-20 02:02 274 查看

函数指针的用法

概要:本文描述的函数指针的一些使用方法。
关键字:函数指针、返回函数指针的函数

提到函数指针,一般我们能够想到的用法如下。

1、 第一种,直接使用,比较原始的方式。

return_type (*func_pointer)(parameter_list),即:返回类型 (*函数名)(参数列表)
例如:
int (*pFun)(int n);
int testFun1(int n)
{
    cout << n << endl;
    return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
    pFun = testFun1;
    (*pFun)(1);
    pFun(1);
}


说明:首先,我们定义一个函数指针变量pFun,函数的原型是:int (*)(int n),即,该函数是一个参数为整形,返回值是空值的函数。请注意我在这里使用的措辞,pFun是一个“变量”,而非“类型”,那么,既然是变量,它就应该能够被赋值,能够被初始化。因此,由于函数testFun1的参数与返回值与上面所描述的类型吻合,所以我们能够对pFun进行赋值pFun = testFun1。然后使用函数指针进行调用,(*pFun)(1)。为什么可以这么调用呢?我们需要理解:函数的函数名本质上就是一个指针,函数名指向该函数在内存中的首地址。就像int array[10]中array就能代表数组首地址一样。所以,表达式(*pFun)(1)表达的意思是先取pFun的值,得到testFun1的地址,然后再进行调用,与直接调用testFun1(1)没有任何区别。
那pFun(1)又是怎么回事,为什么也能够进行调用?为什么与(*pFun)(1)表达同一个意思?
以下说明解释了为什么?在这里引用了一位达人的链接,膜拜先,同时也灰肠感谢这位达人的文字指点。
http://blog.21ic.com/user1/3742/archives/2007/34818.html

/*****************************************************************/
如何获得函数的地址:
有两种方式获取函数的地址。假设funcptr是一个函数指针。如果我们将它指向一个兼容函数func()。
第一种方法使用隐式指针转换(implicit conversion to pointer):
funcptr = func;
第二种方法使用显式指针转换(explicit conversion to pointer):
funcptr = &func;
这两种方法都是可行的。实际上,如果在程序中有第一种形式的语句,编译器会把它自动转换为第二种方式。
使用函数指针调用函数:
象获取函数的地址一样,通过函数指针调用函数的方法也有两种:
第一种是使用显式指针(explicit dereference of the pointer),如下:
extern void func(int x, int y);
void (*func_ptr)(int x, int y) = func;
(*funcptr)(3, 2);
第二种称为隐式指针(implicit dereference of the pointer)。
extern void func(int x, int y):
void (* func_ptr)(int x, int y) = func;
funcptr(3, 2);
/*****************************************************************/


如果你看明白了上面的描述,那么应该很清楚的知道为什么了。呵呵。

2、 第二种,使用typedef的方式。
先说明一下typedef的作用,该关键字的目的是将一个已知的类型定义成一个新的类型,使用新的类型可能会具有更加明确的语义,或者使用更加方便。
如:typedef int INT; INT n = 100;
这种方式是如下定义的。

typedef return_type (*新类型)(parameter_list),即:返回类型 (*新类型)(参数列表)
例如:
typedef int (*FUN)(int n);
int testFun1(int n)
{
    cout << n << endl;
    return 1;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    FUN pFun;
    pFun = testFun1;
    (*pFun)(1);
    pFun(1);
}


说明:这种方式与第一种唯一不同的就是使用了typedef,它为函数的原型为:int (*)(int n)的类型定义了一个新的名字(或称为类型),叫FUN,使用FUN定义一个变量pFun,pFun就能代表一个函数指针,代表的函数原型就是int (*)(int n)。pFun既然是一个变量,那么其使用也就和前面所述的第一种方式无异了,这里不再赘述。

3 第三种,在类中使用函数指针。
class CTest
{
public:
    int Add(int n1, int n2)
    {
        return (n1 + n2);
    }
};
typedef int (CTest::*PADD)(int, int);
int _tmain(int argc, _TCHAR* argv[])
{
    PADD pFun = &CTest::Add;
    CTest testobj;
    int rt = (testobj.*pFun)(1, 2);
    CTest* pTestobj = new CTest();
    rt = (pTestobj->*pFun)(3, 4);
	return 0;
}

指针的定义加上了“类”限制, 指针的使用加上了的“对象”限制,用来指明指针指向的函数是哪个类的, 使用的时候是对象相关的.

个人感觉在类中使用函数指针没有一点用处, 至少我现在不知道有啥用途.

直到我在阅读《STL源码剖析》之前,我一直认为函数指针的使用方式也就只有这么多,但今天在读这本书的时候,发现了以下奇怪的用法,见书:P57页,代码如下:

static void (*__malloc_alloc_oom_handle)();
......(略)
void ( *set_malloc_handle(void (*f)()) ) ()
{
    void (*old)() = __malloc_alloc_oom_handle;
    __malloc_alloc_oom_handle = f;
    return (old);
}
......(略)
void (*__malloc_alloc_template<inst>)::__malloc_alloc_oom_handle() = 0;   /* 为静态变量赋初值*/


乍一看,不对呀,void ( *set_malloc_handle(void (*f)()) ) ()这个定义明明是返回一个空值啊,为什么返回的是一个函数指针,难道书出错了?google了一下,终于明白是怎么回事。原来函数指针还可以这么用。

4、 第四种,定义返回函数指针的函数。
return_type ( *function(func_parameter_list) ) (parameter_list)

说明:这里定义了一个函数function,该函数的参数列表是(func_patameter_list),返回类型是一个函数指针,这个函数指针的原型是return_type (*)(parameter_list)。

得之这种使用方式后,上面的源代码我们就能够明白到底是怎么回事了。

因此:void ( *set_malloc_handle(void (*f)()) ) ()这个定义就是说,定义了一个函数set_malloc_handle,其参数是一个函数指针f,其原型是void (*)(),函数set_malloc_handle的返回值也是一个指针,其原型也是void (*)(),函数内部先将旧的函数指针保存起来,然后设置新的函数指针,最后将旧的函数指针返回出去。一目了然。

实际上,按照这种方式,看着总归有些别扭,感觉语义晦涩难懂,无非就是一个函数,它即能够接收一个函数指针,又能够返回一个函数指针,因此,完全可以按照以下方式来做:

typedef void (*newfun)();
newfun set_malloc_handle(newfun f)
{
    newfun old = malloc_alloc_oom_handle;
    malloc_alloc_oom_handle = f;
    return old;
}


这样看起来是不是更加清晰了呢?呵呵。实际上,我查看了一下windows的STL版本里面的定义,就是按照这种方式。代码如下:

typedef int (__cdecl *new_hand)(size_t);
new_hand __cdecl _set_new_handler(new_hand);


再看一个例子,以前我在刚学linux信号的时,没怎么搞明白,现在也一目了然了。
signal函数原型
Linux 2.0之前版本
void (*signal (int signo, void (*func)(int))) (int);
Linux 2.6 版本
typedef void (*__sighandler_t) (int);
extern __sighandler_t signal (int __sig, __sighandler_t __handler)



本文参考链接:
1. 关于C++中函数指针的使用:
http://www.98exe.net/Article/a/2006-10-23/2025.html
2. 函数指针及其应用:
http://blog.21ic.com/user1/3742/archives/2007/34818.html
3. 定义返回函数指针的函数:
http://dev.firnow.com/course/3_program/c++/cppjs/20091012/178580.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: