1. 程式人生 > 程式設計 >C++回撥函式的理解和使用教程

C++回撥函式的理解和使用教程

一、回撥函式就是一個通過函式指標呼叫的函式。如果你把函式的指標(地址)作為引數傳遞給另一個函式,當這個指標被用來呼叫其所指向的函式時,我們就說這是回撥函式。回撥函式不是由該函式的實現方直接呼叫,而是在特定的事件或條件發生時由另外的一方呼叫的,用於對該事件或條件進行響應。

回撥函式機制:

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

2、將此函式的地址註冊給呼叫者;

3、特定的事件或條件發生時,呼叫者使用函式指標呼叫回撥函式。

注:為什麼要特定事件或條件發生?不應該隨時都可以呼叫回撥函式嗎?

以下是回撥函式的兩種使用方式(簡單理解):

1、

#include <stdio.h>
typedef int(*callback)(int,int);

int add(int a,int b,callback p){
 return (*p)(a,b);
}

int add(int a,int b){
 return a+b;
}
int main(int argc,char *args[]){
 int res = add(4,2,add);
 printf("%d\n",res);
 return 0;
}

在這個例子中,可以看到,我們定義了一個callbak的函式指標,引數為兩個int,返回值為int,通過呼叫函式地址來進行簡單的相加運算。
2、

#include <stdio.h>
typedef int (callBack)(const void *buffer,size_t size,char *p_out);

void callFunc(callBack *consume_bytes,char *p_out) {
 printf("callFunc\n");
 const void *buffer = NULL;
 consume_bytes(buffer,p_out); //傳入值可以隨便填
}

int callBackFunc(const void *buffer,char *p_out){
 printf("callBackFunc\n");
 memset(p_out,0x00,sizeof(char)*100);
 strcpy(p_out,"encoderCallback:this is string.");
 return 1;
}

int main(int argc,char *args[]){
 char p_out[100];
 callFunc(callBackFunc,p_out);
 printf("%s\n",p_out);
 return 0;
}

可以把回撥函式和呼叫函式封裝承類再呼叫。

二、在理解“回撥函式”之前,首先討論下函式指標的概念。

函式指標

(1)概念:指標是一個變數,是用來指向記憶體地址的。一個程式執行時,所有和執行相關的物件都是需要載入到記憶體中,這就決定了程式執行時的任何物件都可以用指標來指向它。函式是存放在記憶體程式碼區域內的,它們同樣有地址,因此同樣可以用指標來存取函式,把這種指向函式入口地址的指標稱為函式指標。

(2)先來看一個Hello World程式:

int main(int argc,char* argv[])
{
 printf("Hello World!\n");
 return 0;
}

然後,採用函式呼叫的形式來實現:

void Invoke(char* s);

int main(int argc,char* argv[])
{
 Invoke("Hello World!\n");
 return 0;
}

void Invoke(char* s)
{
 printf(s);
}

用函式指標的方式來實現:

void Invoke(char* s);

int main()
{
 void (*fp)(char* s); //宣告一個函式指標(fp)  
 fp=Invoke;    //將Invoke函式的入口地址賦值給fp
 fp("Hello World!\n"); //函式指標fp實現函式呼叫
 return 0;
}

void Invoke(char* s)
{
 printf(s);
}

由上知道:函式指標函式的宣告之間唯一區別就是,用指標名(*fp)代替了函式名Invoke,這樣這聲明瞭一個函式指標,然後進行賦值fp=Invoke就可以進行函式指標的呼叫了。宣告函式指標時,只要函式返回值型別、引數個數、引數型別等保持一致,就可以宣告一個函式指標了。注意,函式指標必須用括號括起來 void (*fp)(char* s)。

實際中,為了方便,通常用巨集定義的方式來宣告函式指標,實現程式如下:

typedef void (*FP)(char* s);
void Invoke(char* s);

int main(int argc,char* argv[])
{
 FP fp;  //通常是用巨集FP來宣告一個函式指標fp
 fp=Invoke;
 fp("Hello World!\n");
 return 0;
}

void Invoke(char* s)
{
 printf(s);
}

函式指標陣列

下面用程式對函式指標陣列來個大致瞭解:

#include <iostream>
#include <string>
using namespace std;

typedef void (*FP)(char* s);
void f1(char* s){cout<<s;}
void f2(char* s){cout<<s;}
void f3(char* s){cout<<s;}

int main(int argc,char* argv[])
{
 void* a[]={f1,f2,f3}; //定義了指標陣列,這裡a是一個普通指標
 a[0]("Hello World!\n"); //編譯錯誤,指標陣列不能用下標的方式來呼叫函式

 FP f[]={f1,f3};  //定義一個函式指標的陣列,這裡的f是一個函式指標
 f[0]("Hello World!\n"); //正確,函式指標的陣列進行下標操作可以進行函式的間接呼叫
 
 return 0;
}

回撥函式

(1)概念:回撥函式,顧名思義,就是使用者自己定義一個函式,使用者自己實現這個函式的程式內容,然後把這個函式作為引數傳入別人(或系統)的函式中,由別人(或系統)的函式在執行時來呼叫的函式。函式是你實現的,但由別人(或系統)的函式在執行時通過引數傳遞的方式呼叫,這就是所謂的回撥函式。簡單來說,就是由別人的函式執行期間來回調你實現的函式。

(2)標準Hello World程式:

int main(int argc,char* argv[])
{
 printf("Hello World!\n");
 return 0;
}

將它修改成函式回撥樣式:

//定義回撥函式
void PrintfText() 
{
 printf("Hello World!\n");
}

//定義實現回撥函式的"呼叫函式"
void CallPrintfText(void (*callfuct)())
{
 callfuct();
}

//在main函式中實現函式回撥
int main(int argc,char* argv[])
{
 CallPrintfText(PrintfText);
 return 0;
}

修改成帶參的回撥樣式:

//定義帶參回撥函式
void PrintfText(char* s) 
{
 printf(s);
}

//定義實現帶參回撥函式的"呼叫函式"
void CallPrintfText(void (*callfuct)(char*),char* s)
{
 callfuct(s);
}

//在main函式中實現帶參的函式回撥
int main(int argc,char* argv[])
{
 CallPrintfText(PrintfText,"Hello World!\n");
 return 0;
}

至此,對回撥函式應該有了一個大致的瞭解。

到此這篇關於C++回撥函式的理解和使用的文章就介紹到這了,更多相關C++回撥函式理解和使用內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!