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

相关推荐
AI街潜水的八角4 分钟前
基于C++的决策树C4.5机器学习算法(不调包)
c++·算法·决策树·机器学习
q5673152321 分钟前
在 Bash 中获取 Python 模块变量列
开发语言·python·bash
JSU_曾是此间年少34 分钟前
数据结构——线性表与链表
数据结构·c++·算法
许野平1 小时前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
也无晴也无风雨1 小时前
在JS中, 0 == [0] 吗
开发语言·javascript
狂奔solar1 小时前
yelp数据集上识别潜在的热门商家
开发语言·python
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
blammmp2 小时前
Java:数据结构-枚举
java·开发语言·数据结构
何曾参静谧2 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
暗黑起源喵2 小时前
设计模式-工厂设计模式
java·开发语言·设计模式