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++一定能做到。

posted @ 2018-01-16 22:24  kanite  阅读(5747)  评论(0编辑  收藏  举报