目录
算数类函数对象:(除了 negate是一元运算,其他都是二元运算)
函数对象,就是可以当作函数使用的对象。
类中重载了(),这个类实例化的对象叫做函数对象(仿函数)。
假定某个类有一个重载的 operator(),根据需要获取的参数个数分为:
函数对象的作用:作为算法策略。
STL 中有以下实现“累加”功能的算法(函数模板),该模板的功能是对(first,last)中的每个迭代器 I 执行 val = op(val, *I),返回最终的 val。
在头文件 numeric.h 中,accumulate 的源码如下:
- #include
- template <class InIt, class T, class Fn>
- T accumulate(const InIt first, const InIt last, T val, Fn op)
- {
- for (; first != last; ++first)
- val = op(val, *first);
- return val;
- }
此模板被实例化后,op(val, *first) 必须要有定义,则 op 只能是函数指针或函数对象。因此调用 accumulate 模板时,形参 op 对应的实参只能是函数名、函数指针或者函数对象。
eg:通过 accumulate 模板求一个 vector 中元素的平方和。
- #include
-
- template <class T>
- void PrintInterval(T first, T last)
- { //输出区间[first,last]中的元素
- for (; first != last; ++first)
- cout << *first << " ";
- cout << endl;
- }
- int SumSquares(int total, int value)
- {
- return total + value * value;
- }
- template <class T>
- class SumPowers
- {
- private:
- int power;
- public:
- SumPowers(int p):power(p){}
- const T operator()(const T& total, const T& value)
- { //计算 value 的 power 次方,并加到total上
- T v = value;
- for (int i = 0; i < power - 1; ++i)
- {
- v = v * value;
- }
- return total + v;
- }
- };
-
- void test24()
- {
- const int size = 5;
- int a1[] = { 1,2,3,4,5 };
- vector<int> v(a1, a1 + size);
- cout << "(1)";
- PrintInterval(v.begin(), v.end());
-
- int result = accumulate(v.begin(), v.end(), 0, SumSquares);
- cout << "(2)平方和: " << result << endl;
-
- result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(3));
- cout << "(3)立方和: " << result << endl;
-
- result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(4));
- cout << "(4)4次方和: " << result << endl;
- }
注释:
1.
int result = accumulate(v.begin(), v.end(), 0, SumSquares);
第四个参数是函数名。函数名字的类型是函数指针,因此本行将 accumulate 模板实例化后得到的模板函数定义如下:
- int accumulate(vector<int>::iterator first, vector<int>::iterator last, int val, int(*op)(int, int))
- {
- for (; first != last; ++first)
- val = op(val, *first);
- return val;
- }
形参 op 是一个函数指针,而 op(val, *first) 就调用了指针 op 指向的函数,即函数 SumSquares。
2.
result = accumulate(v.begin(), v.end(), 0, SumPowers<int>(3));
第四个参数是 SumPowes
编译器在编译此行时,会将 accumulate 模板实例化为以下函数:
- int accumulate(vector<int>::iterator first, vector<int>::iterator last, int val, SumPowers<int> op)
- {
- for (; first != last; ++first)
- val = op(val, *first);
- return val;
- }
形参 op 是一个函数对象,而 op(val, *first) 等价于:
op.operator()(val, *first);
即调用了 SumPowers
对比 1 和 2,函数对象的 operator() 成员函数可以根据对象内部的不同状态执行不同操作。???
STL 中定义了一些函数对象类模板,都位于头文件 functional 中。
- template<class T>
- struct greater
- {
- bool operator()(const T& x, const T& y)const
- {
- return x > y;
- }
- };
- #include
- #include
- #include
-
- void test18()
- {
- vector<int> v;
- v.push_back(4);
- v.push_back(7);
- v.push_back(3);
-
- sort(v.begin(), v.end(), greater<int>());
-
- for_each(v.begin(), v.end(), [](int val) {cout << val << " "; });
- //[](int val) {cout << val << " "; } //匿名函数
- }
STL 中的排序模板 sort 能将区间从小到大排序。
(1)该模板要求first、last是随机访问迭代器,元素比较大小是用 < 进行的。
- template <class T>
- void sort(const T first, const T last);
(2)该版本中,元素a、b比较大小是通过表达式 op(a,b) 进行的,op 定义了元素比较大小的规则。例如上边那个例子。
- template <class T, class Pr>
- void sort(const T first, const T last, Pr op);
eg:sort 算法
- #include
//sort算法在此头文件中定义 - template <class T>
- void Printval(T first, T last)
- {
- for (; first != last; ++first)
- cout << *first << " ";
- cout << endl;
- }
-
- class A
- {
- public:
- bool operator<(const A& a)
- {
- return this->v < a.v;
- }
- public:
- int v;
- A(int n):v(n){}
- };
- //bool operator<(const A& a1, const A& a2) //也可以重载为A的const成员函数
- //{
- // return a1.v < a2.v;
- //}
- bool GreaterA(const A& a1, const A& a2)
- {
- return a1.v > a2.v;
- }
- struct LessA
- {
- bool operator()(const A& a1, const A& a2)
- {
- return (a1.v % 10) < (a2.v % 10);
- }
- };
- ostream& operator<<(ostream& o, const A& a)
- {
- o << a.v;
- return o;
- }
- void test25()
- {
- int a1[4] = { 1,5,2,7};
- A a2[5] = { 43,1,8,45,62 };
-
- sort(a1, a1 + 4);
- cout << "(1) "; Printval(a1, a1 + 4);
-
- sort(a2, a2 + 5);
- cout << "(2) "; Printval(a2, a2 + 5); //按v的值从小到大排序
-
- sort(a2, a2 + 5, GreaterA); //按v的值从大到小排序
- cout << "(3) "; Printval(a2, a2 + 5);
-
- sort(a2, a2 + 5, LessA()); //按v的个位数从小到大排序
- cout << "(4) "; Printval(a2, a2 + 5);
- }
注释:
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
- template<class T> T plus
//加法仿函数 - template<class T> T minus
//减法 - template<class T> T multiplies
//乘法 - template<class T> T divides
//取整 - template<class T> T modulus
//取余 - template<class T> T negate
//取反
- template<class T>bool equal_to
//等于 - template<class T>bool not_equal_to
//不等于 - template<class T>bool greater
//大于 - template<class T>bool greater_equal
//大于等于 - template<class T>bool less
//小于 - template<class T>bool less_equal
//小于等于
- template<class T>bool logical_and
//逻辑与 - template<class T>bool logical_or
//逻辑或 - template<class T>bool logical_not
//逻辑非
C++继承了C语言的 struct,并且加以扩充。因为考虑到对C兼容,所以C++保留了 struct,并做了一些扩展使其更适合面向对象。
① C语言中,struct 是一种数据类型,只能定义数据成员,而不能定义成员函数。C++中,struct 类似于class,在其中既可以定义数据成员,也可以定义成员函数。
② 默认的继承访问权。class 默认是 private,struct 默认是 public。
③ 默认访问权限。struct 作为数据结构的实现体,它默认的数据访问权限是 public 的;而 class 作为对象的实现体,它默认的成员变量访问权限是 private 的。
可以看出,struct 更适合看成是一个数据结构的实现体,class 更适合看成是一个对象的实现体。