您好,登錄后才能下訂單哦!
小編給大家分享一下函數指針和回調函數的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
一. 函數指針
關于函數指針的概念,可以想到一個整型指針指向的是一個整型,它的值是所指向對象的地址;一個字符串指針指向的是一個字符串,它的值是所指向字符串的首地址;因此,一個函數指針當然是一個指針變量了,它所指向的是一個函數,它的值就是所指向函數的入口地址。
函數指針的定義如下:
typedef int data_type; data_type (*pfun)(data_type, data_type);
上面的語句中定義了一個函數指針pfun,它表示指向一個返回值為data_type,參數為兩個data_type類型的函數,上面第一個括號也就是(*pfun)的括號不能省略,否則就會變成:
data_type *pfun(data_type, data_type);
這樣的話就為聲明一個函數名為pfun的函數了,它的返回值為data_type*,參數為兩個data_type類型的參數;
下面舉個栗子說明函數指針的使用:
#include <iostream> using namespace std; typedef int data_type; data_type add(data_type& a, data_type& b) { return (a + b); } int main() { data_type a = 2; data_type b = 3; data_type (*pfun)(data_type&, data_type&); pfun = &add; cout<<pfun(a, b)<<endl; return 0; }
上面的程序中實現了一個函數add,并且定義了一個函數指針pfun指向這個函數,對函數指針的賦值和使用其他指針賦值語句一樣,可以取函數的地址直接賦過去,但是因為函數名作為函數的入口地址,因此也可以不加取地址操作符“&”而直接將函數名賦給函數指針;要注意的是,函數指針的定義中,參數類型、個數和返回值必須和要指向的函數原型中的參數類型、個數和返回值一一對應;
運行程序會得到結果5;
指針在C/C++中是一個很靈活的變量,它可以指向與自己類型相同的不同存儲空間,比如在數組中通常可以用指針來操縱,但這里值得注意的是,在一個數組或者字符串中使用指針進行加減操作會進行相應的移位指向下一個空間,有整型指針數組也就自然會有函數指針數組,它的數組成員都是一個個指向某個函數的函數指針,而在這樣的數組中用指針進行加減操作就指向的是不同的函數指針也就是不同的函數了,單純的對一個函數指針進行加減操作是不能夠的,它并不會指向在當前函數上面或下面定義的某個函數。
像給一個整型指針賦值一樣,可以給一個函數指針賦予不同的函數,這樣就可以靈活的用一個指針來調用不同的函數而不用將每個函數都顯式的寫出來。
二. 回調函數
上面談論的函數指針其實就是在為談回調函數做鋪墊,什么是回調函數?其實回調函數就是函數指針的一種使用,用戶自己定義一個函數,將這個指向這個函數的函數指針作為參數傳遞給一個系統函數或者中間函數,當這個系統函數或中間函數執行的時候調用這個函數指針去執行用戶定義的函數,那么用戶定義的這個函數就叫做回調函數。
為什么會有回調函數呢?難道就不能在一個函數里面直接調用用戶所寫的函數而不是傳參過去嗎?這種直接使用被調用函數的用法是在我們知道調用函數的內部實現機制的情況下直接寫入的,那么,如果調用函數是系統內部函數或者是別人所給的一個函數借口呢?再如果有一種設計需求,要求執行一個函數但并不知道調用該函數的函數是如何操縱的呢?這樣就沒辦法直接在調用函數內部寫入被調用函數了,而是需要傳入一個函數地址,至于該函數是如何調用如何來實現的,我們并不需要關心。
從上面的分析來看,回調函數的使用并不是你傳給我,我調用你,而是還需要有一個起始的函數來調用系統函數或者中間函數將回調函數的地址作為參數給傳過去,可畫圖說明:
圖中的虛線,如果中間函數是系統函數,首先會由起始函數調用系統函數而由用戶態進入內核態去由執行操作系統的函數,然后系統函數內部會執行調用用戶實現的一個callback函數而從內核態再返回到用戶態去執行調用callback函數,我個人認為也可以這么理解回調函數的回調二字,因此虛線是用戶態和內核態的一個劃分;但如果中間函數并不是系統函數,那么就一直會在用戶態而不會接觸到系統內部。
栗子時間:
#include <iostream> using namespace std; void print() { //代碼 cout<<"hello..."<<endl; //代碼 } void say_hello(void (*pfun)(void)) { //代碼 pfun(); //代碼 } int main() { //代碼 say_hello(print); //代碼 return 0; }
上面就是一個再簡單不過的小栗子,注釋掉的代碼就可以是用戶自己其他的實現,而如果栗子中的say_hello函數是系統函數或者是別人傳過來的一個函數接口的話,其內部實現我們是無法干涉和了解的,因此,只需要將我們希望執行的回調函數地址給傳過去,從而完成我們需要回調函數來完成的任務就可以了。
以上是“函數指針和回調函數的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。