四、STL之函数对象
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载 "()" 操作符,使得类对象可以像函数那样调用。
注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了 "()" 操作符使得它可以像函数一样调用。
分类:假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
函数对象的作用主要是什么?STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。
/* 1. 函数对象 很像函数调用方式,因此也成仿函数 2. 函数对象超出了普通函数的概念,内部可以拥有自己的状态 3. 函数对象可以作为函数的参数传递 */ #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> using namespace std; class Person { public: void operator()(int num) { cout << num << endl; count++; } int count = 0; }; void doWork(Person p, int num) { p(num); } void test() { Person p; // 1. 函数对象 很像函数调用方式,因此也成仿函数 p(100); // 100 p(100); // 100 p(100); // 100 p(100); // 100 // 2. 函数对象超出了普通函数的概念,内部可以拥有自己的状态 cout << "count = " << p.count << endl; // count = 4 // 3. 函数对象可以作为函数的参数传递 doWork(p, 1000); } int main() { test(); return EXIT_SUCCESS; }
总结:
1、函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题。
2、函数对象超出普通函数的概念,函数对象可以有自己的状态
3、函数对象可内联编译,性能好。用函数指针几乎不可能
4、模版函数对象使函数对象具有通用性,这也是它的优势之一
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> #include<vector> #include<algorithm> using namespace std; class GreaterThen20 { public: bool operator()(int val) { return val > 20; } }; // 一元谓词 void test01() { vector<int> v; v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); // 找到第一个大于20的数字 find_if <algorithm> vector<int>::iterator pos = find_if(v.begin(), v.end(), GreaterThen20()); if (pos != v.end()) { cout << "找到大于20的数字: " << *pos << endl; } else { cout << "未找到" << endl; } } class sortBig2Small { public: bool operator() (int v1, int v2) { return v1 > v2; } }; // 二元谓词 void test02() { vector<int> v; v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); // 从大到小排序 sort(v.begin(), v.end(), sortBig2Small()); // [](){} 匿名函数 lambda [] 代表匿名函数声明, () 参数, {} 实现提 for_each(v.begin(), v.end(), [](int val){cout << val << " "; }); // 40 30 20 10 } int main() { test01(); test02(); return EXIT_SUCCESS; }
// 6个算数类函数对象,除了negate是一元运算,其他都是二元运算。 template<class T> T plus<T>//加法仿函数 template<class T> T minus<T>//减法仿函数 template<class T> T multiplies<T>//乘法仿函数 template<class T> T divides<T>//除法仿函数 template<class T> T modulus<T>//取模仿函数 template<class T> T negate<T>//取反仿函数 // 6个关系运算类函数对象,每一种都是二元运算。 template<class T> bool equal_to<T>//等于 template<class T> bool not_equal_to<T>//不等于 template<class T> bool greater<T>//大于 template<class T> bool greater_equal<T>//大于等于 template<class T> bool less<T>//小于 template<class T> bool less_equal<T>//小于等于 // 逻辑运算类运算函数,not为一元运算,其余为二元运算。 template<class T> bool logical_and<T>//逻辑与 template<class T> bool logical_or<T>//逻辑或 template<class T> bool logical_not<T>//逻辑非#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> #include<algorithm> #include<vector> #include<functional> using namespace std; void test() { // 取反仿函数 negate<int> n; cout << n(10) << endl; // -10 // 加法仿函数 plus<int> p1; cout << p1(1, 3) << endl; // 4 // 大于 greater vector<int> v; v.push_back(10); v.push_back(30); v.push_back(40); v.push_back(20); v.push_back(50); sort(v.begin(), v.end(), greater<int>()); for_each(v.begin(), v.end(), [](int val){cout << val << " "; }); // 50 40 30 20 10 } int main() { test(); return EXIT_SUCCESS; }
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<string> #include<algorithm> #include<vector> #include<functional> using namespace std; // 1. 普通函数适配器 bind2nd class MyPrint { public: void operator()(int val) { cout << val << " "; } }; class MyPrint02 : public binary_function<int, int, void> { public: void operator()(int val, int start) const { cout << "val = " << val << " start = " << start << " val + start = "<< val + start << endl; } }; void test01() { vector<int> v; for (int i = 0; i < 5; i++) { v.push_back(i); } for_each(v.begin(), v.end(), MyPrint()); // 0 1 2 3 4 cout << endl; // 如果需要在输出的结果上加上一个任意值 ,比如 100,这个值需要当做参数传递过去 // 1. 将参数进行绑定 bind2ed() // 2. 做继承, 继承类 binary_function<类型1, 类型2, 返回值类型> // 3. 加上const, 在重载()加上const, 否则父类的时候会重载() for_each(v.begin(), v.end(), bind2nd(MyPrint02(), 100)); // 100 101 102 103 104 } // 2. 取反适配器 not1 class GreatThen3 { public: bool operator()(int val) { return val > 3; } }; class GreatThen3New:public unary_function<int, bool> { public: bool operator()(int val) const { return val > 3; } }; void test02() { vector<int> v; for (int i = 0; i < 5; i++) { v.push_back(i); } // 在容器中大于 3 的数 vector<int>::iterator pos = find_if(v.begin(), v.end(), GreatThen3()); if (pos != v.end()) { cout << "找到了大于3的数字为: " << *pos << endl; } else { cout << "未找到" << endl; } // 现在需要找 < 3 的数, 不能修改仿函数的内容, 用取反适配器 // 1. 加上 not1 // 2. 继承 unary_function<类型1, 返回值类型> // 3. 加上 const pos = find_if(v.begin(), v.end(), not1(GreatThen3New()));// not1 一元取反适配器 if (pos != v.end()) { cout << "找到了小于3的数字为: " << *pos << endl; // 找到了小于3的数字为: 0 } else { cout << "未找到" << endl; } } // 3. 函数指针适配器 ptr_fun void PrintFunc01(int val) { cout << val << " "; } void PrintFunc02(int val, int start) { cout << val + start << " "; } void test03() { vector<int> v; for (int i = 0; i < 5; i++) { v.push_back(i); } // 可以加仿函数 for_each(v.begin(), v.end(), bind2nd(MyPrint02(), 100)); // 100 101 102 103 104 cout << endl; // 也可以加函数对象 for_each(v.begin(), v.end(), PrintFunc01); cout << endl; // 加上自定义参数 // for_each(v.begin(), v.end(), bind2nd(PrintFunc, 100)); 按照普通函数适配器的话, 需要函数 PrintFunc 继承类,不行,加上 const也不行,所以此种方法不行了。 // 函数指针适配器, 将函数指针 适配成函数对象 ptr_fun for_each(v.begin(), v.end(), bind2nd(ptr_fun(PrintFunc02), 100)); cout << endl; } // 4. 成员函数适配器 mem_fun_ref class Person { public: Person(string name, int age) { this->Name = name; this->Age = age; } void printPerson() { cout << "成员函数: 姓名: " << this->Name << " 年龄: " << this->Age << endl; } string Name; int Age; }; void printPerson(Person &p) { cout << "姓名: " << p.Name << " 年龄: " << p.Age << endl; } void test04() { vector<Person> v; Person p1("aaa", 10); Person p2("bbb", 20); Person p3("ccc", 30); Person p4("ddd", 40); Person p5("eee", 50); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); // 全局函数 for_each(v.begin(), v.end(), printPerson); // 成员函数 for_each(v.begin(), v.end(), mem_fun_ref(&Person::printPerson)); } int main() { test01(); test02(); test03(); test04(); return EXIT_SUCCESS; }
浙公网安备 33010602011771号