• C++基础知识(十九)--- 函数对象


    目录

    函数对象(重点)

    函数对象应用实例1:在 accumulate 算法中的应用

    函数对象应用实例2:在 sort 算法中的应用

    eg:greater 模板的源代码如下:

    sort算法有两个版本:

     函数对象和普通函数的区别:

    谓词:

    内建函数对象

    算数类函数对象:(除了 negate是一元运算,其他都是二元运算)

    关系运算类函数对象:(都是二元运算)

    逻辑运算类仿函数:(not 为一元运算,其余为二元运算)

    内建对象函数举例: 

    c++中struct和class的区别


    函数对象(重点)

    C++函数对象详解(附带实例)

    函数对象,就是可以当作函数使用的对象。

    类中重载了(),这个类实例化的对象叫做函数对象(仿函数)。

    • 函数对象(仿函数)是一个类,不是一个函数;
    • 重载了“()”操作符,使得它可以像函数一样调用;

    假定某个类有一个重载的 operator(),根据需要获取的参数个数分为:

    • 一元仿函数(unary functor):一个参数;
    • 二元仿函数(binary functor):两个参数。

    函数对象的作用:作为算法策略。

    函数对象应用实例1:在 accumulate 算法中的应用

    STL 中有以下实现“累加”功能的算法(函数模板),该模板的功能是对(first,last)中的每个迭代器 I 执行 val = op(val, *I),返回最终的 val。

    在头文件 numeric.h 中,accumulate 的源码如下:

    1. #include
    2. template <class InIt, class T, class Fn>
    3. T accumulate(const InIt first, const InIt last, T val, Fn op)
    4. {
    5. for (; first != last; ++first)
    6. val = op(val, *first);
    7. return val;
    8. }

    此模板被实例化后,op(val, *first) 必须要有定义,则 op 只能是函数指针或函数对象。因此调用 accumulate 模板时,形参 op 对应的实参只能是函数名、函数指针或者函数对象。

    eg:通过 accumulate 模板求一个 vector 中元素的平方和。

    1. #include
    2. template <class T>
    3. void PrintInterval(T first, T last)
    4. { //输出区间[first,last]中的元素
    5. for (; first != last; ++first)
    6. cout << *first << " ";
    7. cout << endl;
    8. }
    9. int SumSquares(int total, int value)
    10. {
    11. return total + value * value;
    12. }
    13. template <class T>
    14. class SumPowers
    15. {
    16. private:
    17. int power;
    18. public:
    19. SumPowers(int p):power(p){}
    20. const T operator()(const T& total, const T& value)
    21. { //计算 value 的 power 次方,并加到total上
    22. T v = value;
    23. for (int i = 0; i < power - 1; ++i)
    24. {
    25. v = v * value;
    26. }
    27. return total + v;
    28. }
    29. };
    30. void test24()
    31. {
    32. const int size = 5;
    33. int a1[] = { 1,2,3,4,5 };
    34. vector<int> v(a1, a1 + size);
    35. cout << "(1)";
    36. PrintInterval(v.begin(), v.end());
    37. int result = accumulate(v.begin(), v.end(), 0, SumSquares);
    38. cout << "(2)平方和: " << result << endl;
    39. result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(3));
    40. cout << "(3)立方和: " << result << endl;
    41. result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(4));
    42. cout << "(4)4次方和: " << result << endl;
    43. }

    注释:

    1. 

    int result = accumulate(v.begin(), v.end(), 0, SumSquares);

    第四个参数是函数名。函数名字的类型是函数指针,因此本行将 accumulate 模板实例化后得到的模板函数定义如下:

    1. int accumulate(vector<int>::iterator first, vector<int>::iterator last, int val, int(*op)(int, int))
    2. {
    3. for (; first != last; ++first)
    4. val = op(val, *first);
    5. return val;
    6. }

    形参 op 是一个函数指针,而 op(val, *first) 就调用了指针 op 指向的函数,即函数 SumSquares。

    2.

    result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(3));

    第四个参数是 SumPowes(3),SumPowes 是类模板的名字,SumPowes 就是类的名字。类的名字后面跟着构造函数的参数列表,就代表一个临时对象。

    编译器在编译此行时,会将 accumulate 模板实例化为以下函数:

    1. int accumulate(vector<int>::iterator first, vector<int>::iterator last, int val, SumPowers<int> op)
    2. {
    3. for (; first != last; ++first)
    4. val = op(val, *first);
    5. return val;
    6. }

    形参 op 是一个函数对象,而 op(val, *first) 等价于:

    op.operator()(val, *first);

    即调用了 SumPowers 类的operator 成员函数。

    对比 1 和 2,函数对象的 operator() 成员函数可以根据对象内部的不同状态执行不同操作。???

    函数对象应用实例2:在 sort 算法中的应用

     STL 中定义了一些函数对象类模板,都位于头文件 functional 中。

    eg:greater 模板的源代码如下:

    1. template<class T>
    2. struct greater
    3. {
    4. bool operator()(const T& x, const T& y)const
    5. {
    6. return x > y;
    7. }
    8. };
    1. #include
    2. #include
    3. #include
    4. void test18()
    5. {
    6. vector<int> v;
    7. v.push_back(4);
    8. v.push_back(7);
    9. v.push_back(3);
    10. sort(v.begin(), v.end(), greater<int>());
    11. for_each(v.begin(), v.end(), [](int val) {cout << val << " "; });
    12. //[](int val) {cout << val << " "; } //匿名函数
    13. }

    STL 中的排序模板 sort 能将区间从小到大排序。

    sort算法有两个版本:

    (1)该模板要求first、last是随机访问迭代器,元素比较大小是用 < 进行的。

    1. template <class T>
    2. void sort(const T first, const T last);

    (2)该版本中,元素a、b比较大小是通过表达式 op(a,b) 进行的,op 定义了元素比较大小的规则。例如上边那个例子。

    1. template <class T, class Pr>
    2. void sort(const T first, const T last, Pr op);

    eg:sort 算法

    1. #include //sort算法在此头文件中定义
    2. template <class T>
    3. void Printval(T first, T last)
    4. {
    5. for (; first != last; ++first)
    6. cout << *first << " ";
    7. cout << endl;
    8. }
    9. class A
    10. {
    11. public:
    12. bool operator<(const A& a)
    13. {
    14. return this->v < a.v;
    15. }
    16. public:
    17. int v;
    18. A(int n):v(n){}
    19. };
    20. //bool operator<(const A& a1, const A& a2) //也可以重载为A的const成员函数
    21. //{
    22. // return a1.v < a2.v;
    23. //}
    24. bool GreaterA(const A& a1, const A& a2)
    25. {
    26. return a1.v > a2.v;
    27. }
    28. struct LessA
    29. {
    30. bool operator()(const A& a1, const A& a2)
    31. {
    32. return (a1.v % 10) < (a2.v % 10);
    33. }
    34. };
    35. ostream& operator<<(ostream& o, const A& a)
    36. {
    37. o << a.v;
    38. return o;
    39. }
    40. void test25()
    41. {
    42. int a1[4] = { 1,5,2,7};
    43. A a2[5] = { 43,1,8,45,62 };
    44. sort(a1, a1 + 4);
    45. cout << "(1) "; Printval(a1, a1 + 4);
    46. sort(a2, a2 + 5);
    47. cout << "(2) "; Printval(a2, a2 + 5); //按v的值从小到大排序
    48. sort(a2, a2 + 5, GreaterA); //按v的值从大到小排序
    49. cout << "(3) "; Printval(a2, a2 + 5);
    50. sort(a2, a2 + 5, LessA()); //按v的个位数从小到大排序
    51. cout << "(4) "; Printval(a2, a2 + 5);
    52. }

    注释:

    1. 

    sort(a2, a2 + 5, GreaterA); 

    编译器将 sort 实例化得到的函数原型如下:

    void sort(A* first, A* last, bool(*op)(const A&, const A&));

    该函数在执行过程中,当要比较两元素大小时,就是看 op(a,b),本程序中 op 指向了 GreaterA,因此就用GreaterA定义的规则来比较大小。

    2. 

    sort(a2, a2 + 5, LessA()); 

    编译器将 sort 实例化得到的函数原型如下:

    void sort(A* first, A* last, LessA op);

    该函数在执行过程中,当要比较两元素大小时,就是看 op(a,b),本程序中 op(a,b) 等价于op.operator(a,b),因此就用LessA定义的规则来比较大小。

     函数对象和普通函数的区别:

    函数对象可以有自己的状态;(什么状态)

    函数对象有类型,普通函数没类型;(怎么看的)

    函数对象比普通函数执行效率高(成员函数自动申请成为内联函数);

    谓词:

    普通函数或重载的 operator() 返回值是 bool 类型的函数对象(仿函数)。

    如果 operator 接收一个参数,则叫做一元谓词,如果接收两个参数,则叫做二元谓词

    谓词可以作为一个判断式。

     

    内建函数对象

    STL内建了一些函数对象,即函数对象类模板。

    分为:算数类函数对象、关系运算类函数对象、逻辑运算类仿函数。

    这些仿函数所产生的对象,用法和一般函数完全相同,当然也可以产生无名的临时对象来履行函数功能。

    使用内建函数对象,需要引入头文件 #include

    算数类函数对象:(除了 negate是一元运算,其他都是二元运算)

    1. template<class T> T plus //加法仿函数
    2. template<class T> T minus //减法
    3. template<class T> T multiplies //乘法
    4. template<class T> T divides //取整
    5. template<class T> T modulus //取余
    6. template<class T> T negate //取反

    关系运算类函数对象:(都是二元运算)

    1. template<class T>bool equal_to //等于
    2. template<class T>bool not_equal_to //不等于
    3. template<class T>bool greater //大于
    4. template<class T>bool greater_equal //大于等于
    5. template<class T>bool less //小于
    6. template<class T>bool less_equal //小于等于

    逻辑运算类仿函数:(not 为一元运算,其余为二元运算)

    1. template<class T>bool logical_and //逻辑与
    2. template<class T>bool logical_or //逻辑或
    3. template<class T>bool logical_not //逻辑非

    内建对象函数举例: 

     

    c++中struct和class的区别

    C++继承了C语言的 struct,并且加以扩充。因为考虑到对C兼容,所以C++保留了 struct,并做了一些扩展使其更适合面向对象。

    ① C语言中,struct 是一种数据类型,只能定义数据成员,而不能定义成员函数。C++中,struct 类似于class,在其中既可以定义数据成员,也可以定义成员函数。

    ② 默认的继承访问权。class 默认是 private,struct 默认是 public。

    ③ 默认访问权限。struct 作为数据结构的实现体,它默认的数据访问权限是 public 的;而 class 作为对象的实现体,它默认的成员变量访问权限是 private 的。

    可以看出,struct 更适合看成是一个数据结构的实现体,class 更适合看成是一个对象的实现体。

  • 相关阅读:
    解锁云计算的未来:AI、容器和数据隐私的挑战
    重装系统后如何在win10系统打开命令行窗口
    使用Eclipse搭建Hadoop编程环境
    uniapp自定义播放器
    电子协会 C语言 1级 31 、 计算线段长度
    Rider 设置选中单词侧边高亮,去除警告建议高亮
    Linux 文件 & 目录管理 & 链接
    django表单的使用说明
    钡铼R40边缘计算网关与华为云合作,促进物联网传感器数据共享与应用
    月薪集中在8k-17k、近六成的人一年没跳槽、AI可减少20%-40%工作量,2024中国开发者调查报告来了!...
  • 原文地址:https://blog.csdn.net/woshizuopie/article/details/126329153