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.pswp.cn/news/711937.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/711937.shtml
英文地址,請注明出處:http://en.pswp.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…