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)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...
随机推荐
- 【Luogu】P1593因子和(唯一分解定理,约数和公式)
题目链接 首先介绍两个定理. 整数唯一分解定理:任意正整数都有且只有一种方式写出素数因子的乘积表达式. \(A=(p1k1 p2k2 ...... pnkn \) 求这些因子的代码如下 ;i*i< ...
- BZOJ 2595 [Wc2008]游览计划 ——斯坦纳树
[题目分析] 斯坦纳树=子集DP+SPFA? 用来学习斯坦纳树的模板. 大概就是用二进制来表示树包含的点,然后用跟几点表示树的形态. 更新分为两种,一种是合并两个子集,一种是换根,换根用SPFA迭代即 ...
- BZOJ1923 [Sdoi2010]外星千足虫 【高斯消元】
题目 输入格式 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用"点足机"的统计结果.每行 包含一个"01"串和一个数字,用 ...
- 【图论】bnuoj 52810 Splitting the Empire
acm.bnu.edu.cn/v3/contest_show.php?cid=9208#problem/G [题意] 给定一个无向图,要求把这个无向图的点划分到不同的集合里,使得每个集合的点之间两两没 ...
- Vmware虚拟机三种网卡模式详解
由于Linux目前很热门,越来越多的人在学习linux,但是买一台服务放家里来学习,实在是很浪费.那么如何解决这个问题?虚拟机软件是很好的选择,常用的虚拟机软件有vmware workstations ...
- Query on The Trees(hdu 4010)
题意: 给出一颗树,有4种操作: 1.如果x和y不在同一棵树上则在xy连边 2.如果x和y在同一棵树上并且x!=y则把x换为树根并把y和y的父亲分离 3.如果x和y在同一棵树上则x到y的路径上所有的点 ...
- @Java web程序员,在保留现场,服务不重启的情况下,执行我们的调试代码(JSP 方式)
一.前言 类加载器实战系列的第六篇(悄悄跟你说,这篇比较水),前面5篇在这里: 实战分析Tomcat的类加载器结构(使用Eclipse MAT验证) 还是Tomcat,关于类加载器的趣味实验 了不得, ...
- Servlet 2.4 规范之第二篇:Servlet接口
Servlet接口是Servlet API的最核心抽象类.所有的servlets都直接实现了这个接口,或者以更通用的方式继承了这个接口的实现类.Servlet API自带了两个实现了Servlet接口 ...
- saltstack 开发相关命令记录
SALT API开发相关命令记录. 查看当前的salt key信息salt-key -L 测试被控主机的连通性salt '*' test.ping 远程命令执行测试salt '*' cmd.run ' ...
- TortoiseSVN如何更换或重置登录用户
昨天手贱把svn重新卸载了,再安装后便与之前的项目断了,因为第一次使用这个,也不清楚再怎么登录,还有就是上次是使用别人的账号,也不知道怎么清除别人的账号. 鼠标右键找到settings,点击打开 找到 ...