簡單聊聊C++中回調函數的實現

前言

回調函數其實和普通函數一樣,不同的是普通函數是直接在程序中進行調用,回調函數是通過函數指針將它的地址傳遞給其它函數,函數執行在其它函數體執行,這個過程就叫做回調。所以,C++回調函數也並非高大上的技術,它的原理無非就是函數指針或者對象的傳遞。

回調函數機制:

1、定義一個函數(普通函數即可);

2、將此函數的地址註冊給調用者;

3、特定的事件或條件發生時,調用者使用函數指針調用回調函數。

本文就從函數指針開始對回調函數進行說明。

1 函數指針

函數指針是指一個變量,函數對象創建後就會分配一個地址,這個地址可以通過變量進行保存。這個變量就叫做函數地址變量,也可以稱之為函數指針。
函數指針的定義方式如下:

int(*p)(int, int);

如上,定義瞭一個函數指針,它指向一個包含兩個整型參數且返回值為整型數值的函數對象。

函數指針在C和C++中被經常使用,使用方式也很簡單,具體如下面代碼所示:

typedef int (*Ptr)(int,int);
int add(int a,int b){
    return (a+b);
}
int main()
{
    Ptr pInt = add;
    cout<<pInt(3,5)<<endl;
    return 0;
}

2 C風格的回調函數

上面的代碼是將一個函數地址賦值給瞭函數指針,下面將函數作為回調函數的參數的方式進行處理,函數處理結果也是一致的。代碼如下:

typedef int (*Ptr)(int, int);
int CallBack(Ptr pInt, int a, int b) {
  return pInt(a, b);
}
int add(int a, int b) {
  return (a + b);
}
int main()
{
  cout << CallBack(&add, 3, 5) << endl;
}

代碼如上,代碼運行結果為:8。

實現是不是很簡單,通過回調函數,可以讓用戶自己定義自己的業務實現,且這種方式在網絡通訊中被經常使用,下面在看看一下如果回調函數是類成員函數的時候如何實現。

3 C++風格的回調函數

在C++中,如果回調函數是類成員函數,需要將回調函數定義成為靜態。當然也可以使用全局函數,但是這樣做就會破壞C++的封裝性。

下面的代碼就演示瞭將一個靜態成員函數作為回調函數的使用情況。

typedef int (*Ptr)(int,int);
int RegFuncation(Ptr pInt,int a,int b){
    return pInt(a,b);
}
class COperMath{
public:
    //回調函數
    static int add(int a,int b){
        return (a+b);
    }
    //註冊函數
    void RegFuncationCallBack(){
       cout<<RegFuncation(add,3,5)<<endl;
        return ;
    }
};
int main()
{
    COperMath pInst;
    pInst.RegFuncationCallBack();
    return 0;
}

4 多態類型的回調函數

在前面的代碼中,都是使用函數指針的方式進行,下面的代碼使用多態的方式實現,為瞭演示實現的方式,代碼比較簡單。

class CAniable{
public:
    virtual void eat()=0;
};
class CCat:public CAniable{
public:
    virtual void eat(){
        cout<<"Cat like mouse"<<endl;
    }
};

class CDog:public CAniable{
public:
    virtual void eat(){
        cout<<"Dog like shit"<<endl;
    }
};
int main()
{
    CAniable *pBase = new CCat();
    pBase->eat();
    CAniable *pBase1 = new CDog();
    pBase1->eat();
    delete pBase;
    delete pBase1;
    return 0;
}

代碼運行結果為:

Cat like mouse
Dog like shit

上面的代碼通過定義一個純虛的基類,裡面定義瞭一個純虛的公共接口,其它類都繼承自基類,在使用時就可以將這個類指針傳遞給回調函數,進而實現回調的功能。

5 通過function和bind實現回調函數功能

function功能很函數指針功能類似,不同的是function可以調用各種對象和函數。function還可以調用lamda表達式。具體如下所示。

typedef function<int(int,int)> func;
int add(int a,int b){
    return (a+b);
}

class COperMath{
public:
    float Sum(float a,float b){
        return(a+b);
    }
};

int main()
{
    //function包裹add
    func f = &add;
    cout<<"func="<<f(3,5)<<endl;
    //function和bind聯合使用
    COperMath cMath;
    function<float(float,float)> func_bind = bind(&COperMath::Sum,ref(cMath),placeholders::_1,placeholders::_2);
    cout<<"func_bind="<<func_bind(6.0,10.0)<<endl;
    return 0;
}

代碼運行結果為:

func=8
func_bind=16

如上,本文使用瞭5種方式對回調函數進行實現,在實際項目中,使用回調函數的場景比這裡要復雜的多,希望大傢在實際使用中能夠運用自如。

6 總結

回調函數在實際中有許多作用。假設有這樣一種情況:我們要編寫一個庫,該庫實現排序功能,但是又不希望在庫裡實現排序邏輯,這樣就可以使用回調函數讓用戶自己通過函數指針的方式將排序邏輯傳進來進行排序。回調可用於網絡編程中,如通過回調函數獲取服務端返回的數據信息並進行處理。

到此這篇關於C++中回調函數實現的文章就介紹到這瞭,更多相關C++回調函數實現內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: