C++:函数指针和返回函数指针的函数
函数指针 & 返回函数指针的函数
一、函数指针的声明和使用
声明一个函数指针,给它赋值并调用它指向的函数
函数指针就是一个指向函数的指针。
先来简单看一下怎么使用函数指针。我们声明一个函数,和一个指向该函数类型的指针,让指针指向该函数并通过指针调用它。
#include<iostream>
using namespace std;
//定义一个返回值为int、参数表为(char,double)的函数
int func(char c, double d) {
cout << c << " = " << d << endl;
return 0;
}
int main() {
//p_int是一个指向返回值为int、参数表为(char,double)的函数的指针
int (*p_int)(char, double);
//让p_int指向函数func
p_int = &func;
//通过函数指针p_int调用func
(*p_int)('A',3.14);
return 0;
}
输出结果:A = 3.14
可以这样描述p_int
:它指向一个返回值为int
、参数表为(char,double)
的函数。声明函数指针的句子是int (*p_int)(char, double)
,我们可以这样理解它:
-
p_int
前面的*说明它是一个指针 -
(*p_int)
的右侧是一个形参表,这说明该指针指向一个函数 -
(*p_int)
的左侧是int
,这说明该指针指向的返回值是int
类型
注意(*p_int)
两侧的括号不能省略,否则句子就会变成int *p_int(char,double)
,这是一个函数,函数名为p_int,返回值是一个int型指针。
当p_int
的值为0
或nullptr
时,说明它不指向任何函数。
等价的表达
(1)在给函数指针赋值时,以下语句作用是相同的:
p_int = &func;
p_int = func;
第一个的句子意义很显然:把函数func
的地址赋给p_int
;而由于我们把函数名当作一个值使用时,它会自动地转换成指针,则第二个的句子也做了一样的事情。
(2)在使用函数指针调用函数时,以下语句作用是相同的:
(*p_int)('A',3.14);
p_int('A',3.14);
不论是对p_int
解引用还是直接使用p_int
,都可以成功地调用它指向的函数。
二、函数指针作为形参传递
函数的形参列表中不能定义函数类型的形参,所以要把一个函数作为另一个函数的参数需要使用函数指针类型的形参:
#include<iostream>
using namespace std;
//定义一个返回值为int、参数表为(char,double)的函数
int func(char c, double d) {
cout << c << " = " << d << endl;
return 0;
}
//定义一个函数,形参列表中包含func这一类型的函数
void use_pointer_of_func(char c, double d,int (*p)(char,double)) {
p(c,d);
}
int main() {
//把func作用参数调用
use_pointer_of_func('A', 3.14, &func);
//写作use_pointer_of_func('A', 3.14, func)也是可以的
}
在函数use_pointer_of_func
的形参列表中,int (*p)(char,double)
就是一个函数指针类型的形参。然而如果(*p)
指向的函数形参列表很长,如int (*p)(char,double,double,double,char,char,char.......)
,这时候可以用decltype
和typedef
来简化语句:
typedef decltype(func) *F;
//写作typedef int (*F)(*char c, double d)也是等价的
void use_pointer_of_func(char c, double d, F) ......
更改后代码如下:
#include<iostream>
using namespace std;
//定义一个返回值为int、参数表为(char,double)的函数
int func(char c, double d) {
cout << c << " = " << d << endl;
return 0;
}
typedef decltype(func)* F;
//写作typedef int (*F)(*char c, double d)也是等价的
//定义一个函数,形参列表中包含func这一类型的函数
//F是func类型的函数指针的别名
void use_pointer_of_func(char c, double d, F p) {
p(c, d);
}
int main() {
//把func作用参数调用
use_pointer_of_func('A', 3.14, &func);
//写作use_pointer_of_func('A', 3.14, func)也是可以的
}
三、返回值为函数指针类型的函数
以上说了函数本身不能作为形参,同样的,函数也不能作为返回值,但是我们可以返回指向函数的指针。以下是一个名为f
的函数,它的参数表是(string)
,它返回一个函数指针,指向一个参数表为(char,double)
返回值为int
的函数:
int (*f(string))(char, double);
我们来理解一下这个语句:
-
f
有形参列表(string)
,所以f
是一个输入参数为一个字符串的函数 -
f
前面有*
,说明f
返回的是一个指针 - 指针
(*f(int))
右侧有形参列表(char, double)
,说明f
返回的指针指向一个函数,(char, double)
是该函数的形参表。 - 最左边的
int
说明被指向的函数返回值是int
类型
上面的写法有点绕,我们可以用using
来简化它:
using F = int(char,double);
F *f(string);
该写法与int (*f(string))(char, double)
等价,并且含义较容易理解:函数f
读入一个string
参数返回一个F*
类型的值,而F
是一个读入参数表(char,double)
,返回一个int
的函数。
你也可以直接把F
作为函数指针:
using F = int(*)(char,double);//F是函数指针类型
F f(string);//f的返回类型是函数指针
推荐阅读
-
导数的四次运算和复合函数的求导
-
用于 Python 机器学习的函数极限和导数 高等数学文章
-
关于反射机制(方法和构造函数)的 JAVA 注释
-
构造函数和析构函数方法的区别
-
深入研究 C 语言中的函数指针和左右规则
-
基于 RBF 神经网络和滑膜控制的风力涡轮机系统状态观测和故障估计,RBF 由 S 函数实现
-
C++ 构造函数和析构函数
-
C++ 仿函数外设和封装器 - 绑定函数
-
35 岁实现财务*,腾讯程序员手握2300万提前退休?-1000万房产、1000万腾讯股票、加上300万的现金,一共2300万的财产。有网友算了一笔账,假设1000万的房产用于自住,剩下1300万资产按照平均税后20-50万不等进行计算,大约花上26-60年左右的时间才能赚到这笔钱。也就是说,普通人可能奋斗一辈子,才能赚到这笔钱。在很多人还在为中年危机而惶惶不可终日的时候,有的人的35岁,就已经安全着陆,试问哪个打工人不羡慕?但问题是有这样财富积累必然有像样的实力做靠山。没有人可以不劳而获。 看到这里,肯定有人说,那么对于普通人来说,卷可能真就成了唯一的出路。但是卷也有轻松的卷,“偷懒”的卷法,对于程序员而言,刨除掉一时无法改掉的开会传统占用的大部分时间,如何把有限的时间和精力放在真正重要的架构设计、需求设计上,而不是重复的造*,编码、改bug、手动测试。因此在科技改变生活的今天,学会使用AI工具成为程序员们的必备技能。 以全栈式全自动的软件开发工具飞算SoFlu软件机器人为例,作为全球首款面向微服务架构设计和最佳实践的软件机器人,SoFlu软件机器人改变了原来手工编码的作业模式,通过可视化拖拽方式以及参数配置就能实现等同于编写复杂代码的业务逻辑,在设计业务逻辑时就完成了微服务应用开发,做到“业务即图,图即代码”,实现“软件开发,十倍提效”。 而作为飞算SoFlu软件机器人的一个重要组成部分,FuncGPT(慧函数)支持所有类型函数创建。通过自然语言描述Java函数需求,实时生成高质量、高可读性的Java函数代码。生成代码可直接复制到IDEA,或一键导入Java全自动开发工具函数库。 FuncGPT(慧函数)具有五大核心能力: ● 自然语言:通过自然语言即可生成函数,降低软件开发门槛。 ● 秒级函数开发:全自动秒级开发函数,秒级完成,效率千倍提升。 ● 一站式函数开发应用:函数生成即可直接应用,效率、安全有保障。 ● 质量可靠:生成的函数代码符合业界规范、具备良好的可读性,符合最优解。 ● 灵活生成:可以根据开发人员的具体需求生成并支持调整和修改。 以“将文件流转换为File对象”这个需求为例,以下是FuncGPT(慧函数)秒级生成的代码: / 类名:FileConverter // 函数名:convertStreamToFile // 函数功能:将文件流转换为File对象 // POM依赖包:无 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class FileConverter { /** * 将文件流转换为File对象 * @param inputStream 文件流 * @param filePath 文件路径 * @param fileName 文件名 * @return 转换后的File对象 * @throws IOException 如果发生I/O异常 */ public static File convertStreamToFile(InputStream inputStream, String filePath, String fileName) throws IOException { File file = new File(filePath + File.separator + fileName); // 创建File对象 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 创建文件输出流 byte buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { // 从文件流读取数据并写入文件 outputStream.write(buffer, 0, bytesRead); } } return file; // 返回转换后的File对象 } } // 函数示例 // 将文件流转换为File对象示例 // 入参:inputStream,文件流 // 入参:filePath,文件路径 // 入参:fileName,文件名 // 出参:file,转换后的File对象 // 调用示例: // InputStream inputStream = new FileInputStream("example.txt"); // String filePath = "C:\\Users\\User\\Documents"; // String fileName = "example.txt"; // File file = FileConverter.convertStreamToFile(inputStream, filePath, fileName); // System.out.println(file.getAbsolutePath); // 输出结果:例如,将文件流转换为File对象后,文件的绝对路径为:C:\Users\User\Documents\example.txt // 则输出结果为:C:\Users\User\Documents\example.txt 通过分析,不难发现以上代码:
-
Power Pivot 函数 - 智能时间函数 DateAdd 的用法和区别