我们先简单聊一下函数指针的背景,具体使用请参考我的这篇博客
成都创新互联是一家专业提供平邑企业网站建设,专注与成都网站设计、成都网站建设、H5场景定制、小程序制作等业务。10年已为平邑众多企业、政府机构等服务。创新互联专业网站设计公司优惠进行中。C++ :函数: 函数指针_hongwen_yul的博客-博客
假设现在有这样一段代码:C/C++中可以使用指针指向一段代码,这个指针就叫函数指针,假设有这样一段代码、
// main.cpp
#includeint func(int a) {
return a+1;
}
int main(){
int (*f)(int) = func;
printf("%p",f);
}
// 打印结果 :400526
我们定义一个函数 func() ,然后使用指针变量 f 指向该函数,然后打印该变量f 指向的地址,代码是很简单的,然后我们编译一下,看下编译后生成的指令,接下来我们重点关注fuc 函数:
可以看到,编译好的函数 func 位于地址 ox400526,然后我们运行下编译好的程序,发现输出的数据和编译后的地址是一致的,这个指针变量保存了函数func 的机器指令。
所以说明:函数指针本质上也是一个指针,只不过这个指针指向的不是内存中的一段数据,而是内存中的一段代码。
有的同学可能会有疑问,:为什么编译器在生成可执行文件时就知道函数 func 存放在内存地址 0x400526上了?这不是应该是程序被加载到内存后开始运行时,才能确定的吗?
答案就在函数指针:可以把一段代码当做一个变量传来传去,这个变量保存了这段代码地址,它的主要用途之一就是 回调函数,关于回调函数,你可以参考我的这篇文章。
C++:函数:回调函数:还不懂回调函数来捶我_hongwen_yul的博客-博客q回调函数------函数指针https://blog.csdn.net/u013620306/article/details/128009205?spm=1001.2014.3001.5501
其实回调函数就是这样的
2:函数指针的衍生上面我们说到,可以定义一个指针变量来保存函数地址,但是了,假如我们我们的场景在复杂点:
我们依然需要在模块A中定义函数,同时运行模块A 需要依赖模块B产生的数据,然后将模块A定义的函数和模块B产生的数据一并传递给模块C来调用,就像这样:
很显然单纯的函数指针已经不够用了,因为函数指针只是单纯的指向了内存中的一段代码,但是我们不仅需要将内存的一段代码同时也需要内存中的一块数据,一并传递给模块C。
那么如何实现上面的功能了? 你可以定义一个结构体,将代码和数据打包起来、
typedef void (*func) (int);
struct closure{
func f;
int arg;
};
我们将这个结构体命名为 :closure 这个结构体中包含两部分
这样,我们在模块A 为指针变量赋值,在模块B为保存数据的变量赋值,然后将此结构体传递给模块C ,模块C中可以这样使用。
void run(struct functor func) {
func->f(func->arg);
}
closure既包含了一段代码也包含了这段代码使用的数据,这里的数据称为context (函数运行依赖的数据),这个技术就是:Functor 。(就是说:单纯的函数指针并没有捕捉上下文的能力,这里的上下文就是指代码依赖的数据,你不得不自己动手构造一个结构体用来存储代码依赖的上下文。)
有的同学又会问了:为什么不用函数指针来指向对象的成员函数,这是因为函数指针没有办法捕捉 this (指向对象的指向) 这个上下文 。 (原因我后面在讲,这个不是本文的重点)
3:std::Function好像还是不能理解?没关系,我们一步一步带领大家去理解,大家先对 std::Function有一个概念性的认识。
3.1:先想一想:C++怎样定义指向对象成员函数的指针参考我的这篇博文
C++:函数指针进阶二:指向对象成员函数的指针_hongwen_yul的博客-博客
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧