VC++的函数指针和回调函数 及友元函数
什么是函数指针
函数指针是指向函数的指针变量。也就是说,它是一个指针变量,而且该指针指向一个函数。
对于指针变量来说,它的值是它指向的变量的地址。举个例子:指针变量pi是指向一个整型变量i的指针,则变量i的地址 &i 就是指针变量pi的值。也就是说整型变量指针指向一个整型变量,而整型变量指针的值就是它所指的整型变量的地址。与其它类型指针变量一样,函数指针变量的值就是它指向的函数的地址。
那么什么是函数的地址呢?
我们首先来看函数调用是怎么回事。在程序运行时,一个函数占用一段连续的内存。当调用一个函数时,实际上是跳转到函数的入口地址,执行函数体的代码,完成后返回。
函数指针指向一个函数的入口地址,也就是函数存储空间的首地址。
在C语言中,数组名代表数组的首地址,同样函数名代表了函数的首地址,因此在赋值时,直接将函数指针指向函数名就行了。
函数指针的定义
一般,函数指针的定义格式为:
函数类型 (*指针变量名)(形参列表);
“函数类型”说明函数的返回类型,由于“()”的优先级高于“*”,所以指针变量名外的括号必不可少,后面的“形参列表”表示指针变量指向的函数所带的参数列表。
例如:对于函数int f(int a),我们定义一个指向该函数的函数指针fp,采用如下格式:
int (*fp)(int a);
函数指针的赋值
前面我们已经讲到,在C语言中,函数名代表了函数的首地址,因此在赋值时,直接将函数名赋值给函数指针就可以了。
例如:
int func(int x); //声明一个函数
int (*fp)(int x); //定义一个函数指针
fp = func; //将func函数的首地址赋值给指针fp
赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针就指向函数func(x)的代码的首地址。
通过函数指针调用函数
与其它指针变量相类似,如果指针变量pi是指向某整型变量i的指针,则*pi等于它所指向的变量i;如果pf是指向某浮点型变量f的指针,则*pf就等价于它所指的变量f。同样地,fp是指向函数func(x)的指针,则*fp就代表它所指向的函数func。所以在执行了fp = func;之后,(*fp)和func代表同一函数。
由于函数指针指向存储区中的某个函数,因此可以通过函数指针调用相应的函数。
用函数指针调用函数由三步组成:
首先,定义函数指针变量。
例如:int (*fp)(int x);
然后,给函数指针变量赋值。
例如:fp = func; (func(x)必须要先有定义)
最后,用(*指针变量)(参数表);调用函数。
例如:(*fp)(x);(x必须先赋值)。
在这里,(*fp)(x);一般写成fp(x); fp(x)是标准C++的写法,(*fp)(x);是兼容C语言的标准写法。
总结以上知识,举例说明
到目前为止,相信您已经简单了解了函数指针,下面我们举一个简单的、完整的程序进行说明。
例1
#include <iostream>
using namespace std;
//定义一个函数add,两个输入参数为整型,返回值为整型
int add(int a,int b)
{
return a+b;
}
//定义一个函数指针变量,该变量所指函数的类型与int add(int,int)相对应。
int (*padd)(int,int);
int main()
{
int a1 = 1;
int b1 = 2;
//函数指针变量赋值,函数指针指向add函数
padd = add;
//通过函数指针变量调用函数,与直接调用add函数效果相同
int c1 = (*padd)(a1,b1);
//也可以写成int c1 = padd(a1,b1);
cout<<c1<<endl;
return 0;
}
编译并运行程序,返回两个数的和3。
函数指针的作用
现在,相信您已经明白了函数指针,但是,您可能会迷惑:函数指针到底有什么作用呢?
函数指针是C++一个重要的组成部分,它的最大好处就是实现函数的回调。
什么是回调函数
函数,我们大家都知道。函数体是为了完成某种功能的一段代码,一般情况下,我们在主程序中直接调用函数,主程序调用函数是为了完成这部分功能,被调用函数完成后立即返回主程序。
函数的调用,我们都知道,那么什么是回调函数,我们什么时候使用回调函数呢?
初次接触回调函数很难理解,我们先通过下面的图示简单地介绍回调函数。
图1
图1,我们很容易理解,它是我们正常调用函数的情况,程序中直接调用函数。
图2
图2的理解就有些费解,首先程序A调用函数1,而函数1本身又调用了程序A自己编写的函数2。函数2就是回调函数。
初次理解回调函数确实有些困难,为了让您弄懂它,我在这里再对图2进行一下解释:
在一般情况下,函数1是由系统完成的。图2 改为下图更容易理解:
图3
我们的程序执行了某项操作,会通知系统,调用系统的函数1执行相应功能,但系统还需调用函数2,函数2的内容是由我们来完成的。
比如,我们按下一个按钮,我们调用系统(也可以说通知系统)完成相应功能,系统首先完成按钮的重画,使其显示为按下状态,同时还要执行按钮被按下后的相应操作。按钮被按下后的操作内容是由用户来完成的,系统是不能确定的,用户可以根据自己的需要填写内容。
现在您明白了回调函数的好处了吧。它由程序开发人员完成其实现内容,而是由系统(或其它函数)调用,它使得我们编程更加方便灵活。
回调函数的实现
回调函数,是通过函数指针实现的。下面我们举一个最简单的通过函数指针实现回调函数的例子:
//下面的例程模拟单击按钮后的回调
//主函数调用的Function_After_Push_Button函数相当于按钮被按下后通知系统的函数
// OnClick函数是回调函数,相当于按钮被按下具体要执行什么操作,其内容由用户根据自己的需要来完成
#include <iostream>
using namespace std;
//定义回调函数OnClick
void OnClick ()
{
cout<<"The Button is Click!"<<endl;
}
//定义一个函数,该函数的输入参数是一个函数指针
void Function_After_Push_Button(void(*pf)())
{
pf();
}
int main()
{
//定义一个函数指针
void (*pf)();
//给函数指针赋值
pf = OnClick;
//实现回调
Function_After_Push_Button(pf);
return 0;
}
上例是一个非常简单的回调函数,但并不能完全体现出回调函数的好处。该例程旨在演示如何使用函数指针实现回调,在实际编程过程中,最常用的还是使用系统规定好的回调函数。
VC++的函数指针和回调函数 及友元函数的更多相关文章
- C语言之函数指针、回调函数的使用
一.背景 首先看下如下代码,这个定义是放在头文件的,在程序中tCdrvCallbackFkt也定义了另一个变量,而且括号后面还跟定义了几个变量,不理解这个定义. typedef void (PUBLI ...
- C语言函数指针和回调函数
彻底搞定C指针-函数名与函数指针 函数名&函数名取地址 函数指针 通常我们可以将指针指向某类型的变量,称为类型指针(如,整型指针).若将一个指针指向函数,则称为函数指针. 函数名的意义 函数名 ...
- C:函数指针、回调函数
函数指针 是一个指针,指向函数的指针,指针存放的都是地址,所以函数指针存放的是函数的地址.数组名就是数组的首地址,函数名就是函数的首地址.与数组类似. 代码demo int (*p) (int ,in ...
- 利用C语言中的函数指针实现c++中的虚函数
C语言中的函数指针 #include<stdio.h> int fun1(int a) { return a*a; } int fun2(int a) { return a*a*a; } ...
- C++成员函数指针错误用法警示(成员函数指针与高性能的C++委托,三篇),附好多评论
今天做一个成绩管理系统的并发引擎,用Qt做的,仿照QtConcurrent搞了个模板基类.这里为了隐藏细节,隔离变化,把并发的东西全部包含在模板基类中.子类只需注册需要并发执行的入口函数即可在单独线程 ...
- 声明函数指针、回调函数、函数对象------c++程序设计基础、编程抽象与算法策略
声明函数指针 #include<iostream> using namespace std; double a(double aa) { return aa; } int main() { ...
- 深入浅出剖析C语言函数指针与回调函数(一)【转】
本文转载自:http://blog.csdn.net/morixinguan/article/details/65494239 关于静态库和动态库的使用和制作方法. http://blog.csdn. ...
- C 函数指针、回调函数
参考链接:https://www.runoob.com/cprogramming/c-fun-pointer-callback.html 函数指针 函数指针就是执行函数的指针,他可以像正常函数一样去调 ...
- C基础知识(6):指针--函数指针与回调涵数
函数指针 函数指针是指向函数的指针变量. 通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数. 函数指针可以像一般函数一样,用于调用函数.传递参数. #include < ...
随机推荐
- Hi3531D搭建环境时,出现的问题
1.展开SDK包得时候,运行./sdk.unpack得时候出现: 原因:ubuntu14.04中默认得是dash,要将dash改成bash. 解决方法:sudo ln -fs /bin/bash /b ...
- CentOS桥接网卡配置
网桥方式配置步骤 1.增加网桥设备br0 vi /etc/sysconfig/network-scripts/ifcfg-br0 DEVICE=br0 ONBOOT=yes TYPE=Bridge B ...
- Android 第三方分享中遇到的问题以及解决方案
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 第三方登录和分享过程中难免遇到各种纠结的问题,下面将我遇到的分享给大家. 先说第三方登录 1.首先要 ...
- 洛谷 P1913 L国的战斗之伞兵
P1913 L国的战斗之伞兵 题目背景 L国即将与I国发动战争!! 题目描述 为了在敌国渗透作战,指挥官决定:派出伞兵前往敌国!然而敌国的风十分强烈,能让伞兵在同一高度不停转悠,直到被刮到一个无风区… ...
- 检查类型是否包含iterator
- java导入大量Excel时报错
在项目中同事遇到一问题,如今给大家分享一下. 在程序里面导入两千多条数据后.程序就报错. 刚開始以为是内存的问题.在经过细致跟踪代码后发现每次都是833行的第三列报错.也就是第一万列.最后在网上找到了 ...
- (MySQL里的数据)通过Sqoop Import HBase 里 和 通过Sqoop Export HBase 里的数据到(MySQL)
Sqoop 可以与HBase系统结合,实现数据的导入和导出,用户需要在 sqoop-env.sh 中添加HBASE_HOME的环境变量. 具体,见我的如下博客: hadoop2.6.0(单节点)下Sq ...
- qgis显示引擎研究(一)
作者:朱金灿 来源:http://blog.csdn.net/clever101 Qgis是一个著名的开源地理信息系统软件.今天研究了一下它的显示那一块,算是有一点眉目了. 在Windows环境下所有 ...
- 00082_Set接口
1.Set接口介绍 (1)Collection中可以存放重复元素,也可以不存放重复元素,那么我们知道List中是可以存放重复元素的.那么不重复元素给哪里存放呢?那就是Set接口,它里面的集合,所存储的 ...
- Codeforces #258 Div.2 E Devu and Flowers
大致题意: 从n个盒子里面取出s多花.每一个盒子里面的花都同样,而且每一个盒子里面花的多数为f[i],求取法总数. 解题思路: 我们知道假设n个盒子里面花的数量无限,那么取法总数为:C(s+n-1, ...