色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

介紹在C++中實現回調的幾種方法

冬至子 ? 來源:技術鋪子 ? 作者: chasenzhang ? 2023-01-18 15:09 ? 次閱讀

從C的回調函數說起

C語言中,回調函數是一個非常重要的概念,它的定義

回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。

回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。

其實說白了就是把一個函數當做參數傳下去。

C中實現回調函數比較簡單,請看下面這個例子:

#include 


typedef void (*p_CB)(int);
void CB(int a)              { printf("CB a = %d\\n", a); }
void runCB(p_CB CB, int a)  { printf("run CB\\n"); CB(a); }


int main()
{
    p_CB cb = &CB;
    runCB(cb, 20);
    return 0;
}

C++中的回調函數的問題

在C++中的一個重要概念就是類,所以我們一般想讓類的成員函數作為回調函數(如果直接用非類的成員函數作為回調函數,其實就和C語言中的方法一樣),但是想實現這樣的功能,還是存在一些限制的。

主要原因是,類的成員函數的參數都隱藏了this指針這個參數,既然多加了一個參數,那么成員函數的參數個數就和定義的回調函數個數不匹配,導致調用失敗。

舉個例子:

#include 


typedef void (*p_CB)(int);
void runCB(p_CB CB, int a) { printf("run CB\\n"); CB(a); }


class B
{
public:
    void CB(int a) { printf("CB a = %d\\n", a); }
};


int main()
{
    B b;
    runCB(B::CB, 20); //錯誤
    return 0;
}

我們這樣寫,在15行會報下面的錯誤。

test_class_cb.cpp: In functionint main()’:
test_class_cb.cpp:15:14: error: invalid use of non-static member functionvoid B::CB(int)’
     runCB(B::CB, 20); //錯誤

報的錯說使用了非靜態的函數,分析下原因,其實是B::CB的函數是非靜態成員函數,它隱藏了this參數,導致p_CB和B::CB這兩個函數的參數不匹配。

而編譯器報的這個錯誤,其實也是同樣的意思,編譯器說我們調用的不是非靜態函數,當我們把B::CB定義成靜態函數也就不會報錯了(也就是去掉了this指針)。

C++中的回調函數的實現

靜態函數

既然成員函數都會存在this指針,那么我們可以去掉this指針呢?其實是可以的,我們把成員函數定義為靜態函數,靜態函數是屬于整個類的,不屬于某個對象,也就沒有this指針了。

這個例子的話,就是我們在上一個章節提到的,大家可以直接加上static。

這種方法其實有一定的缺點,靜態會帶來諸多的不變,因為靜態函數沒有this指針,那么它就訪問不了普通的成員函數或者數據成員,會給我們在開發中帶來不小的影響,特別是工程比較大的時候。

成員函數的函數指針

這個方法從另外一個角度出發,我們可以定義一個成員函數的函數指針,其實相當于這個函數指針有了this參數了。

例子如下:

#include 


class B
{
public:
    void CB(int a) { printf("CB a = %d\\n", a); }
};


typedef void (B::*p_CB)(int);
// using p_CB = void (B::*)(int);
void runCB(p_CB CB, B b, int a)  { printf("run CB\\n"); (b.*CB)(a); }


int main()
{
    B b;
    p_CB p_f1 = &B::CB;
    runCB(p_f1, b, 20);
    return 0;
}

這種寫法晦澀難懂,特別是(b.*CB)(a)這種寫法一看上去就覺得很奇怪,代碼寫的越生僻,越復雜,帶來的風險就越大。

另外,如果想要采用這種方法實現回調,那么在定義回調函數的時候就得知道誰會調用它,顯然,這個要求是不合理的,所以,這種方法很不常用,只是介紹這種方法。

單例模式

這個方法是上面靜態函數方法的進一步優化,因為靜態函數沒有傳進去this指針,那么我們可不可以想辦法得到this指針呢?單例模式就可以做到,一般上單例模式為了讓類只存在一個對象,一般都會在類的內部定義一個指向自己的指針,我們就可以通過這個指針,在任何地方都可以訪問到這個對象。

簡單例子:

#include 


class B
{
public:
    static B *get_instance() {
        static B instance;
        return &instance;
    }
    void CB(int a) { printf("CB a = %d\\n", a); }
};


void runCB(int a)
{
    printf("run CB\\n"); 
    B *b_ptr = B::get_instance();
    b_ptr->CB(a);
}


int main(int argc, char *argv[])
{
  B *b_ptr = B::get_instance();
    runCB(20);
    return 0;
}

使用這種方法,在任何地方都可以訪問該對象,可以很方便得調用對象的方法,是比較好的一種方法了,需要注意的就是單例模式的一些限制而已。

另外說一下,單例模式只能說是一種可以解決回調函數的辦法,不一定是因為要回調,才設計成單例。

C++11的function和bind

如果你的編譯器支持C++11標準的話(現在編譯器基本上都會支持),還有一種更加方便快捷的方法。

function模板

首先介紹一下什么叫 可調用對象 ,簡單來說就是可以使用()來調用的對象,在C++11中,包括函數、函數指針、lambda表達式、bind創建的對象和重載了()的類。

function是一個模板函數,它的功能和函數指針很像,但是函數指針只能針對非成員函數,而function則可以調用C++中所有的可調用實體。

對于成員函數來說,function不能直接調用,這就需要通過下面的bind來做“媒介”。

bind函數

bind函數簡單介紹,就是可以綁定到任意一個可調用對象,下面是它的定義。

可以講bind看作一個通用的函數適配器,他接受一個可調用對象,生成一個新的可調用對象來“適應”原對象的參數列表。 ----《c++Primer》

也就是說,通過bind綁定類的非靜態成員函數,生成一個可調用對象,然后通過function模板去調用這個可調用對象,也就實現了調用類的非靜態成員函數。

下面通過一個簡單的例子來說明如何使用。

例子

#include 
#include 
// typedef std::function
using funCB = std::function<void(int)>; //可以這樣寫,更直觀
class B
{
public:
    void setCB(funCB CB)    { m_CB = CB; }
    void runCB(int a)       { std::cout << "runCB" << std::endl; m_CB(a); }
    void printB(int a)      { std::cout << "a = " << a << std::endl; }
    funCB m_CB;
};
class C
{
public:
    void cbfun(int a) { std::cout << "CB a = "
                        << a << std::endl; }
};
int main()
{
    B b; C c;
    funCB fun = std::bind(&C::cbfun, &c, std::placeholders::_1);
    b.setCB(fun);
    b.runCB(20);
    return 0;
}

在這個例子中,b.runCB(),然后會調用m_CB函數,而m_CB通過setCB綁定到了C::cbfun,所以C::cbfun也會被調用。也就是就是通過b的成函數調用到了c的成員函數,實現了回調。

這種方式是不是看起很簡單呢,

后記

這邊文章介紹了在C++中實現回調的幾種方法,總的來說C++11的function&bind是比較好的方法,另外說一點,function的bind的功能不止這些,這里介紹的只是他們的一種用法。

審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7618

    瀏覽量

    138707
  • 編譯器
    +關注

    關注

    1

    文章

    1645

    瀏覽量

    49473
  • 回調函數
    +關注

    關注

    0

    文章

    87

    瀏覽量

    11665
收藏 人收藏

    評論

    相關推薦

    Android NDK編程--- C/C++調用Java不同類的靜態方法

    前言上一篇我們介紹了《Android NDK編程(四)--- C/C++調用Java方法》,主要是C
    發表于 07-02 07:56

    調函數程序開發中有何作用呢

    調函數程序開發是一個非常重要的概念,所謂的調其實就是不同程序模塊之間的接口和約定,是軟件
    發表于 03-01 07:13

    如何在screenViewBase寫這兩個調?

    你好我想使用 clicklistener 和按鈕調。如何在screenViewBase寫這兩個調?screenViewBase::sc
    發表于 01-30 07:36

    C/C++調函數

    ;#125;在這個入門案例,Callback_1、2、3就是調函數,handle函數的第二個參數就是函數指針,也就是通過函數指針來調用。純C語言通過函數指針來進行
    發表于 02-11 15:25

    (純干貨)使用STM32測量頻率和占空比的幾種方法

    本文詳細介紹了使用STM32測量頻率和占空比的幾種方法。
    的頭像 發表于 03-13 15:43 ?4.4w次閱讀
    (純干貨)使用STM32測量頻率和占空比的<b class='flag-5'>幾種方法</b>

    VISUAL C++教程之VISUAL C++的安裝和使用方法

    本文檔的主要內容詳細介紹的是VISUAL C++教程之VISUAL C++的安裝和使用方法資料免費下載。
    發表于 12-27 16:32 ?19次下載
    VISUAL <b class='flag-5'>C++</b>教程之VISUAL <b class='flag-5'>C++</b>的安裝和使用<b class='flag-5'>方法</b>

    干貨:計算fibnacci 級數的幾種方法

    干貨:計算fibnacci 級數的幾種方法
    的頭像 發表于 06-22 11:23 ?2533次閱讀
    干貨:計算fibnacci 級數的<b class='flag-5'>幾種方法</b>

    詳解調函數的概念及使用步驟

    調函數就是一個被作為參數傳遞的函數。C語言中,調函數只能使用函數指針
    的頭像 發表于 05-26 15:20 ?4173次閱讀

    一文詳解C/C++調函數

    參數傳遞給另一個函數,調函數不是由該函數的實現方直接調用,而是特定的事件或條件發生時由另外的一方調用的,用于對該事件或條件進行響應。**如果代碼立即被執行就稱為同步
    的頭像 發表于 02-12 09:20 ?1711次閱讀

    labview事件調的使用

    介紹LabVIEW事件調的使用方法,可以用于處理執行時間較長的異步事件
    的頭像 發表于 08-24 16:38 ?5022次閱讀
    labview<b class='flag-5'>中</b>事件<b class='flag-5'>回</b><b class='flag-5'>調</b>的使用

    C++生成Dll與調函數測試

    描述了VS環境下,通過C++生成dll的方法,測試調函數
    的頭像 發表于 08-29 16:05 ?1867次閱讀
    <b class='flag-5'>C++</b>生成Dll與<b class='flag-5'>回</b><b class='flag-5'>調</b>函數測試

    javajvm調優有幾種方法

    JVM調優是Java應用程序性能優化過程的重要步驟,它通過針對JVM進行優化來提高應用程序的性能和可靠性。JVM調優可以根據具體的場景和需求,采用不同的方法和策略進行。 首先,我們需
    的頭像 發表于 12-05 11:11 ?2245次閱讀

    ??嵌入式調函數的實現方法

    調函數的命名規范沒有固定的標準,但是根據通用慣例和編碼規范,調函數的命名應該能夠反映函數的作用和功能,讓其他開發者能夠快速理解并使用。
    發表于 03-04 14:49 ?884次閱讀

    調函數(callback)是什么?調函數的實現方法

    調函數是一種特殊的函數,它作為參數傳遞給另一個函數,并在被調用函數執行完畢后被調用。調函數通常用于事件處理、異步編程和處理各種操作系統和框架的API。
    發表于 03-12 11:46 ?3361次閱讀

    C++實現類似instanceof的方法

    函數,可實際上C++沒有。但是別著急,其實C++中有兩種簡單的方法可以實現類似Java的in
    的頭像 發表于 07-18 10:16 ?740次閱讀
    <b class='flag-5'>C++</b><b class='flag-5'>中</b><b class='flag-5'>實現</b>類似instanceof的<b class='flag-5'>方法</b>
    主站蜘蛛池模板: 亚洲伦理精品久久 | 色色激情网| 午夜DV内射一区区 | 色偷偷男人天堂 | 且试天下芒果免费观看 | 尹人久久大香找蕉综合影院 | 午夜视频在线瓜伦 | 亚洲免费无l码中文在线视频 | 回复术士勇者免费观看全集 | 色综合精品无码一区二区三区 | 99re久久精品在线播放 | 亚州AV人片一区二区三区99久 | 日本漫画母亲口工子全彩 | 欧美xxxx83d | 中文无码字慕在线观看 | 一本之道高清在线观看一区 | 网红主播 国产精品 开放90后 | 涩涩免费视频软件 | 浓毛BWBWBWBWBW日本 | 久久精品熟女亚洲AV国产 | 国产精品久久久久久人妻香蕉 | 亚洲AV久久无码精品九号软件 | 好男人在线视频 | 999视频在线观看 | 樱花之恋动漫免费观看 | 国产欧美无码亚洲毛片 | 国产剧情在线精品视频不卡 | 天天看高清影视在线18 | 抽插的日日液液H | 美国女孩毛片 | 亚洲一日韩欧美中文字幕在线 | 小雪奶水涨翁工帮吸的推荐语录 | 最近免费中文MV在线字幕 | 两个吃奶一个添下面视频 | WWW国产亚洲精品久久久日本 | 丰满的寡妇hd高清在线观看 | 2020久久精品永久免费 | 国产精品美女久久久网站动漫 | 久久久黄色大片 | 亚洲色图p | 日本精品久久久久中文字幕 1 |