zoukankan      html  css  js  c++  java
  • 最佳谓词函数 --- 函数对象

    前言

      学习C++标准算法时,我们知道带有_if的算法都带有一个谓词函数。此前我们直接使用函数名充当谓词函数,这样做有很大的局限性( 下文会做分析 )。为此本文将介绍C++中一个新的技术:函数对象。用它来充当谓词函数就能解决这个问题。

    什么是函数对象?

      函数对象就是重载了函数调用操作符的对象。我们知道,函数调用规则已经非常固定了,那么为何要重载函数调用操作符呢?因为重载后,这个函数调用操作符将不再用作一般意义的函数调用功能。不能调用各种函数的对象那还叫对象吗?从语义上来讲,它不符合对象的设定原则" 对现实事物的虚拟 ",因此我们叫它函数对象以区别于其他对象。那这样的对象有什么用?这个问题稍后讨论,下面来看一个简单的用作求绝对值的函数对象实现:

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 /*
     7  * 1. 函数对象的作用是虚拟函数,因此对它的命名也按照函数命名规范。
     8  * 2. 重载了函数调用操作符,构造函数也不能用了。当然函数对象只需要()这一个" 函数 ",无需定义其他任何
     9  *    函数,包括构造函数。
    10 */
    11 class absInt {
    12 public:
    13     int operator() (int val) {
    14         return val < 0? -val : val;
    15     }
    16 };
    17 
    18 
    19 int main()
    20 {
    21     absInt absObj;
    22     int val1 = -1;
    23     int val2 = 1;
    24 
    25     /*
    26      * absObj本质是对象,但它虚拟成了一个返回绝对值的函数。
    27     */
    28     cout << absObj(val1) << endl;
    29     cout << absObj(val2) << endl;
    30 
    31     return 0;
    32 }

      运行结果:

      

      仔细阅读代码便能发现,该程序将对象虚拟化为一个函数来用。

    为何要定义函数对象?

      要对象就用对象,函数就用函数,为何费那么大劲把对象整成函数?相信有人会这么问。别急,我们先来回顾一个使用标准算法的例子,这个代码返回容器中长度超过6的单词:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <vector>
     4 #include <string>
     5 
     6 using namespace std;
     7 
     8 bool GT6 (const string &s) {
     9     return s.size() >= 6;
    10 }
    11 
    12 int main()
    13 {
    14     /*
    15      * 构建测试容器
    16     */
    17     vector<string> words;
    18     words.push_back("China");
    19     words.push_back("America");
    20     words.push_back("England");
    21     words.push_back("Japan");
    22 
    23     // 获取容器中长度大于6的字符串的个数
    24     vector<string> :: size_type wc = count_if(words.begin(), words.end(), GT6);
    25 
    26     // 打印结果
    27     cout << wc << endl;
    28 
    29     return 0;
    30 }

      这段代码没有问题,正常地返回了结果:

      

      但是,如果我改变注意了,又想获得长度大于5的字符串,那么我该怎么做?修改函数调用操作符重载函数是可行的办法,但是当函数复杂起来的时候,这会是一个很麻烦的工作。好在改用函数对象充当谓词函数后就能解决这个问题了。

    使用函数对象的改进版本

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <vector>
     4 #include <string>
     5 
     6 using namespace std;
     7 
     8 class GT_cls {
     9 public:
    10     GT_cls (string::size_type val=0) : bound(val) {};
    11     bool operator() (const string &s) {
    12         return s.size() >= bound;
    13     }
    14         
    15 private:
    16     string::size_type bound;
    17 };
    18 
    19 int main()
    20 {
    21     /*
    22      * 构建测试容器
    23     */
    24     vector<string> words;
    25     words.push_back("China");
    26     words.push_back("America");
    27     words.push_back("England");
    28     words.push_back("Japan");
    29 
    30     /*
    31      * 获取容器中长度大于6的字符串的个数
    32      * 如要取长度大于5的,只要将下面语句中的6改成5即可,不用修改重载函数。
    33     */
    34     vector<string> :: size_type wc = count_if(words.begin(), words.end(), GT_cls(5));
    35 
    36     // 打印结果
    37     cout << wc << endl;
    38 
    39     return 0;
    40 }

      运行结果:

      

      如果要找长度大于8的单词个数?同理,将函数对象参数改成8即可。

    说明

      请细细体会上面的代码,分析其执行过程。

  • 相关阅读:
    Java魔法堂:String.format详解
    Postgresql 正则表达式
    Linux下安装LAMP(Apache+PHP+MySql)和禅道
    Redis 启动警告错误解决[转]
    Postgresql: UUID的使用
    在Linux下安装RabbitMQ
    Python的包管理工具Pip
    在Linux CentOS 6.6上安装RedisLive
    [转]在Linux CentOS 6.6上安装Python 2.7.9
    在Linux上rpm安装运行Redis 3.0.4
  • 原文地址:https://www.cnblogs.com/scut-fm/p/3245398.html
Copyright © 2011-2022 走看看