C++使用模板、函數指針、接口和lambda表達式這四種方法做回調函數的區別比較


  在C++中,兩個類之間存在一種關系,某個類需要另外一個類去完成某一個功能,完成了之后需要告知該類結果,這種最普通最常見的需求,往往使用回調函數來解決。

  如題,我總結下來有這么四種方式可以完成這項功能,下面來一一分析:

  1、使用模板

 1 // CppTest.cpp : 定義控制台應用程序的入口點。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <stdlib.h>
 6 #include <math.h>
 7 
 8 template<typename T>
 9 class MathTemplate
10 {
11     int ops1,ops2;
12     int result;
13 public:
14     void Add(int a,int b,T callback)
15     {
16         ops1 = abs(a);   /* 實際上這個函數可能非常復雜,非常耗時,這樣回調更突顯作用*/
17         ops2 = abs(b);
18 
19         result = ops1+ops2;
20 
21         callback.showResult(result);
22     }
23 };
24 
25 class Result
26 {
27 public:
28     void showResult(int res)
29     {
30         printf("result = %d\n",res);
31     }
32 };
33 
34 int _tmain(int argc, _TCHAR* argv[])
35 {
36     Result reShow;
37     MathTemplate<Result> math;
38     math.Add(1,3,reShow);
39 
40     system("pause");
41     return 0;
42 }
View Code

  說明:結果類需要知道數學類的處理結果(下面都會使用這個例子),把數學類方法定義為模板函數,回調函數以模板變量的形式傳遞進去。

  優點:兩個類耦合度低,數學類不需要知道結果類,結果類因為需要數學類處理,肯定要包括數學類。

  缺點:寫數學類時,必須要知道結果類有showResult這個方法。

  2、使用函數指針

 1 // CppTest.cpp : 定義控制台應用程序的入口點。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <stdlib.h>
 6 #include <math.h>
 7 
 8 class Result;
 9 
10 typedef void (Result::*CallbackPtr)(int);
11 
12 class MathCallBack
13 {
14     int ops1,ops2;
15     int result;
16 public:
17     void Add(int a,int b,Result *caller,CallbackPtr callback)
18     {
19         ops1 = abs(a);   /* 實際上這個函數可能非常復雜,非常耗時,這樣回調更突顯作用*/
20         ops2 = abs(b);
21 
22         result = ops1+ops2;
23 
24         (caller->*callback)(result);
25     }
26 };
27 
28 class Result
29 {
30 public:
31     void showResult(int res)
32     {
33         printf("result = %d\n",res);
34     }
35 };
36 
37 int _tmain(int argc, _TCHAR* argv[])
38 {
39     Result reShow;
40     MathCallBack math;
41 
42     math.Add(1,3,&reShow,&Result::showResult);
43 
44     system("pause");
45 
46     return 0;
47 }
View Code

  說明:跟上面一樣,結果類需要知道數學類的處理結果,主要注意的是C++函數指針的寫法與調用,必須以(對象.*函數指針)(參數)的形式調用。所以,傳遞回調函數時需要傳入調用對象。

  缺點:這種方法用起來沒有優點,直接說缺點,耦合度高,數學類需要直接知道結果類,數學類不能重用,調用方式寫起來也是別扭。

  3、使用接口

 1 // CppTest.cpp : 定義控制台應用程序的入口點。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <stdlib.h>
 6 #include <math.h>
 7 
 8 class Result;
 9 
10 class IProcessResult
11 {
12 public:
13     virtual void ProcessResult(int result)=0;
14 };
15 
16 class MathCallBack
17 {
18     int ops1,ops2;
19     int result;
20 public:
21     void Add(int a,int b,IProcessResult *process)
22     {
23         ops1 = abs(a);   /* 實際上這個函數可能非常復雜,非常耗時,這樣回調更突顯作用*/
24         ops2 = abs(b);
25 
26         result = ops1+ops2;
27 
28         process->ProcessResult(result);
29     }
30 };
31 
32 class Result:public IProcessResult
33 {
34 public:
35     void ProcessResult(int res)
36     {
37         printf("result = %d\n",res);
38     }
39 };
40 
41 int _tmain(int argc, _TCHAR* argv[])
42 {
43     Result reShow;
44     MathCallBack math;
45 
46     math.Add(1,3,&reShow);
47 
48     system("pause");
49 
50     return 0;
51 }
View Code

  說明:功能一模一樣,一樣以回調的方式顯示結果。

  優點:典型的面向接口編程,即結果類針對結果處理接口編程,不針對具體編程,降低耦合度。

  缺點:程序中多了一個接口類,多了一個文件,不要小看多了一個文件,在大型項目工程里,有非常多的類似類之間關系,這樣做會多出很多只有一個接口函數的類。

  4、使用lambda表達式

 1 // CppTest.cpp : 定義控制台應用程序的入口點。
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <stdlib.h>
 6 #include <math.h>
 7 #include <iostream>
 8 #include <functional>
 9 
10 class MathCallBack
11 {
12     int ops1,ops2;
13     int result;
14 
15 public:
16     void Add(int a,int b,std::function<void (int)> func)
17     {
18         ops1 = abs(a);   /* 實際上這個函數可能非常復雜,非常耗時,這樣回調更突顯作用*/
19         ops2 = abs(b);
20 
21         result = ops1+ops2;
22         func(result);
23     }
24 };
25 
26 int _tmain(int argc, _TCHAR* argv[])
27 {
28     MathCallBack math;
29 
30     
31     math.Add(1,3,[](int result) -> void {  
32             printf("result = %d\n",result); 
33         });
34 
35     system("pause");
36 
37     return 0;
38 }
View Code

  說明:功能一模一樣,一樣以回調的方式顯示結果。注意看lambda的回調函數類型哦!

  優點:不用多說,整個代碼簡潔了不知道多少倍,優點無數。

  總結:其實寫這個博文就是為了學習C++的lambda表達式,在自己的項目中前3中方法都用了,始終感覺耦合度大,代碼不簡潔。見識過C#中lambda表達式的巨大優勢,就知道C++一定能做到。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM