C++之函数对象(Function Object) & for_each

来源:互联网 发布:福建 知乎 编辑:程序博客网 时间:2024/06/05 00:49

函数对象

对于一些用到函数作为参数的c++STL算法(如下面的for_each算法函数),函数的传递当然可以用泛化的函数指针来进行,但是c++STL常使用的是函数对象,目的在于更简洁、不依赖于当前计算机硬件体系的方式来表达算法。

  一个函数对象,即一个重载了括号操作符“()”的对象。当用该对象调用此操作符时,其表现形式如同普通函数调用一般,因此取名叫函数对象可以参考如下链接

    http://blog.csdn.net/bonchoix/article/details/8050627#reply

  在c++STL中,定义了若干函数对象,包括算数运算(plus,minus,multiplies,divides,modulus和negate),用于比较(equal_to,not_equal_to,less,greater,less_equal和greater_equal)以及逻辑运算(logical_and,logical_or,logical_not)等

for_each

 如下,for_each函数的实现代码,内部使用了一个for循环,逐一遍历迭代器[first,last)【左闭右开】,然后调用f进行操作。可见,for_each函数并没有修改任何元素数据,只有执行的【对象】f会改动数据(所以不是严格意义的非变易函数)

template<class InputIter,class Function>Function for_each(InputIter first, InputIter last, Function f) {for (; first != last; ++first)f(*first);  //调用f对象的函数operator(),对每个元素进行处理return f;       //返回函数对象}
  需要注意的是

(1)f是对象!对象!对象!不是函数,对数据进行处理的是f的重载后的operator(),所以返回值是在对象f成员变量基础上运算得到的;

(2)这里函数采用值传递(而不是引用),所以该函数将对象f返回,用以将处理后的数据保存下来(实际是对象f发生了变化,将f返回即可读取处理后的数据),若函数无返回值,则形参f不会发生变化,后续有代码为例。

代码

 先看下其他大佬http://blog.csdn.net/y1196645376/article/details/51289254写的

class Average{public:Average():count(0), sum(0){ }void operator()(double num)   //每次调用这个仿函数就相当于往里面添加了一个数{count++; sum += num;                    cout<<3*num<<endl; //为了便于调试观察,特将各数值输出}double GetAverage(){ return sum / count; }     //最后由这个方法得到当前的平均值private:int count;double sum;};template < class T ,class F>F For_each(T begin, T end, F functor){for (T it = begin; it != end; it++)functor(*it);return functor;}int main(){vector<int> arr = { 1, 2, 3, 4, 5 };Average result = For_each(arr.begin(), arr.end(), Average());  //这里的Average()相当于一个临时对象cout << result.GetAverage() << endl;return 0;}

   期初这句话没看懂,一直以为Average()是调用重载()函数,【就是前面的注意(1)f是对象,不是函数】

Average result = For_each(arr.begin(), arr.end(), Average());  //这里的Average()相当于一个临时对象

       导致一直理解为返回的functor一直没变

return functor;

   后来才理解,这里Average()相当于构造函数,创建了一个默认参数对象,调用该对象的重载函数,依次对arr数据处理,最后返回改变后的对象(相当于借助arr各个数据,改变对象,最后返回)
   为了验证上面说法,特将上述代码主函数部分修改如下

int main(){vector<int> arr = { 1, 2, 3, 4, 5 };Average result,r1;result = For_each(arr.begin(), arr.end(),r1); double ave = result.GetAverage();return 0;}

  可以发现结果

r1作为形参传递,最后结果r1没变,而运算结果以对象形式返回给了result,发生了变化


   再在类Average中添加构造函数

Average(int a, int b) { count = a; sum = b; }
   并将主函数改成

int main(){vector<int> arr = { 1, 2, 3, 4, 5 };Average result,r1(0,5);result = For_each(arr.begin(), arr.end(),r1); double ave = result.GetAverage();return 0;}
  发现结果

  result结果是在r1基础上,以arr数据进行r1的重载函数【operator()】处理

  

  综合上述结果,可以验证前述结论

 

  本人新手,理解比较浅显,望大佬多多指正!

原创粉丝点击