STL算法之回调函数和函数对象的理解及设计


         STL算法之回调函数和函数对象的理解及设计

                                                By qianghaohao
          引言:在我们使用STL的算法的时候,很多算法提供回调函数为参数和函数对象来作为参数,提供
更加强大的功能。就比如STL中sort算法来说吧,我们可能一般情况下这么使用sort(v.begin(), v.end());
这种情况下是对容器中元素默认升序排序。那么我们怎么实现降序排序呢?有两种方法,要么用库中提
供的函数对象作为参数,要么自己编写个函数或者函数对象来作为参数。那么问题来了,库中提供的
函数对象怎么用呢?是啥意思呢?即使我们传进去了也不知道为啥这样?传个自己写的函数?那自己
该怎么写呢?怎么写才能符合STL要求的接口呢?所有的这一切其实都可以通过调试代码单步来理解的。
我们没必要专门研究《STL源码剖析》之类的高深书籍,照样也可以看到看懂STL源码的实现。调试的
时候单步跟进去便揭开了庐山正面目,其实里面的代码也挺好理解的,只不过都是用模板写的,看起来
不那么舒服,多看几眼就懂了。STL真是GP程序设计思想啊,一切皆模板.。。。
            接下来通过使用一个STL的一个accumulate算法来解答上面的所有困惑:

      首先贴一段完整的代码,看看读者能否看懂每一句代码是怎么运行的,如果不懂看后面的解释:
//以下代码来自:http://www.cplusplus.com/
// accumulate example
#include <iostream>
#include <functional>
#include <numeric>
using namespace std;

int myfunction (int x, int y) {return x+2*y;}

struct myclass {
 int operator()(int x, int y) {return x+3*y;}
} myobject;

int main () {
  int init = 100;
  int numbers[] = {10,20,30};

  cout << "using default accumulate: ";
  cout << accumulate(numbers,numbers+3,init);
  cout << endl;

  cout << "using functional's minus: ";
  cout << accumulate (numbers, numbers+3, init, minus<int>() );
  cout << endl;

  cout << "using custom function: ";
  cout << accumulate (numbers, numbers+3, init, myfunction );
  cout << endl;

  cout << "using custom object: ";
  cout << accumulate (numbers, numbers+3, init, myobject );
  cout << endl;

  return 0;
}
        在上面代码中accumulate(numbers,numbers+3,init)这句调用就不解释了,最基本的使用,相信只要接触了STL的都懂。
可能让STL初学者迷惑的是后面三次的调用。接下来逐个分析下:
    一. 解析:accumulate (numbers, numbers+3, init, minus<int>() );
   猛一看,这句代码不好理解。。。于是查询MSDN或者到C++网站查询使用方法,查看半天结果全英文,最终还是不懂。。。
  没看懂该怎么办呢?没错,开始单步调试,跳进这句代码的调用,豁然开朗:
      没错,我们很幸运地看到了accumulate算法的实现,那么这段代码还看不懂么???稍微懂点模板的很容易看懂了,就一个简单的for
语句迭代累加。。。似乎也没那么神奇!现在我们可以看到我们传的那个函数对象参数就是 __binary_op,函数指针的调用方式就不用说
了吧-- __init = __binary_op(__init, *__first);这句代码便是对我们的函数的调用,可见第一个参数使我们传进去的 init,第二个是STL容器
中的元素。那么我们现在关心的是那个函数对象是怎么实现的,对吧?于是继续跳进 __binary_op函数的调用:

     到了这里上面的所有疑惑估计都豁然开朗了吧!!!我们调用的minus<int>()这个函数对象其实实现的功能是返回x - y。
那么 accumulate (numbers, numbers+3, init, minus<int>() )这句代码实现的功能也就迎刃而解了,它实现的功能就是
init = init - Elem; 这个表达式的累加。 Elem这里代表容器的每个元素。那么最终结果就是60了。
      二. 解析:accumulate (numbers, numbers+3, init, myfunction );
    这句代码和上面的类似,只不过第三个参数是自己定义的一个回调函数,通过自定义来满足自己的功能需求。那么初学者
的疑惑就来了,该怎么自定义这个回调函数呢?其实不难,从上面的调试中我们就看到了accumulate的实现了,它的第
三个参数 __binary_op是一个含有两个参数的回调函数-- __binary_op(__init, *__first);那么我们只要定义一个含有两个参数
的回调函数即可,当然也要有返回值。这段代码中是这么定义的:
int myfunction (int x, int y) {return x+2*y;}
很明显,这个函数是否和要求的,那么我们就这么写了!!!这下会写自己的回调函数了吧,就这么简单。
      三.解析:accumulate (numbers, numbers+3, init, myobject );
   这句代码也和上面的完全类似,只不过第三个参数是自己定义的函数对象,定义方法和自定义回调函数一样的,参数和
库中的接口一致即可。给初学者稍微解释下函数对象--函数对象就一个类重载了()运算符,然后就可以用对象名+参数
列表来调用这个重载函数了,这不就极其类似一个函数的调用吗?对,就是这样的,所以称这种对象为函数对象。
这个理解是我自己这么理解,仅供参考!

      结语:
          到此为止,相信大家对STL算法中回调函数和函数对象有所理解了吧,最起码能看懂别人或者示例代码了吧,也最
起码学会了如何定制自己的回调函数或者函数对象来使用STL的算法了吧。

转载于:https://www.cnblogs.com/codingnutter/p/5634477.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值