鱼C论坛

 找回密码
 立即注册
查看: 2394|回复: 0

[学习笔记] 053-C++之函数对象与谓词

[复制链接]
发表于 2018-9-22 14:42:06 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 moc 于 2018-9-22 14:41 编辑

1、函数对象和谓词的定义
1. 函数对象
        重载函数调用操作符的类,其对象常称为函数对象(function object),即他的行为类似函数的对象。如果一个类,表现出一个函数的特征,即通过“对象名+(参数列表)”使用一个类对象,如果没有上下文,便不能区分是函数还是函数对象,所以也被称为仿函数
        通过重载operator()来实现。
在STL标准库中,函数对象被广泛的使用以获得弹性,标准库中很多算法都可以使用函数对象或函数来作为自定的回调函数。
        一元函数对象: 函数参数1个;
        二元函数对象: 函数参数两个。
2. 谓词
谓词:作为回调函数,其返回值是bool类型,可以作为一个判断式,可以是普通的回调函数,也可是一个函数对象
        一元谓词:函数参数1个;
        二元谓词:函数参数2个。
2、函数对象和普通函数的联系与区别
联系:函数对象和普通函数一样,执行函数的过程非常相似。
  1. // 函数对象    重载了()运算符的类的对象
  2. template <typename T>
  3. class ShowElemt
  4. {
  5. public:
  6.         void operator()(T &t)
  7.         {
  8.                 n++;
  9.                 printN();
  10.                 cout << t << endl;
  11.         }

  12.         ShowElemt()
  13.         {
  14.                 //cout << "ShowElemt构造函数 do!\n";
  15.                 n = 0;
  16.         }

  17.         ~ShowElemt()
  18.         {
  19.                 //cout << "ShowElemt析构函数 do!\n";
  20.         }
  21.         void printN()
  22.         {
  23.                 cout << "n:" << n << endl;
  24.         }
  25. private:
  26.         int n;
  27. };

  28. // 函数模板  
  29. template <typename T>
  30. void FunShowElemt(T &t)
  31. {
  32.         cout << t << endl;
  33. }

  34. // 普通函数  
  35. void FunShowElem2t(int &t)
  36. {
  37.         cout << t << endl;
  38. }

  39. void main01()
  40. {
  41.         int a = 10;
  42.         ShowElemt<int> showElemt;
  43.         showElemt(a);   // 函数对象的()执行  很像一个函数 ==> 仿函数

  44.         FunShowElemt<int>(a);   // 模板函数的执行
  45.         FunShowElem2t(a);       // 普通函数的执行


  46. }
复制代码

区别:  函数对象属于类对象,能突破函数的概念,能保存调用的状态信息。
注意:
         函数对象 做函数参数  (当函数形参不是引用时,执行的是值拷贝(拷贝构造函数),和原来的函数对象就无关啦)
        /*for_each原型: _Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func)*/
        函数对象   做函数返回值
            1. 分清函数对象做函数参数 是值拷贝 还是引用
            2. 分清stl算法返回的是迭代器还是函数对象(谓词)

  1. void main02()
  2. {
  3.         vector<int> v1;
  4.         v1.push_back(1);
  5.         v1.push_back(3);
  6.         v1.push_back(5);

  7.         // 直接  类名+()==》得到的是一个匿名对象
  8.         for_each(v1.begin(), v1.end(), ShowElemt<int>());   // 匿名函数对象  匿名仿函数 (析构函数会执行3次?)
  9.         for_each(v1.begin(), v1.end(), FunShowElem2t);     // 通过回调函数

  10.         cout << "*****\n";
  11.         ShowElemt<int> show1;   // 声明一个函数对象
  12.         show1 = for_each(v1.begin(), v1.end(), show1);  // for_each函数存在对象做参数和返回值
  13.         show1.printN();
  14. }
复制代码

3、谓词和函数对象应用举例
1. 一元谓词 => 通过一元谓词查找容器中能被4整除的数
  1. template<typename T>
  2. class IsDiv
  3. {
  4. public:
  5.         IsDiv(const T &divisor)
  6.         {
  7.                 this->divisor = divisor;
  8.         }
  9.         bool operator()(T &t)  
  10.         {
  11.                 return (t % divisor == 0);
  12.         }
  13. private:
  14.         T divisor;
  15. };

  16. void main03()
  17. {
  18.         vector<int> v2;
  19.         int a = 4;
  20.         IsDiv<int> myDiv(a);

  21.         for (int i = 0; i < 10; i++)
  22.         {
  23.                 v2.push_back(i + 1);
  24.         }

  25.         //find_if(v2.begin(), v2.end(), IsDiv<int>(a));  // 匿名函数对象
  26.         vector<int>::iterator it = find_if(v2.begin(), v2.end(), myDiv);
  27.         if (it == v2.end())
  28.         {
  29.                 cout << "没有找到能被4整除的元素\n";
  30.         }
  31.         else
  32.         {
  33.                 cout << "第一个能被4整除的元素" << *it << endl;
  34.         }
  35. }
复制代码

2. 二元函数对象 => 容器v1、v2  对应位置元素之和给到v3的对应位置。
  1. // 二元函数对象
  2. template <typename T>
  3. class SumAdd
  4. {
  5. public:
  6.         T operator()(T t1, T t2)
  7.         {
  8.                 return t1 + t2;
  9.         }
  10. };
  11. void main04()
  12. {
  13.         vector<int> v1, v2, v3;
  14.         v1.push_back(1);
  15.         v1.push_back(4);
  16.         v1.push_back(7);

  17.         v2.push_back(2);
  18.         v2.push_back(5);
  19.         v2.push_back(8);

  20.         v3.resize(5);  // 预先给v3分配空间

  21.         transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), SumAdd<int>()); // 谓词
  22.         for (auto each : v3)
  23.         {
  24.                 cout << each << endl;
  25.         }
  26. }
复制代码

3. 二元谓词 => 容器中元素的排序
  1. // 二元谓词
  2. bool myCompare(const int &a, const int &b)
  3. {
  4.         return a < b;  // 从小到大
  5. }

  6. void main05()
  7. {
  8.         vector<int> v1(10);
  9.         for (int i = 0; i < 10; i++)
  10.         {
  11.                 int tmp = rand() % 100;
  12.                 v1[i] = tmp;
  13.         }
  14.         for (auto each : v1)
  15.         {
  16.                 cout << each << " ";
  17.         }
  18.         cout << endl;
  19.         // 排序
  20.         sort(v1.begin(), v1.end(), myCompare);
  21.         for (auto each : v1)
  22.         {
  23.                 cout << each << " ";
  24.         }
  25. }
复制代码

4. 二元谓词在集合中的应用 =>集合不区分大小写查找元素。

  1. struct CompareNoCap
  2. {
  3.         bool operator()(const string &str1, const string &str2) const  // const属性
  4.         {
  5.                 string str1_;
  6.                 str1_.resize(str1.size());
  7.                 transform(str1.begin(), str1.end(), str1_.begin(), tolower); // tolower预定义函数对象

  8.                 string str2_;
  9.                 str2_.resize(str2.size());
  10.                 transform(str2.begin(), str2.end(), str2_.begin(), tolower); // tolower预定义函数对象

  11.                 return (str1_ < str2_);
  12.         }
  13. };

  14. void main06()
  15. {
  16.         set<string> set1;
  17.         set1.insert("bbb");
  18.         set1.insert("aaa");
  19.         set1.insert("ccc");
  20.         set<string>::iterator it = set1.find("aAa");  // find函数默认区分大小写
  21.         if (it == set1.end())
  22.         {
  23.                 cout << "未查找到aaa " << endl;
  24.         }
  25.         else
  26.         {
  27.                 cout << "查找到aaa " << endl;
  28.         }

  29.         set<string, CompareNoCap> set2;
  30.         set2.insert("bbb");
  31.         set2.insert("aaa");
  32.         set2.insert("ccc");
  33.         set<string, CompareNoCap>::iterator it2 = set2.find("aAa");  // find函数不区分大小写
  34.         if (it2 == set2.end())
  35.         {
  36.                 cout << "未查找到aAa " << endl;
  37.         }
  38.         else
  39.         {
  40.                 cout << "不区分大小写查找到aaa " << endl;
  41.         }
  42. }
复制代码

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-22 12:37

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表