moc 发表于 2018-9-22 14:42:06

053-C++之函数对象与谓词

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

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

        ShowElemt()
        {
                //cout << "ShowElemt构造函数 do!\n";
                n = 0;
        }

        ~ShowElemt()
        {
                //cout << "ShowElemt析构函数 do!\n";
        }
        void printN()
        {
                cout << "n:" << n << endl;
        }
private:
        int n;
};

// 函数模板
template <typename T>
void FunShowElemt(T &t)
{
        cout << t << endl;
}

// 普通函数
void FunShowElem2t(int &t)
{
        cout << t << endl;
}

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

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


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

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

        cout << "*****\n";
        ShowElemt<int> show1;   // 声明一个函数对象
        show1 = for_each(v1.begin(), v1.end(), show1);// for_each函数存在对象做参数和返回值
        show1.printN();
}
3、谓词和函数对象应用举例
1. 一元谓词 => 通过一元谓词查找容器中能被4整除的数
template<typename T>
class IsDiv
{
public:
        IsDiv(const T &divisor)
        {
                this->divisor = divisor;
        }
        bool operator()(T &t)
        {
                return (t % divisor == 0);
        }
private:
        T divisor;
};

void main03()
{
        vector<int> v2;
        int a = 4;
        IsDiv<int> myDiv(a);

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

        //find_if(v2.begin(), v2.end(), IsDiv<int>(a));// 匿名函数对象
        vector<int>::iterator it = find_if(v2.begin(), v2.end(), myDiv);
        if (it == v2.end())
        {
                cout << "没有找到能被4整除的元素\n";
        }
        else
        {
                cout << "第一个能被4整除的元素" << *it << endl;
        }
}
2. 二元函数对象 => 容器v1、v2对应位置元素之和给到v3的对应位置。
// 二元函数对象
template <typename T>
class SumAdd
{
public:
        T operator()(T t1, T t2)
        {
                return t1 + t2;
        }
};
void main04()
{
        vector<int> v1, v2, v3;
        v1.push_back(1);
        v1.push_back(4);
        v1.push_back(7);

        v2.push_back(2);
        v2.push_back(5);
        v2.push_back(8);

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

        transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), SumAdd<int>()); // 谓词
        for (auto each : v3)
        {
                cout << each << endl;
        }
}
3. 二元谓词 => 容器中元素的排序
// 二元谓词
bool myCompare(const int &a, const int &b)
{
        return a < b;// 从小到大
}

void main05()
{
        vector<int> v1(10);
        for (int i = 0; i < 10; i++)
        {
                int tmp = rand() % 100;
                v1 = tmp;
        }
        for (auto each : v1)
        {
                cout << each << " ";
        }
        cout << endl;
        // 排序
        sort(v1.begin(), v1.end(), myCompare);
        for (auto each : v1)
        {
                cout << each << " ";
        }
}
4. 二元谓词在集合中的应用 =>集合不区分大小写查找元素。

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

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

                return (str1_ < str2_);
        }
};

void main06()
{
        set<string> set1;
        set1.insert("bbb");
        set1.insert("aaa");
        set1.insert("ccc");
        set<string>::iterator it = set1.find("aAa");// find函数默认区分大小写
        if (it == set1.end())
        {
                cout << "未查找到aaa " << endl;
        }
        else
        {
                cout << "查找到aaa " << endl;
        }

        set<string, CompareNoCap> set2;
        set2.insert("bbb");
        set2.insert("aaa");
        set2.insert("ccc");
        set<string, CompareNoCap>::iterator it2 = set2.find("aAa");// find函数不区分大小写
        if (it2 == set2.end())
        {
                cout << "未查找到aAa " << endl;
        }
        else
        {
                cout << "不区分大小写查找到aaa " << endl;
        }
}
页: [1]
查看完整版本: 053-C++之函数对象与谓词