c++函数指针 回调函数

 

目录

函数指针

​编辑

实例

函数指针作为某个函数的参数

实例

 std::function轻松实现回调函数

绑定一个函数

作为回调函数

 作为函数入参



函数指针

函数指针是指向函数的指针变量。

通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。

函数指针可以像一般函数一样,用于调用函数、传递参数。

函数指针类型的声明:

typedef type (*fun_ptr)(type,type); // 声明一个指向同样参数、返回值的函数指针类型

实例

以下实例声明了函数指针变量 p,指向函数 max:

#include <stdio.h>
#define  _CRT_SECURE_NO_WARNINGS
typedef int(*func_ptr)(int, int);int max(int x, int y)
{return x > y ? x : y;
}int main(void)
{//p是指向max的函数指针func_ptr p = &max;//也可以写成 func_ptr p = max;int a, b, c, d;printf("请输入三个数字:");scanf("%d %d %d", &a, &b, &c);/* 与直接调用函数等价,d = max(max(a, b), c) */d = p(p(a, b), c);printf("最大的数字是: %d\n", d);return 0;
}

函数指针作为某个函数的参数

函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。

简单讲:回调函数是由别人的函数执行时调用你实现的函数。

以下是来自知乎作者常溪玲的解说:

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。

实例

实例中 populate_array() 函数定义了三个参数,其中第三个参数是函数的指针,通过该函数来设置数组的值。

实例中我们定义了回调函数 getNextRandomValue(),它返回一个随机值,它作为一个函数指针传递给 populate_array() 函数。

populate_array() 将调用 10 次回调函数,并将回调函数的返回值赋值给数组。


#include <stdlib.h>
#include <stdio.h>void populate_array(int* array, size_t arraySize, int (*getNextValue)(void))
{for (size_t i = 0; i < arraySize; i++)array[i] = getNextValue();
}// 获取随机值
int getNextRandomValue(void)
{return rand();
}int main(void)
{int myarray[10];populate_array(myarray, 10, getNextRandomValue);//函数的名称就是函数的地址for (int i = 0; i < 10; i++) {printf("%d ", myarray[i]);}printf("\n");return 0;
}

 std::function轻松实现回调函数

#include <functional>
#include <iostream>struct Foo
{Foo(int num) : num_(num) {}void print_add(int i) const { std::cout << num_ + i << '\n'; }int num_;
};void print_num(int i)
{std::cout << i << '\n';
}struct PrintNum
{void operator()(int i) const{std::cout << i << '\n';}
};int main()
{// store a free functionstd::function<void(int)> f_display = print_num;f_display(-9);// store a lambdastd::function<void()> f_display_42 = []() { print_num(42); };f_display_42();// store the result of a call to std::bindstd::function<void()> f_display_31337 = std::bind(print_num, 31337);f_display_31337();// store a call to a member functionstd::function<void(const Foo&, int)> f_add_display = &Foo::print_add;const Foo foo(314159);f_add_display(foo, 1);f_add_display(314159, 1);// store a call to a data member accessorstd::function<int(Foo const&)> f_num = &Foo::num_;std::cout << "num_: " << f_num(foo) << '\n';// store a call to a member function and objectusing std::placeholders::_1;std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);f_add_display2(2);// store a call to a member function and object ptrstd::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);f_add_display3(3);// store a call to a function objectstd::function<void(int)> f_display_obj = PrintNum();f_display_obj(18);auto factorial = [](int n){// store a lambda object to emulate "recursive lambda"; aware of extra overheadstd::function<int(int)> fac = [&](int n) { return (n < 2) ? 1 : n * fac(n - 1); };// note that "auto fac = [&](int n) {...};" does not work in recursive callsreturn fac(n);};for (int i{5}; i != 8; ++i)std::cout << i << "! = " << factorial(i) << ";  ";std::cout << '\n';
}

绑定一个函数

#include <functional>
#include <iostream>//普通函数
void func(void)
{std::cout << __FUNCTION__ << std::endl;
}
//静态类成员函数
class Foo
{
public:static int foo_func(int a){std::cout << __FUNCTION__ << "(" << a << ") ->:";return a;}
};int main(void)
{std::function<void(void)> fr = func;fr();std::function<int(int)> fr1 = Foo::foo_func;std::cout << fr1(456) << std::endl;
}

作为回调函数

#include <functional>
#include <iostream>
class A
{
std::function<void()> callback_;
public:A(const std::function<void()>& f) :callback_(f) {};
void notify(void)
{callback_();}
};
class Foo {
public:
void operator()(void)
{
std::cout << __FUNCTION__ << std::endl;}
};
int main(void)
{Foo foo;
A aa(foo);aa.notify();
}

 作为函数入参

#include <functional>
#include <iostream>
void call_when_even(int x, const std::function<void(int)>& f)
{
if (!(x & 1)){f(x);}
}
void output(int x)
{
std::cout << x << " ";
}
int main(void)
{
for (int i = 0; i < 10; ++i){call_when_even(i, output);}
std::cout << std::endl;
}

一些AI给出的回答

`std::function`是C++标准库中的一个通用、可调用、多态的函数封装器,可以用来存储任何可调用对象的引用,如函数指针、函数对象、Lambda表达式等。它的主要作用是将函数作为参数传递,实现回调函数的功能。

下面是一个简单的实例,演示了如何使用`std::function`存储一个函数,并调用它:` 

 

在这个例子中,我们定义了

#include <iostream>
#include <functional>void print_hello() {std::cout << "Hello, world!" << std::endl;
}int main() {std::function<void()> func = print_hello;func();return 0;
}

一个名为`print_hello`的函数,用于打印"Hello, world!"。然后,我们创建了一个`std::function<void()>`类型的变量`func`,并将`print_hello`函数的地址赋值给`func`。最后,我们调用`func`,输出"Hello, world!"。

在C++中,`std::function`是一个通用、可调用、多态的函数封装器,可以用来存储任何可调用对象的引用,如函数指针、函数对象、Lambda表达式等。`std::function`的模板参数`T`表示存储的函数的参数类型,当`T`是一个函数指针类型时,`std::function`可以用来存储一个函数指针;当`T`是一个函数对象类型时,`std::function`可以用来存储一个函数对象;当`T`是一个Lambda表达式类型时,`std::function`可以用来存储一个Lambda表达式。

下面是一些例子:

// 存储一个接受两个int参数的函数
std::function<int(int, int)> func1;// 存储一个接受一个int参数并返回一个int的函数
std::function<int(int)> func2;// 存储一个不接受任何参数的函数
std::function<void()> func3;// 存储一个Lambda表达式
std::function<int(int)> func4 = [](int x) { return x * 2; };

在这些例子中,`func1`和`func2`可以用来存储任何接受相应参数类型的函数,`func3`可以用来存储任何不接受任何参数的函数,`func4`可以用来存储一个接受一个int参数并返回一个int的Lambda表达式。


 

#include <iostream>
#include <functional>class A {
public:A(const std::function<void()>& f) :callback_(f) {};void print() {callback_();}private:std::function<void()> callback_;
};int main() {A obj([&]() {std::cout << "Hello, World!" << std::endl;});obj.print();return 0;
}

在这个例子中,我们定义了一个名为A的类,它有一个构造函数,接受一个名为callback_的std::function<void()>类型的参数。我们还定义了一个名为print的方法,用于调用callback_函数。在main函数中,我们创建了一个A类的对象,并将一个Lambda表达式作为其构造函数的参数传递。然后我们调用obj的print方法,输出"Hello, World!"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/711937.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

证券相关业务知识

证券相关业务知识 LOF交易回售业务触发条件 股票代码区分融券专户竞价交易与大宗交易一级市场和二级市场ETF交易融资融券交易&#xff08;两融&#xff09;融券强平转托管簿记和预簿记期权权证股票板块 LOF交易 LOF&#xff0c;即上市型开放式基金&#xff08;Listed Open-End…

【Java】UWB高精度工业定位系统项目源代码

目录 UWB技术原理 优势 1. 高精度&#xff1a; 2. 抗干扰能力强&#xff1a; 3. 定位范围广&#xff1a; 4. 实时性强&#xff1a; 应用前景 定位系统源码功能介绍 实时定位&#xff1a; 轨迹回放&#xff1a; 区域管理&#xff1a; 巡检管理: 数据可视化分析&…

BAT等大厂必问技术面试题,2024Android开发面试解答之设计模式

IT行业薪水高&#xff0c;这是众所周知的&#xff0c;所以很多人大学都选择IT相关专业&#xff0c;即使非该专业的人&#xff0c;毕业了也想去一个培训机构镀镀金&#xff0c;进入这一行业。 但是有关这个行业35岁就退休的说法&#xff0c;也一直盛传。 加上这几年不断有各大…

回溯 Leetcode 47 全排列II

全排列II 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 Leetcode 47 学习记录自代码随想录 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2], [1,2,1], [2,1,1]] 示例 2&#xff1a; 输入&#xff1…

Unity3d Shader篇(十)— 渐变纹理

文章目录 前言一、什么是Unlity渐变纹理Shader&#xff1f;1. 渐变纹理Shader工作原理2. 渐变纹理&#xff1f;3. 渐变纹理的优缺点优点&#xff1a;缺点&#xff1a; 4. 渐变纹理例图 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函…

Linux下的GDB

1.前言 GDB是Linux下非常好用且强大的调试工具。GDB可以调试C、C、Go、java、 objective-c、PHP等语言。对于一名Linux下工作的c/c程序员&#xff0c;GDB是必不可少的工具 2.GDB使用帮助 GDB命令拥有较多内部命令。在gdb命令提示符下输入help可以查看所有内部命令及使用说明 …

Mediapipe笔记:安装Mediapipe+手部检测+动作识别

Mediapipe 安装Mediapipe 打开Anaconda prompt检查环境和python运行环境是否一致(默认base环境&#xff0c;不用切换)输入命令行pip install mediapipe0.9.1.0 -i https://pypi.tuna.tsinghua.edu.cn/simple Mediapope完成手部关键点检测 手部检测 创建对象(加载模型参数)…

(二十二)devops持续集成开发——jenkins服务代理Agent搭建

前言 在Jenkins 中&#xff0c;代理&#xff08;Agent&#xff09;是一种用于执行构建、部署和其他任务的计算节点。代理节点可以是物理机器、虚拟机或容器&#xff0c;它们负责接收 Jenkins 主控节点委派的任务并执行这些任务。通过使用代理节点&#xff0c;可以有效地分担Je…

Redis内存淘汰策略详解

Redis作为一个高性能的键值对数据库&#xff0c;被广泛应用于各种需要快速响应和持久存储的场景中。然而&#xff0c;由于其内存存储的特性&#xff0c;当Redis的内存使用达到其最大配置限制时&#xff0c;就需要有一种策略来管理内存的使用&#xff0c;以避免内存溢出。这就是…

NLP Seq2Seq模型

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制]\n&#x1f680; 文章来源&#xff1a;[K同学的学习圈子](https://www.yuque.com/mi…

深入理解Linux线程(LWP):概念、结构与实现机制(2)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;会いたい—Naomile 1:12━━━━━━️&#x1f49f;──────── 4:59 &#x1f504; ◀️ ⏸ ▶️ ☰ &a…

Vue3+vite打包后页面空白问题

vite.config.js vite.config.js 增加 base: ./ import { fileURLToPath, URL } from node:url import { defineConfig } from vite import vue from vitejs/plugin-vue// https://vitejs.dev/config/ export default defineConfig({base: ./,resolve: {alias: {: fileURLToPath…

解析短视频美颜SDK:美颜美型技术的深度剖析

美颜并非简单的滤镜叠加&#xff0c;而是依托着先进的图像处理和人工智能技术&#xff0c;才能够达到如此出色的效果。本文将深入探讨短视频美颜SDK背后的技术原理和实现方法&#xff0c;从而揭示其美颜美型技术的深度剖析。 一、美颜SDK的基本原理 美颜SDK的基本原理是通过对…

maven 包管理平台-01-maven 入门介绍 + Maven、Gradle、Ant、Ivy、Bazel 和 SBT 的详细对比表格

拓展阅读 maven 包管理平台-01-maven 入门介绍 Maven、Gradle、Ant、Ivy、Bazel 和 SBT 的详细对比表格 maven 包管理平台-02-windows 安装配置 mac 安装配置 maven 包管理平台-03-maven project maven 项目的创建入门 maven 包管理平台-04-maven archetype 项目原型 ma…

docker单机启动mysql、redis容器命令

将your_path、your_password、your_version替换成自己需要的 mysql docker run -d -p 3306:3306 --name mysql --restartalways \ -v /your_path/my.cnf:/etc/mysql/my.cnf \ -v /your_path/log:/logs \ -v /your_path/mysql:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORDyour_pa…

java 企业培训管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 企业培训管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

UCWSC

feature fusion neural network based on a decomposition mechanism (FFDM) 辅助信息 作者未提供代码

学习大数据,所必需的java基础(6)

文章目录 集合Set集合介绍HashSet集合的介绍和使用LinkedHashSet的介绍以及使用哈希值哈希值的计算方式HashSet的存储去重的过程 Map集合Map的介绍HashMap的介绍以及使用HashMap的两种遍历方式方式1&#xff1a;获取key&#xff0c;然后再根据key获取value方式2&#xff1a;同时…

【Sql Server】Update中的From语句,以及常见更新操作方式

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

Docker技术概论(4):Docker CLI 基本用法解析

Docker技术概论&#xff08;4&#xff09; Docker CLI 基本用法解析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:http…