函数对象
对于一些用到函数作为参数的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()】处理
综合上述结果,可以验证前述结论
本人新手,理解比较浅显,望大佬多多指正!