C++使用模板、函数指针、接口和lambda表达式这四种方法做回调函数的区别比较
在C++中,两个类之间存在一种关系,某个类需要另外一个类去完成某一个功能,完成了之后需要告知该类结果,这种最普通最常见的需求,往往使用回调函数来解决。
如题,我总结下来有这么四种方式可以完成这项功能,下面来一一分析:
1、使用模板
// CppTest.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h>
#include <math.h> template<typename T>
class MathTemplate
{
int ops1,ops2;
int result;
public:
void Add(int a,int b,T callback)
{
ops1 = abs(a); /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
ops2 = abs(b); result = ops1+ops2; callback.showResult(result);
}
}; class Result
{
public:
void showResult(int res)
{
printf("result = %d\n",res);
}
}; int _tmain(int argc, _TCHAR* argv[])
{
Result reShow;
MathTemplate<Result> math;
math.Add(,,reShow); system("pause");
return ;
}
说明:结果类需要知道数学类的处理结果(下面都会使用这个例子),把数学类方法定义为模板函数,回调函数以模板变量的形式传递进去。
优点:两个类耦合度低,数学类不需要知道结果类,结果类因为需要数学类处理,肯定要包括数学类。
缺点:写数学类时,必须要知道结果类有showResult这个方法。
2、使用函数指针
// CppTest.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h>
#include <math.h> class Result; typedef void (Result::*CallbackPtr)(int); class MathCallBack
{
int ops1,ops2;
int result;
public:
void Add(int a,int b,Result *caller,CallbackPtr callback)
{
ops1 = abs(a); /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
ops2 = abs(b); result = ops1+ops2; (caller->*callback)(result);
}
}; class Result
{
public:
void showResult(int res)
{
printf("result = %d\n",res);
}
}; int _tmain(int argc, _TCHAR* argv[])
{
Result reShow;
MathCallBack math; math.Add(,,&reShow,&Result::showResult); system("pause"); return ;
}
说明:跟上面一样,结果类需要知道数学类的处理结果,主要注意的是C++函数指针的写法与调用,必须以(对象.*函数指针)(参数)的形式调用。所以,传递回调函数时需要传入调用对象。
缺点:这种方法用起来没有优点,直接说缺点,耦合度高,数学类需要直接知道结果类,数学类不能重用,调用方式写起来也是别扭。
3、使用接口
// CppTest.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h>
#include <math.h> class Result; class IProcessResult
{
public:
virtual void ProcessResult(int result)=;
}; class MathCallBack
{
int ops1,ops2;
int result;
public:
void Add(int a,int b,IProcessResult *process)
{
ops1 = abs(a); /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
ops2 = abs(b); result = ops1+ops2; process->ProcessResult(result);
}
}; class Result:public IProcessResult
{
public:
void ProcessResult(int res)
{
printf("result = %d\n",res);
}
}; int _tmain(int argc, _TCHAR* argv[])
{
Result reShow;
MathCallBack math; math.Add(,,&reShow); system("pause"); return ;
}
说明:功能一模一样,一样以回调的方式显示结果。
优点:典型的面向接口编程,即结果类针对结果处理接口编程,不针对具体编程,降低耦合度。
缺点:程序中多了一个接口类,多了一个文件,不要小看多了一个文件,在大型项目工程里,有非常多的类似类之间关系,这样做会多出很多只有一个接口函数的类。
4、使用lambda表达式
// CppTest.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <functional> class MathCallBack
{
int ops1,ops2;
int result; public:
void Add(int a,int b,std::function<void (int)> func)
{
ops1 = abs(a); /* 实际上这个函数可能非常复杂,非常耗时,这样回调更突显作用*/
ops2 = abs(b); result = ops1+ops2;
func(result);
}
}; int _tmain(int argc, _TCHAR* argv[])
{
MathCallBack math; math.Add(,,[](int result) -> void {
printf("result = %d\n",result);
}); system("pause"); return ;
}
说明:功能一模一样,一样以回调的方式显示结果。注意看lambda的回调函数类型哦!
优点:不用多说,整个代码简洁了不知道多少倍,优点无数。
总结:其实写这个博文就是为了学习C++的lambda表达式,在自己的项目中前3中方法都用了,始终感觉耦合度大,代码不简洁。见识过C#中lambda表达式的巨大优势,就知道C++一定能做到。
C++使用模板、函数指针、接口和lambda表达式这四种方法做回调函数的区别比较的更多相关文章
- java四种引用与回调函数
JAVA四种引用 java对象的引用包括: 强引用 软引用 弱引用 虚引用 Java中提供这四种引用类型主要有两个目的: 第一是可以让程序员通过代码的方式决定某些对象的生命周期: 第二是有利于JVM进 ...
- Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法
1 编程范式 主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 1.1 命令式编程 关注计算机执行的步骤,就是告诉计算机先做什么后做什么 1.2 声明式编程 表达程序的执行逻辑,就是告诉计算 ...
- 使用Java函数接口及lambda表达式隔离和模拟外部依赖更容易滴单测
概述 单测是提升软件质量的有力手段.然而,由于编程语言上的支持不力,以及一些不好的编程习惯,导致编写单测很困难. 最容易理解最容易编写的单测,莫过于独立函数的单测.所谓独立函数,就是只依赖于传入的参数 ...
- C#函数式程序设计之函数、委托和Lambda表达式
C#函数式程序设计之函数.委托和Lambda表达式 C#函数式程序设计之函数.委托和Lambda表达式 相信很多人都听说过函数式编程,提到函数式程序设计,脑海里涌现出来更多的是Lisp.Haske ...
- 深入学习C#匿名函数、委托、Lambda表达式、表达式树类型——Expression tree types
匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...
- Java核心技术-接口、lambda表达式与内部类
本章将主要介绍: 接口技术:主要用来描述类具有什么功能,而并不给出每个功能的具体实现.一个类可以实现一个或多个接口. lambda表达式:这是一种表示可以在将来的某个时间点执行的代码块的简洁方法. 内 ...
- 优雅实现INotifyPropertyChanged接口——利用Lambda表达式
原文:优雅实现INotifyPropertyChanged接口--利用Lambda表达式 参考文章 在14年的时候,曾经读过上面的参考文章,不过当时并没有怎么理解,慢慢地也就将这篇文章忘诸脑后了. 直 ...
- Java 终于在 Java 8 中引入了 Lambda 表达式。也称之为闭包或者匿名函数。
本文首发于 blog.zhaochunqi.com 转载请注明 blog.zhaochunqi.com 根据JSR 335, Java 终于在 Java 8 中引入了 Lambda 表达式.也称之为闭 ...
- 匿名函数、委托和Lambda表达式
匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...
随机推荐
- POJ 1286 Necklace of Beads ——Burnside
[题目分析] 题目大意:一个环有n个点,共染三种颜色.问 在旋转和对称的情况下有多少种本质不同的方案数. Burnside直接做. [代码] #include <cstdio> #incl ...
- BZOJ 3907: 网格【组合数学】
Description 某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m.现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过 ...
- leetcode 376
利用贪心思想,每次都得到到当前数最长的长度,和与当前数链接的前一个数之间差的符号 class Solution { public: int wiggleMaxLength(vector<int& ...
- Ionic 如何把左上角的按钮去掉?
代码实现: <ion-header > <ion-toolbar> <ion-buttons start> <a href="#"> ...
- docker管理工具推荐(linux和windows)
1.windows. 下载dokcer toolbox即可 2.linux 推荐rancher.安装链接参考:http://www.kaimingwan.com/post/rong-qi-yu-ron ...
- oracle连接封装方法
public static void updateSqlOracle(String sqlstr,String linkIP,String username,String password) thro ...
- localStorage增删改查
/** * 设置 本地缓存 */ export function setStorage(key, obj) { if (typeof obj === 'string') { localStorage. ...
- LeetCode OJ--Remove Duplicates from Sorted List II *
http://oj.leetcode.com/problems/remove-duplicates-from-sorted-list-ii/ 处理链表的范例 #include <iostream ...
- Delphi使用进行post数据时超时设置
因项目需要进行http的post提交数据,开始时用indy的idHttp组件,但是测试时发现当网络中断(如拔掉网线),idHttp的超时设置无效果,要等20秒才提示超时(参考网上的做法,将indy9升 ...
- alibaba/fastjson 之 JSONPath
JOSNPath 是一个非常强大的工具,对于处理 json 对象非常方便. 官方地址:https://github.com/alibaba/fastjson/wiki/JSONPath 基本用法:ht ...