当前课程知识点:C++语言程序设计基础 > 第6章 数组、指针与字符串(二) > 指针与函数 > 指向函数的指针
指向函数的指针
函数指针的定义
定义形式
存储类型 数据类型 (*函数指针名)();
含义
函数指针指向的是程序代码存储区。
函数指针的典型用途——实现函数回调
通过函数指针调用的函数
例如将函数的指针作为参数传递给一个函数,使得在处理相似事件的时候可以灵活的使用不同的方法。
调用者不关心谁是被调用者
需知道存在一个具有特定原型和限制条件的被调用函数。
函数指针举例
编写一个计算函数compute,对两个整数进行各种计算。有一个形参为指向具体算法函数的指针,根据不同的实参函数,用不同的算法进行计算
编写三个函数:求两个整数的最大值、最小值、和。分别用这三个函数作为实参,测试compute函数
#include <iostream>
using namespace std;
int compute(int a, int b, int(*func)(int, int))
{ return func(a, b);}
int max(int a, int b) // 求最大值
{ return ((a > b) ? a: b);}
int min(int a, int b) // 求最小值
{ return ((a < b) ? a: b);}
int sum(int a, int b) // 求和
{ return a + b;}
int main()
{
int a, b, res;
cout << "请输入整数a:"; cin >> a;
cout << "请输入整数b:"; cin >> b;
res = compute(a, b, & max);
cout << "Max of " << a << " and " << b << " is " << res << endl;
res = compute(a, b, & min);
cout << "Min of " << a << " and " << b << " is " << res << endl;
res = compute(a, b, & sum);
cout << "Sum of " << a << " and " << b << " is " << res << endl;
}
大家好
欢迎回来继续学习
C++语言程序设计
这一节我们来学习
指向函数的指针
什么是指向函数的指针呢
我们前面已经看到例题
已经学习了用了指向数据的指针
比如说我们将一个
已经定义过的变量
它的地址初始化指针
或者赋值给指针
那使得这个指针
就指向了这个变量
指向了这个数据
那实际上呢
我们在运行中的代码
它也是在内存中
占有存储空间的
那么一段段的代码
一个个的函数
它们也是有起始地址的
那接下来我们要讲的
指向函数的指针呢
就是说这个指针里面
容纳的是函数代码的起始地址
那么这个指针就叫做
指向函数的指针
下面我们来看
如何定义一个指向函数的指针
大家看这个指针的定义
在函数指针名前面
有这么一个*
然后有一对括号
把函数指针名和*
仅仅地括在一起
那就说明正在定义的
是一个指针
如果没有这一对括号呢
这样的形式是什么
我们前面学过
是指针类型的函数
说这个函数的返回值是指针
那么所以呢
*和这个函数指针名
外面的这一对括号
是非常重要的
有这一对括号就说明
你定义的是一个指向函数的指针
好 说明这是一个指针
好 除了这个指针以外
左看看 右看看
都是在说
这个指针是指向什么的指针
右边看看有一对圆括号
那是什么
函数参数表啊
说明这个指针
它是一个指向函数的指针
那么为什么左边
还有数据类型啊 这些
这是定义的函数返回类型是什么
所以从这个定义呢
我们可以看出
定义一个指向函数的指针的时候
要规定
这个函数的参数表是什么样的
空的
或者里头有几个什么类型的参数
都要列出来
还有
这个函数的返回值是什么样的
所以定义指针的时候
总要确定它指向对象的类型
我们前面定义指向数据的指针
要确定
它指向的数据类型是什么
现在定义指向函数的指针
要确定它指向的函数
除了函数名以外
函数原型的其他部分是什么样
也就是函数名是由指针
将来由指针来充当了
那么除此而外
参数表是什么样的
函数返回值是什么样的
那都要在这个定义中去确定它
函数指针呢
它指向的是函数
它程序代码的存储区的起始位置
也就是函数代码的首地址
那么大家一定会问
为什么我们需要
指向函数的指针呢
为什么我们要去
存这个函数代码的首地址呢
我们访问函数的时候
都是通过函数名访问的
每个函数它一定是有名字的
那需要函数指针作什么用呢
接下来我们就来看
函数指针它的典型用途
函数指针的典型用途呢
就是实现函数回调
函数回调又是什么呢
就是说通过函数指针
去调用函数
那么为什么有好好的函数名不用
我们要通过函数指针
去调用函数呢
有了函数指针
我们就可以将函数指针
作为参数传递给另外一个函数
使得在处理相似的事件的时候
可以灵活地使用不同的方法
那么这样做的好处就是
调用者
就是那个主调函数 调用者
它不用关心谁是被调用者
只需要知道存在一个
具有特定原型
和特定限制条件的被调函数
就可以了
那这里呢
我们通过这样一个例子
让大家清楚什么是函数回调
它的好处是什么
比如说
我们需要编写一个计算函数
compute
对两个整数进行各种计算
两个整数可以有很多计算
比如说加减乘除运算
比如说求最大值 最小值等等
可以有很多种运算
整数的运算种类有很多
那么这个compute函数呢
我们希望它是一个通用的函数
可以对两个整数
做各种各样的计算
那么一个函数怎么能保证它
对整数做各种各样的计算呢
这个时候我们就在
compute函数的形参中
设一个函数指针作参数
那么真正等你调用这个
compute函数的时候
每次你调用它可能目的不同
这次要作加法
下次要求最大值
再下次要求最小值 对吧
每次你调用compute函数的时候
如果目的不同
你可以传给它一个
不同的函数地址 函数指针
比如说我将
求最大值的函数
函数名传给它
用函数名
去初始化形参的函数指针
或者下一次我将求和的函数
函数名传给它
这样的话
我们写compute函数的时候呢
就只管说
我要调用一个
对两个整数进行运算的函数
至于说到底做什么运算
运行时
你把代表这个运算的函数名
传给我
我用函数指针来接收
然后用函数指针充当函数名
去调用这个函数体
这就是函数指针的好处
也就是所谓函数回调
下面呢
我们就来看这个例题的原代码
我们在这里定义了一个
compute函数
希望它能执行
特别通用的计算功能
什么计算都能做
反正是两个整数的计算
都希望它能做
那怎么达到这一点呢
首先
要做两个整数的计算
得有两个整数传进来
两个形参a和b
接受要进行计算的两个整数
那接下来第三个参数是什么呢
是一个指向函数的指针
这个指针所指向的函数原型
应该是什么呢
返回值是int类型的
参数是两个int类型的
必须要求是这样的
那接下来呢
我们要实验一下
让这个compute函数做各种计算
各种
当然是很多种了
我们这里只举三个简单例子
一个是求两个数的最大值
一个是求两个数的最小值
还有求和这三个运算
这都准备好了以后
主函数中
定义变量
并且从键盘输入两个整数值
准备好
定义好这个存放结果的这个值
然后调用compute函数
第一次调用的时候
给它a b
这是必须给的
接下来呢 将什么给它呢
将刚才这个最大值函数的函数名
作为参数传过去了
这个函数名
前面加一个地址运算符
如果光写函数名
不写地址运算符也是可以的
函数名也代表它的地址
写上地址运算符
就比较清楚
我们是传这个函数的地址
这种写法更清晰
但都是对的
传函数的首地址过去以后
传到哪儿去了呢
传给这个compute函数了
于是这个指针
就指向了max
最大值函数的代码
用它直接当函数名用
就调用了求最大值函数的函数体
计算了a b的最大值返回了
同样地道理
后面调用呢
在传最小值函数的首地址
求和函数的首地址
每次传给它不同函数的首地址
这个函数指针就可以充当
不同的函数名来用
去调用相应的函数体功能
这就实现了一个函数回调的功能
-导学
--第1章导学
-计算机系统简介
--计算机系统简介
--计算机系统简介 测试题
-计算机语言和程序设计方法的发展
--计算机语言和程序设计方法的发展 测试题
-面向对象的基本概念
--面向对象的基本概念 测试题
-程序的开发过程
--程序的开发过程
--程序的开发过程 测试题
-信息的表示和储存
--计算机的数字系统
--数据的编码表示
--信息的表示和储存 测试题
-实验指导
-导学
--第二章导学
-C++语言概述
--C++语言概述 测试题
-基本数据类型、常量、变量
--程序举例
--基本数据类型、常量、变量 测试题
-运算与表达式
--运算与表达式 测试题
-实验二:简单程序设计(上)
-数据的输入和输出
--数据的输入和输出
--数据的输入和输出 测试题
-选择结构
--if语句
--switch语句
--选择结构 测试题
-循环结构
--for语句
--循环结构 测试题
-自定义类型
--自定义类型
--自定义类型
-第2章小结
--第二章小结
-实验二:C++简单程序设计(下)
-导学
--导学
-函数定义
--函数定义
--函数定义 测试题
-函数调用
--例3-2
--例3-3
--例3-4
--例3-5
--例3-6
--函数调用 测试题
-嵌套与递归
--例3-9
--例3-10
--嵌套与递归 测试题
-函数的参数传递
--函数的参数传递
--函数的参数传递 测试题
-引用类型
--引用类型 测试题
-含有可变参数的函数
--含有可变参数的函数 测试题
-内联函数
--内联函数 测试题
-constexpr函数
--CONSTEXPR函数课后习题
-带默认参数值的函数
--带默认参数值的函数 测试题
-函数重载
--函数重载 测试题
-C++系统函数
--C++系统函数习题
-第3章小结
--第三章小结
-实验三(上)函数的应用
-实验三(下)函数的应用
-导学
--导学
-面向对象程序的基本特点
--面向对象程序的基本特点 测试题
-类和对象
--类和对象的定义
--类和对象 测试题
-构造函数
--构造函数基本概念
--委托构造函数
--复制构造函数
--构造函数 测试题
-析构函数
--析构函数
--析构函数 测试题
-类的组合
--类的组合
--类的组合程序举例
--前向引用声明
--类的组合 测试题
-UML简介
--UML简介
--UML简介课后习题
-结构体与联合体
--结构体与联合体 测试题
-枚举类
--枚举类
--枚举类 测试题
-第4章小结
--第四章小结
-实验四(上)
--实验四(上)
-实验四(下)
--实验四(下)
-导学
--导学
-标识符的作用域与可见性
--标识符的作用域与可见性 测试题
-对象的生存期
--对象的生存期
--对象的生存期 测试题
-类的静态成员
--类的静态成员 测试题
-类的友元
--类的友元 测试题
-共享数据的保护
--共享数据的保护 测试题
-多文件结构和预编译命令
--多文件结构和预编译命令 测试题
-第5章小结
--小结
-实验五
--实验五
-导学
--导学
-数组的定义与初始化
--数组的定义与使用
--一维数组应用举例
--数组的定义与初始化 测试题
-数组作为函数的参数
--数组作为函数的参数 测试题
-对象数组
--对象数组
--对象数组 测试题
-基于范围的for循环
-指针的定义和运算
--指针的定义和运算 测试题
-综合实例
--综合实例
-实验六(上)
--实验六上
-指针与数组
--指针数组
--指针与数组 测试题
-指针与函数
--指针类型的函数
--指向函数的指针
--指针与函数 测试题
-对象指针
--对象指针
--对象指针 测试题
-动态内存分配
--动态内存分配 测试题
-智能指针
--智能指针
-vector对象
--vector对象
--vector对象 测试题
-对象复制与移动
--移动构造
--对象复制与移动 测试题
-字符串
--C风格字符串
--string类
--字符串 测试题
-第6章小结
--第六章小结
-综合实例
--综合实例
-实验六(下)
--实验六(下)