指针函数与函数指针有什么用,什么是指针函数,pdf

C语言中的函数指针与指针函数
我的图书馆
C语言中的函数指针与指针函数
函数是任何一门语言中必不可少的部分,正是由这些函数组成了程序。首先谈一下C语言中的函数指针与指针函数,再了解一下函数参数传递的相关原理。
1.函数指针与指针函数
(1) 函数指针 即指向这个函数的指针,定义为 数据类型 (*fun)(参数列表) ,()的优先级比*高,所以*fun加括号。如 void (*fun)(int*,int*);
(2)指针函数 即返回值是指针的函数,定义为 数据类型 * fun(参数列表). 如 char* fun(int*,int*);即返回值为char*型。
在C语言中,变量有它的地址,同理函数也是有地址的。那么把函数的地址赋给函数指针,再通过函数指针调用这个函数就可以了。
第一步: 定义函数指针,如 int (*pfun)(int*,int*);
第二步: 定义函数 &如 int fun(int*,int*);
第三步: 把函数的地址赋给函数指针,即 pfun=
第四步: 通过函数指针去调用这个函数 (*pfun)(p,q); //pfun是函数的地址,那么 *pfun当然就是函数本身了。
2.函数参数传递问题
在C语言中,有两种参数传递的方式 ,一种是值传递,另一种是指针传递。
值传递很好理解,即把实参的值传递给形参。
而指针传递传的是地址在C语言中,形参值的改变并不能改变实参的值,但形参所指向内容值的改变却能改变实参,这一点非常的重要,是指针传递的精华所在。
3. 指针函数
当函数的返回值为指针类型时,应该尽量不要返回局部变量的指针,因为,局部变量是定义在函数内部,当这个函数调用结束了,局部变量的栈内存也被释放了,因此,不能够正确的得到返回值。实际上,内存已经被释放了,但这个指针的地址已经返回过去了,但是这个地址已经是无效的了,此时,对这个指针的使用是很危险的。
野指针并不是NULL,而是指向垃圾内存的指针。&
有两种情况可以导致野指针:
(2)malloc,free
第一种情况是定义指针,但没有给指针赋地址,此时,对指针的使用是很危险的,因为你不知道它指向哪里,是个野指针。
第二种情况,malloc是在堆上分配内存,必须由用户手动释放,当释放之后,指针指向的内存已经释放掉了,但指针本身的地址还存在,即指向了一个无效的内存,所以这时的指针为野指针,必须把这个指针p=NULL.
5. 下面举个例子说明上述几种情况
#include &stdio.h&#include &string.h&#include &stdlib.h&#include &unistd.h&void fun1(int*,int*);void fun2(int*,int*);char* fun(char*,char*);//指针函数,即返回值为指针的函数int main(){//定义3个函数指针void (*pfun1)(int*,int*);void(*pfun2)(int*,int*);char*(*pfun)(char*,char*);//定义返回值为指针的函数指针int *p;int *q;int a=10;int b=20;p=&a;//整形指针变量的初始化q=&b;printf("%d\n",*p);printf("%d\n",*q);pfun1=fun1;//把函数fun的地址赋值给函数指针pfunpfun2=fun2;(*pfun1)(p,q);//用函数指针去调用函数,pfun是fun的地址,那么*pfun当然就是函数本身了printf("%d\n",*p);printf("%d\n",*q);//当交换两个指针时,发现值并没有发生改变//在C语言中,形参的改变并不能改变实参,实参中p指向a的地址,q指向b的地址,在形参中,把两个地址互换,即形参的p指向b的地址,q指向a的地址,但并不能改变实参的值,除非改变地址中的内容值(*pfun2)(p,q);printf("%d\n",*p);printf("%d\n",*q);//此时p与q指向的值发生了变化,由于把地址中的内容交换了,所以交换了p,qpfun=char* x="ab";char* y="bc";char* s=(*pfun)(x,y);printf("%s\n",s);//free(s);//s指向这个堆内存,所以malloc之后要释放s=NULL;if(s!=NULL){//释放掉这个内存后,指针仍然不为空,此时的指针称为野指针,所以要把s=NULLprintf("%s\n",s);}//对于野指针,有两种情况//第一种情况: char*只声明了字符型指针,但没明确指向的地址,此时,用这个指针是很危险的,因为这个指针是野指针//第二种情况: malloc()之后,没有free()之后,没有把指针设置为空,因为此时指针仍然存有地址,但是这个地址已经是无效的,所以对这个指针的使用是很危险的return 0;}void fun1(int*p,int*q){int* temp=p;p=q;q=}void fun2(int*p,int*q){temp=*p;*p=*q;*q=}char* fun(char*p,char* q){//char a[]="abc";//定义一个内存空间,局部变量栈上内存//char* s=a;////在这函数结束之后,char型指针被释放掉,因此不能正确返回//因此,最好别返回一个局部变量指针//(1)解决方法:把数组变成静态,即 static char a[]="abc";静态内存在函数结束后不会被释放//(2)申请堆内存//(3)定义为常量区//char *s=(char*)malloc(sizeof(char*)*10);// strcpy(s,"abc");char* s1="ssss"; //定义一个指针变量指向字符串,在C中,字符串被存放在常量区,静态存储区域,因此,在这个函数结束之后,这个地址仍然是有效的,即常量区的内存没有被释放掉,因此能够返回值return s1;}
1. fun1函数
&fun1函数中交换地址,并不能交换两个指针指向的值,因为形参的改变不能引起实参的改变。
2. fun2函数
fun2函数交换的是地址里面的内容,所以能交换两个指针指向的值。
3. fun函数
(1)fun函数里面定义的a是个局部变量,在函数返回之后这块内存会被释放掉。因此,为了得到返回值,可以声明为 static char a[]=""abc";
(2)malloc申请的是堆内存,因此,可以得到返回值,但必须free掉这块内存,同时将p=NULL,避免野指针。
(3)可以定义char* s=字符串,在C语言中,字符串是存放是静态常量区,因此,函数结束后,那块内存不会被释放掉。可以得到返回值。
&因此,不能返回局部指针变量。
C语言中,形参只有在传递时才分配内存单元,实参到形参的传递是单向传递,因此,形参的改变并不能引起实参的改变,另外,实参与形参占据着不同的内存单元。
发表评论:
TA的最新馆藏[转]&[转]&c语言(27)
指针函数和函数指针有什么区别&
1,这两个概念都是简称,指针函数是指带指针的函数,即本质是一个函数。我们知道函数都又返回类型(如果不返回值,则为无值型),只不过指针函数返回类型是某一类型的指针。其定义格式如下所示:&
返回类型标识符 *返回名称(形式参数表)&
{ 函数体 }&
返回类型可以是任何基本类型和复合类型。返回指针的函数的用途十分广泛。事实上,每一个函数,即使它不带有返回某种类型的指针,它本身都有一个入口地址,该地址相当于一个指针。比如函数返回一个整型值,实际上也相当于返回一个指针变量的值,不过这时的变量是函数本身而已,而整个函数相当于一个“变量”。例如下面一个返回指针函数的例子:&
float *find();&
&&&&static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};&
&&&&float *p;&
&&&&int i,m;&
&&&&printf(&Enter the number to be found:&);&
&&&&scanf(&%d&,&m);&
&&&&printf(&the score of NO.%d are:\n&,m);&
&&&&p=find(score,m);&
&&&&for(i=0;i&4;i++)&
&&&&&&&&printf(&%5.2f\t&,*(p+i));&
float *find(float(*pionter)[4],int n)/*定义指针函数*/&
&&&&float *&
&&&&pt=*(pionter+n);&
&&&&return(pt);&
学生学号从0号算起,函数find()被定义为指针函数,起形参pointer是指针指向包含4个元素的一维数组的指针变量。pointer+1指向score的第一行。*(pointer+1)指向第一行的第0个元素。pt是一个指针变量,它指向浮点型变量。main()函数中调用find()函数,将score数组的首地址传给pointer.&
2,“函数指针”是指向函数的指针变量,因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上一致的。函数指针有两个用途:调用函数和做函数的参数。函数指针的说明方法为:&
数据类型标志符 (*指针变量名)(参数);注:函数括号中的参数可有可无,视情况而定。&
下面的程序说明了函数指针调用函数的方法:&
int max(int x,int y){ return(x&y?x:y); }&
void main()&
&&&&int (*ptr)();&
&&&&int a,b,c;&
&&&&scanf(&%d,%d&,&a,&b);&
&&&&c=(*ptr)(a,b);&
&&&&printf(&a=%d,b=%d,max=%d&,a,b,c);&
ptr是指向函数的指针变量,所以可把函数max()赋给ptr作为ptr的值,即把max()的入口地址赋给ptr,以后就可以用ptr来调用该函数,实际上ptr和max都指向同一个入口地址,不同就是ptr是一个指针变量,不像函数名称那样是死的,它可以指向任何函数,就看你像怎么做了。在程序中把哪个函数的地址赋给它,它就指向哪个函数。而后用指针变量调用它,因此可以先后指向不同的函数,不过注意,指向函数的指针变量没有++和--运算,用时要小心。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:52953次
积分:1120
积分:1120
排名:千里之外
原创:49篇
转载:84篇
(7)(1)(1)(26)(50)(2)(3)(10)(7)(10)(10)(6)只需一步,快速开始
后使用快捷导航没有帐号?
查看: 1801|回复: 69
指针函数与函数指针,一看必通
签到天数: 123 天[LV.7]常住居民III
马上注册加入鱼C,享用更多服务吧^_^
才可以下载或查看,没有帐号?
函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是一致的。函数指针有两个用途:调用函数和做函数的指针变量名) (指针变量名 )”中的括号不能省,若省略整体则成为一个函数说明,说明了一个返回的指针变量,所以可把函数max()赋给ptr作为ptr的值,即把max()的入口地址赋给ptr,以后就可以用ptr来调用该函数,实际上ptr和max都指向同一个入口地址,不同就是ptr是一个指针变量,不像函数名称那样是死的,它可以指向任何函数,就看你想怎么做了。在程序中把哪个函数的地址赋给它,它就指向哪个函数。而后用指针变量调用它,因此可以先后指向不同的函数。不过注意,指向函数的指针变量没有++和--运算,用时要小心。
指针函数,指针函数是指带指针的函数,即本质是一个函数。函数都有返回类型(如果不指针变量的值,不过这时的变量是函数本身而已,而整个函数相当于一个“变量”。例如下面一个返回指针函数的例子:
#include &stdio.h&
float *find(float(*pionter)[4],int n);//函数声明
int main(void)
{
& &&&static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
& &&&float *p;
& &&&int i,m;
& &&&printf(&Enter the number to be found:&);
& &&&scanf(&%d&,&m);
& &&&printf(&the score of NO.%d are:\n&,m);
& &&&p=find(score,m-1);
& &&&for(i=0;i&4;i++)
& && && &printf(&%5.2f\t&,*(p+i));
&&
& &&&return 0;
float *find(float(*pionter)[4],int n)/*定义指针函数*/
{
& &&&float *
& &&&pt=*(pionter+n);
& &&&return(pt);
}复制代码共有三个学生的成绩,函数find()被定义为指针函数,其指针变量。pointer+n指向score的第n+1行。*(pointer+1)指向第一行的第0个元素。pt是一个指针变量,它指向数组的首地址传给pointer.
游客,如果您要查看本帖隐藏内容请
[hide]//指针函数是指返回值是指针的函数,即本质是一个函数
#include&iostream&
int main()
{
& & float *find(float (*p)[4],int m);//查询序号为m的学生的四门课程的成绩
& & float score[][4]={{50,51,52,55},{70,70,40,80},{77,99,88,67}};//定义成绩数组,第一维可以为变量
& & float *pf=NULL;//定义一个指针时一定要初始化
& & int i,m;
& & cout&&&请输入您想查询的学生的序号:&;
& & cin&&m;
& & pf=find(score,m);//返回为一维数组指针,指向一个学生成绩
& & for(i=0;i&4;i++)
& & cout&&*(pf+i)&&& &;
& & cout&&
& & return 0;
}
float *find(float (*p)[4],int m)
{
& & float *pf=NULL;
& & pf=*(p+m);//p是指向二维数组的指针,加*取一维数组的指针
& &
}
[/hide]复制代码
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 52 天[LV.5]常住居民I
再过两天就学这个了{:1_1:}
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 702 天[LV.9]以坛为家II
向大师好好学习
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 172 天[LV.7]常住居民III
学无止境,咱来瞅瞅!~
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 12 天[LV.3]偶尔看看II
我也要学!!!!:big:big:big:big:big
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 2 天[LV.1]初来乍到
支持支持支持
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 32 天[LV.5]常住居民I
支持一下!
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
该用户从未签到
支持支持支持~
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 139 天[LV.7]常住居民III
学习一下 看看啊
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 1 天[LV.1]初来乍到
学习一下{:1_1:}{:1_1:}
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 18 天[LV.4]偶尔看看III
更看不懂了& & 彻底懵了
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 304 天[LV.8]以坛为家I
感谢楼主无私奉献!!
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 795 天[LV.10]以坛为家III
你看后面两个字就明白了& &
指针函数是函数
函数指针是指针
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 92 天[LV.6]常住居民II
学习了!!!
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
该用户从未签到
{:1_1:}指针不好懂
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 123 天[LV.7]常住居民III
糖心 发表于
再过两天就学这个了
加油,,,,,
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 123 天[LV.7]常住居民III
qaed 发表于
我也要学!!!!
加油啊,指针刚开始确实不太好用
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 123 天[LV.7]常住居民III
蒲公英花开 发表于
更看不懂了& & 彻底懵了
说白了就是指针函数是函数,这个函数返回的是指针,而函数指针是一个指针,它指向一个函数
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 123 天[LV.7]常住居民III
沉思的牛 发表于
你看后面两个字就明白了& &
指针函数是函数
函数指针是指针
是的,就是这样,,,,,
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
签到天数: 57 天[LV.5]常住居民I
看的有点发晕。。。
如果您的【问题求助】得到满意的解答,请自行将分类修改为【已经解决】;如果想鼓励一下楼主或帮助到您的朋友,可以给他们【评分】鼓励;善用【论坛搜索】功能,那里可能有您想要的答案!
•••(
Powered by(window.slotbydup = window.slotbydup || []).push({
id: '1102523',
container: s,
size: '180,30',
display: 'inlay-fix'
函数指针与成员函数指针有什么区别?各自有什么样的作用?
发布日期: 09:12
C++入门教程
C++成员函数指针
本章我们主要学习函数指针与成员函数指针有什么区别?各自有什么样的作用?下面我们就做一下具体讲解,希望大家多多支持中国站长网络学院。
标准C++中没有真正的面向对象的函数指针。这一点对C++来说是不幸的,因为面向对象的指针(也叫做&闭包(closure)&或&委托 (delegate)&)在一些语言中已经证明了它宝贵的价值。在Delphi (Object Pascal)中,面向对象的函数指针是Borland可视化组建库(VCL,Visual Component Library)的基础。而在目前,C#使&委托&的概念日趋流行,这也正显示出C#这种语言的成功。在很多应用程序中,&委托&简化了松耦合对象的设计 模式[GoF]。这种特性无疑在标准C++中也会产生很大的作用。很遗憾,C++中没有&委托&,它只提供了成员函数指针(member function pointers)。很多程序员从没有用过函数指针,这是有特定的原因的。因为函数指针自身有很多奇怪的语法规则(比如&-&*&和&.*&操作 符),而且很难找到它们的准确含义,并且你会找到更好的办法以避免使用函数指针。更具有讽刺意味的是:事实上,编译器的编写者如果实现&委托&的话会比他 费劲地实现成员函数指针要容易地多!在这篇文章中,我要揭开成员函数指针那&神秘的盖子&。在扼要地重述成员函数指针的语法和特性之后,我会向读者解释成员函数指针在一些常用 的编译器中是怎样实现的,然后我会向大家展示编译器怎样有效地实现&委托&。最后我会利用这些精深的知识向你展示在C++编译器上实现优化而可靠的&委 托&的技术。比如,在Visual C++(6.0, .NET, and .NET 2003)中对单一目标委托(single-target delegate)的调用,编译器仅仅生成两行汇编代码!函数指针下面我们复习一下函数指针。在C和C++语言中,一个命名为my_func_ptr的函数指针指向一个以一个int和一个char*为参数的函数,这个函数返回一个浮点值,声明如下:float (*my_func_ptr)(int, char *);//为了便于理解,我强烈推荐你使用typedef关键字。//如果不这样的话,当函数指针作为一个函数的参数传递的时候,// 程序会变得晦涩难懂。// 这样的话,声明应如下所示:typedef float (*MyFuncPtrType)(int, char *);MyFuncPtrType my_func_应注意,对每一个函数的参数组合,函数指针的类型应该是不同的。在Microsoft Visual C++(以下称MSVC)中,对三种不同的调用方式有不同的类型:__cdecl, __stdcall, 和__fastcall。如果你的函数指针指向一个型如float some_func(int, char *)的函数,这样做就可以了:my_func_ptr = some_当你想调用它所指向的函数时,你可以这样写:(*my_func_ptr)(7, &Arbitrary String&);你可以将一种类型的函数指针转换成另一种函数指针类型,但你不可以将一个函数指针指向一个void *型的数据指针。其他的转换操作就不用详叙了。一个函数指针可以被设置为0来表明它是一个空指针。所有的比较运算符(==, !=, &, &, &=, &=)都可以使用,可以使用&==0&或通过一个显式的布尔转换来测试指针是否为空(null)。在C语言中,函数指针通常用来像qsort一样将函数作为参数,或者作为Windows系统函数的回调函数等等。函数指针还有很多其他的应 用。函数指针的实现很简单:它们只是&代码指针(code pointer)&,它们体现在汇编语言中是用来保存子程序代码的首地址。而这种函数指针的存在只是为了保证使用了正确的调用规范。成员函数指针在C++程序中,很多函数是成员函数,即这些函数是某个类中的一部分。你不可以像一个普通的函数指针那样指向一个成员函数,正确的做法应该是,你必须使用一个成员函数指针。一个成员函数的指针指向类中的一个成员函数,并和以前有相同的参数,声明如下:float (SomeClass::*my_memfunc_ptr)(int, char *);//对于使用const关键字修饰的成员函数,声明如下:float (SomeClass::*my_const_memfunc_ptr)(int, char *)注意使用了特殊的运算符(::*),而&SomeClass&是声明中的一部分。成员函数指针有一个可怕的限制:它们只能指向一个特定的类 中的成员函数。对每一种参数的组合,需要有不同的成员函数指针类型,而且对每种使用const修饰的函数和不同类中的函数,也要有不同的函数指针类型。在 MSVC中,对下面这四种调用方式都有一种不同的调用类型:__cdecl, __stdcall, __fastcall, 和 __thiscall。(__thiscall是缺省的方式,有趣的是,在任何官方文档中从没有对__thiscall关键字的详细描述,但是它经常在错 误信息中出现。如果你显式地使用它,你会看到&它被保留作为以后使用(it is reserved for future use)&的错误提示。)如果你使用了成员函数指针,你最好使用typedef以防止混淆。将函数指针指向型如float SomeClass::some_member_func(int, char *)的函数,你可以这样写:my_memfunc_ptr = &SomeClass::some_member_很多编译器(比如MSVC)会让你去掉&&&,而其他一些编译器(比如GNU G++)则需要添加&&&,所以在手写程序的时候我建议把它添上。若要调用成员函数指针,你需要先建立SomeClass的一个实例,并使用特殊 操作符&-&*&,这个操作符的优先级较低,你需要将其适当地放入圆括号内。SomeClass *x = new SomeC(x-&*my_memfunc_ptr)(6, &Another Arbitrary Parameter&);//如果类在栈上,你也可以使用&.*&运算符。SomeC(y.*my_memfunc_ptr)(15, &Different parameters this time&);不要怪我使用如此奇怪的语法——看起来C++的设计者对标点符号有着由衷的感情!C++相对于C增加了三种特殊运算符来支持成员指 针。&::*&用于指针的声明,而&-&*&和&.*&用来调用指针指向的函数。这样看起来对一个语言模糊而又很少使用的部分的过分关注是多余 的。(你当然可以重载&-&*&这些运算符,但这不是本文所要涉及的范围。)一个成员函数指针可以被设置成0,并可以使用&==&和&!=&比较运算符,但只能限定在同一个类中的成员函数的指针之间进行这样的比较。 任何成员函数指针都可以和0做比较以判断它是否为空。与函数指针不同,不等运算符(&, &, &=, &=)对成员函数指针是不可用的。成员函数指针的怪异之处成员函数指针有时表现得很奇怪。首先,你不可以用一个成员函数指针指向一个静态成员函数,你必须使用普通的函数指针才行(在这里&成员函数 指针&会产生误解,它实际上应该是&非静态成员函数指针&才对)。其次,当使用类的继承时,会出现一些比较奇怪的情况。比如,下面的代码在MSVC下会编 译成功(注意代码注释):#include &stdio.h&class SomeClass {public:virtual void some_member_func(int x, char *p) {printf(&In SomeClass&); };};class DerivedClass : public SomeClass {public:// 如果你把下一行的注释销掉,带有 line (*)的那一行会出现错误// virtual void some_member_func(int x, char *p) { printf(&In DerivedClass&); };};int main() {//声明SomeClass的成员函数指针typedef void (SomeClass::*SomeClassMFP)(int, char *);SomeClassMFP my_memfunc_my_memfunc_ptr = &DerivedClass::some_member_ // ---- line (*)return 0;}奇怪的是,&DerivedClass::some_member_func是一个SomeClass类的成员函数指针,而不是 DerivedClass类的成员函数指针!(一些编译器稍微有些不同:比如,对于Digital Mars C++,在上面的例子中,&DerivedClass::some_member_func会被认为没有定义。)但是,如果在 DerivedClass类中重写(override)了some_member_func函数,代码就无法通过编译,因为现在 的&DerivedClass::some_member_func已成为DerivedClass类中的成员函数指针!成员函数指针之间的类型转换是一个讨论起来非常模糊的话题。在C++的标准化的过程中,在涉及继承的类的成员函数指针时,对于将成员函数指 针转化为基类的成员函数指针还是转化为子类成员函数指针的问题和是否可以将一个类的成员函数指针转化为另一个不相关的类的成员函数指针的问题,人们曾有过 很激烈的争论。然而不幸的是,在标准委员会做出决定之前,不同的编译器生产商已经根据自己对这些问题的不同的回答实现了自己的编译器。根据标准(第 5.2.10/9节),你可以使用reinterpret_cast在一个成员函数指针中保存一个与本来的类不相关的类的成员函数。有关成员函数指针转换 的问题的最终结果也没有确定下来。你现在所能做的还是像以前那样——将成员函数指针转化为本类的成员函数的指针。在文章的后面我会继续讨论这个问题,因为 这正是各个编译器对这样一个标准没有达成共识的一个话题。在一些编译器中,在基类和子类的成员函数指针之间的转换时常有怪事发生。当涉及到多重继承时,使用reinterpret_cast将子类 转换成基类时,对某一特定编译器来说有可能通过编译,而也有可能通不过编译,这取决于在子类的基类列表中的基类的顺序!下面就是一个例子:class Derived: public Base1, public Base2 // 情况 (a)class Derived2: public Base2, public Base1 // 情况 (b)typedef void (Derived::* Derived_mfp)();typedef void (Derived2::* Derived2_mfp)();typedef void (Base1::* Base1mfp) ();typedef void (Base2::* Base2mfp) ();Derived_对于情况(a),static_cast&Base1mfp&(x)是合法的,而 static_cast&Base2mfp&(x)则是错误的。然而情况(b)却与之相反。你只可以安全地将子类的成员函数指针转化为第一个 基类的成员函数指针!如果你要实验一下,MSVC会发出C4407号警告,而Digital Mars C++会出现编译错误。如果用reinterpret_cast代替static_cast,这两个编译器都会发生错误,但是两种编译器对此有着不同的原 因。但是一些编译器对此细节置之不理,大家可要小心了!标准C++中另一条有趣的规则是:你可以在类定义之前声明它的成员函数指针。这对一些编译器会有一些无法预料的副作用。我待会讨论这个问题,现在你只要知道要尽可能得避免这种情况就是了。需要值得注意的是,就像成员函数指针,标准C++中同样提供了成员数据指针(member data pointer)。它们具有相同的操作符,而且有一些实现原则也是相同的。它们用在stl::stable_sort的一些实现方案中,而对此很多其他的 应用我就不再提及了。成员函数指针的使用现在你可能会觉得成员函数指针是有些奇异。但它可以用来做什么呢?对此我在网上做了非常广泛的调查。最后我总结出使用成员函数指针的两点原因:用来做例子给C++初学者看,帮助它们学习语法;或者为了实现&委托(delegate)&!成员函数指针在STL和Boost库的单行函数适配器(one-line function adaptor)中的使用是微不足道的,而且允许你将成员函数和标准算法混合使用。但是它们最重要的应用是在不同类型的应用程序框架中,比如它们形成了MFC消息系统的核心。当你使用MFC的消息映射宏(比如ON_COMMAND)时,你会组装一个包含消息ID和成员函数指针(型如:CCmdTarget::* 成员函数指针)的序列。这是MFC类必须继承CCmdTarget才可以处理消息的原因之一。但是,各种不同的消息处理函数具有不同的参数列表(比如 OnDraw处理函数的第一个参数的类型为CDC *),所以序列中必须包含各种不同类型的成员函数指针。MFC是怎样做到这一点的呢?MFC利用了一个可怕的编译器漏洞(hack),它将所有可能出现的 成员函数指针放到一个庞大的联合(union)中,从而避免了通常需要进行的C++类型匹配检查。(看一下afximpl.h和cmdtarg.cpp中 名为MessageMapFunctions的union,你就会发现这一恐怖的事实。)因为MFC有如此重要的一部分代码,所以事实是,所有的编译器都 为这个漏洞开了绿灯。(但是,在后面我们会看到,如果一些类用到了多重继承,这个漏洞在MSVC中就不会起作用,这正是在使用MFC时只能必须使用单一继 承的原因。)在boost::function中有类似的漏洞(但不是太严重)。看起来如果你想做任何有关成员函数指针的比较有趣的事,你就必须做好与这个语言的漏洞进行挑战的准备。要是你想否定C++的成员函数指针设计有缺陷的观点,看来是很难的。在写这篇文章中,我有一点需要指明:&允许成员函数指针之间进行转换(cast),而不允许在转换完成后调用其中的函数&,把这个规则纳入 C++的标准中是可笑的。首先,很多流行的编译器对这种转换不支持(所以,转换是标准要求的,但不是可移植的)。其次,所有的编译器,如果转换成功,调用 转换后的成员函数指针时仍然可以实现你预期的功能:那编译器就没有所谓的&undefined behavior(未定义的行为)&这类错误出现的必要了(调用(Invocation)是可行的,但这不是标准!)。第三,允许转换而不允许调用是完全 没有用处的,只有转换和调用都可行,才能方便而有效地实现委托,从而使这种语言受益。为了让你确信这一具有争议的论断,考虑一下在一个文件中只有下面的一段代码,这段代码是合法的:class SomeCtypedef void (SomeClass::* SomeClassFunction)(void);void Invoke(SomeClass *pClass, SomeClassFunction funcptr) {(pClass-&*funcptr)(); };注意到编译器必须生成汇编代码来调用成员函数指针,其实编译器对SomeClass类一无所知。显然,除非链接器进行了一些极端精细的优化 措施,否则代码会忽视类的实际定义而能够正确地运行。而这造成的直接后果是,你可以&安全地&调用从完全不同的其他类中转换过来的成员函数指针。
(window.slotbydup = window.slotbydup || []).push({
id: '1063561',
container: s,
size: '230,230',
display: 'inlay-fix'
Visual C++是一个功能强大的可视化软件开发工具,是高等院校计算机及相关专业主要核心课程。 本教程对Visual C++ 的应用与开发进行了详细系统的介绍,内容主要包括:Visual C++程序的建立,菜单、工具栏和状态栏的创建,对话框和常用控件,窗口、文档与视图,图形绘制,数据库应用,多媒体技术等。 本教程以案例教学为主,各章节都附有大量的实例,并且操作步骤详细,有利于引导读者更好的消化、理解和实际应用本章节所学的知识内容,希望大家能多多支持中国站长网络学院!
免责声明:以上教程信息由会员自行搜集、整理、发布,内容的真实性、准确性和合法性由发布会员负责。站长学院对此不承担任何责任。}

我要回帖

更多关于 c 函数指针 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信