C++之函数指针

题外话:

和函数指针类似的有个指针函数,很简单,顺便提一句。

指针函数就是一个函数,但是它的返回值是指针类型

c 复制代码
int* Add(int a, int b)
{
	int* c = new int;
	
	*c = a + b;
	
	return c;
}

归根结底,指针函数还是一个函数,和普通函数没有什么区别。

函数指针

函数指针是指向函数的指针变量。在C/C++语言中,函数名实际上就是一个函数指针,它存储了函数的入口地址。函数指针的声明和使用方式类似于普通指针。同时函数指针可以调用指向的函数,使函数的调用更加灵活。

函数指针的主要作用是实现回调函数,在程序运行时动态地将某个函数的执行权传递给另一个函数。比如,在处理数据时,可能需要用到很多不同的算法,这时候可以通过函数指针来动态地选择不同的算法进行处理。函数指针还常用于实现动态绑定和动态分发。

函数地址

函数也是有地址的,可以用函数名表示地址或者在函数名前加&表示。

c 复制代码
#include <iostream>
#include <iomanip>

int Add(int a, int b)
{
	return a + b;
}

int main()
{
	std::cout << std::hex << Add << std::endl;
	std::cout << std::hex << &Add << std::endl;

	system("pause");
	return 0;
}

输出:

c 复制代码
00007FF71ADD11FE
00007FF71ADD11FE

可以看到,两种方式的十六进制输出是相同的。

定义函数指针

函数指针的声明如下:

c 复制代码
返回值类型 (*指针变量名)(参数列表);

其中,指针变量名就是函数指针的变量名。

例如:

c 复制代码
// 定义函数指针变量pf
int (*pf)(int a, int b);

有的时候函数的参数列表和返回值比较复杂,每次定义这样的函数指针都要重写一遍比较烦琐。因此可以用类型定义运算符"typedef"为该函数定义一个简单的类型名。有了这样一个类型名之后,就可以用来定义函数指针变量,而不用重写函数参数列表和返回类型。

例如:

c 复制代码
typedef int (*FuncPtr)(int a, int b);
c 复制代码
#include <iostream>
#include <iomanip>

typedef int (*FuncPtr)(int a, int b);

int Add(int a, int b)
{
	return a + b;
}

int main()
{
	// 方法1
	int (*pf)(int a, int b);
	pf = Add;

	std::cout << pf(2, 3) << std::endl;

	// 方法2
	int (*pf1)(int a, int b) = Add;

	std::cout << pf1(2, 3) << std::endl;

	// 方法3
	FuncPtr func = Add;

	std::cout << func(2, 3) << std::endl;

	system("pause");
	return 0;
}

这是函数指针的三种写法以及调用,假设我们的Add函数有多个参数,这种时候使用typedef提前声明非常方便。

回调函数

函数指针常被用于回调函数,回调函数是一种在程序运行过程中通过函数指针来实现的函数调用方式。它的基本思想是将一个函数的地址作为参数传递给另一个函数,在合适的时候调用这个函数来完成一定的任务。

使用回调函数的主要目的是实现代码的灵活性和扩展性,将某个需要在特定事件发生时执行的函数的执行权交给另一个函数。通常,回调函数包括两个步骤:首先,程序需要定义一个回调函数,然后,程序中的某个部分会使用这个回调函数,在特定情况下触发执行。

c 复制代码
#include <iostream>
#include <iomanip>

typedef int (*FuncPtr)(int a, int b);

// 回调函数
int Add(int a, int b)
{
	return a + b;
}

// 使用回调函数的函数
void Test(int a, int b, FuncPtr func)
{
	std::cout << func(a, b) << std::endl;
}

int main()
{
	Test(2, 3, Add);

	system("pause");
	return 0;
}

回调函数用于异步编程示例

c 复制代码
#include <iostream>
#include <thread>
#include <functional>

typedef void (*CallBack)();

// 异步函数
void AsyncFunction(CallBack callback) {
	std::cout << "异步函数开始执行..." << std::endl;

	// 模拟异步操作,等待2秒钟
	std::this_thread::sleep_for(std::chrono::seconds(2));

	std::cout << "异步函数执行完毕。" << std::endl;

	// 调用回调函数
	callback();
}

// 回调函数实现
void CallbackFunction() {
	std::cout << "回调函数被调用。" << std::endl;
}

int main() {
	std::cout << "主函数开始执行。" << std::endl;

	// 调用异步函数,并传递回调函数作为参数
	AsyncFunction(CallbackFunction);

	std::cout << "主函数继续执行。" << std::endl;

	// 模拟主线程继续执行其他任务
	std::this_thread::sleep_for(std::chrono::seconds(3));

	std::cout << "主函数执行完毕。" << std::endl;

	system("pause");
	return 0;
}

输出结果:

c 复制代码
主函数开始执行。
异步函数开始执行...
// 等待2s
异步函数执行完毕。
回调函数被调用。
主函数继续执行。
// 等待3s
主函数执行完毕。

回调函数通常在以下情况下被广泛使用:

1、异步操作:当需要执行异步操作时,回调函数是一种常见的异步通知方式。例如,网络请求、文件读写、定时器等操作都可以在操作完成后使用回调函数进行通知。

2、事件处理:当需要响应特定的事件时,回调函数是一种常见的事件处理方式。例如,用户输入事件、鼠标点击事件、按键事件等都可以使用回调函数的方式进行处理。

3、定制逻辑:当需要定制特定的逻辑时,回调函数可以允许用户自定义代码片段。例如,图形界面库通常会提供一些回调函数用于用户自定义处理窗口关闭、按钮点击等事件。

4、并发处理:当需要处理多个任务并发执行时,回调函数可以用于处理每个任务的完成通知。例如,线程池中的任务完成后会调用回调函数进行处理。

5、插件扩展:当需要扩展现有功能时,回调函数可以被用作插件系统的一种扩展方式。例如,文本编辑器可以提供一些回调函数接口,供插件开发者自定义功能。

相关推荐
程序猿进阶1 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
qq_433618443 分钟前
shell 编程(二)
开发语言·bash·shell
闻缺陷则喜何志丹6 分钟前
【C++动态规划 图论】3243. 新增道路查询后的最短距离 I|1567
c++·算法·动态规划·力扣·图论·最短路·路径
charlie11451419118 分钟前
C++ STL CookBook
开发语言·c++·stl·c++20
袁袁袁袁满18 分钟前
100天精通Python(爬虫篇)——第113天:‌爬虫基础模块之urllib详细教程大全
开发语言·爬虫·python·网络爬虫·爬虫实战·urllib·urllib模块教程
ELI_He99924 分钟前
PHP中替换某个包或某个类
开发语言·php
小林熬夜学编程29 分钟前
【Linux网络编程】第十四弹---构建功能丰富的HTTP服务器:从状态码处理到服务函数扩展
linux·运维·服务器·c语言·网络·c++·http
m0_7482361132 分钟前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
倔强的石头10640 分钟前
【C++指南】类和对象(九):内部类
开发语言·c++
Watermelo61744 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript