21、C++ Primer 4th 笔记,重载运算符(2)
1、自增操作符和自减操作符
为了与内置类型一致,前缀操作符应返回被增量或减量对象的引用;后辍式操作符应返回旧值(不是引用)。后辍式操作符函数接受一个额外的(即无用的)int型形参。
示例
#include "iostream" #include "stdio.h" using namespace std; class CheckedPtr { public: CheckedPtr(int *b, int *e):beg(b), end(e), curr(e){} public: CheckedPtr& operator++(); //前辍 CheckedPtr& operator--(); CheckedPtr operator++(int);//后辍 CheckedPtr operator--(int); private: int *beg; int *end; int *curr; }; CheckedPtr& CheckedPtr::operator++() { if (curr == end) throw out_of_range("increment past the end of CheckedPtr"); ++curr; return *this; } CheckedPtr& CheckedPtr::operator--() { if (curr == beg) throw out_of_range("decrement past the beginning of CheckedPtr"); --curr; return *this; } CheckedPtr CheckedPtr::operator++(int) { CheckedPtr ret(*this); ++*this; //调用前辍增量操作符,在本函数中无需作越界检查 return ret; } CheckedPtr CheckedPtr::operator--(int) { CheckedPtr ret(*this); --*this; //调用前辍减量操作符,在本函数中无需作越界检查 return ret; } int main() { CheckedPtr parr(ia, ia + size); parr.operator++(0); //显式调用后辍增量操作符 parr.operator++(); //显式调用前辍增量操作符 return 0; }
显式调用操作符
示例如上中。
所传递的值通常会被忽略,便是必要的。
2、函数调用操作符和函数对象
可以为类类型的对象重载函数调用操作符。一般表示操作的类重载调用操作符。函数调用操作符必须声明为成员函数,可以重载(由形参的数目或类别加以区别)。
示例
#include "iostream" #include "stdio.h" using namespace std; struct absInt { int operator()(int val) { return val < 0 ? -val:val; } }; int main() { int i = -42; absInt absOjb; unsigned int ui = absOjb(i); return 0; }
通过为类类型的对象提供一个实参表而使用调用操作符,看起来像一个函数调用。定义了函数调用操作符的类,其对象常称为函数对象,即他们是行为类似函数的对象。
3、将函数对象用于标准库算法
使用谓词函数示例
#include "iostream" #include "stdio.h" using namespace std; bool GT6(const string &s) { return s.size() >= 6; } int main() { vector<string>::size_type wc = count_if(words.begin(), words.end(), GT6) return 0; }
使用函数对象比使用谓词函数更灵活。
函数对象示例
#include "iostream" #include "stdio.h" #include "algorithm" #include "functional" using namespace std; class GT_cls { public: GT_cls(size_t val = 0):bound(val){} bool operator()(const string &s) { return s.size() >= bound; } private: std::string::size_type bound; }; int main() { vector<string> words; vector<string>::size_type wc = count_if(words.begin(), words.end(), GT_cls(6)); return 0; }
4、标准库定义的函数对象
这些标准库函数对象类型放在functional头文件中定义。
算术函数对象类型 |
函数对象 |
所应用的操作符 |
plus<Type> |
applies + |
|
minus<Type> |
applies - |
|
multiplies<Type> |
applies * |
|
divides<Type> |
applies / |
|
modulus<Type> |
applies % |
|
negate<Type> |
applies - |
|
关系函数对象类型 |
equal_to<Type> |
applies == |
not_equal_to<Type> |
applies != |
|
greater<Type> |
applies > |
|
greater_equal<Type> |
applies >= |
|
less<Type> |
applies < |
|
less_equal<Type> |
applies <= |
|
逻辑函数对象类型 |
logical_and<Type> |
applies && |
logical_or<Type> |
applies | |
|
logical_not<Type> |
applies ! |
有两个一元函数对象类:一元减(negate<Type>))和逻辑非(logical_not<Type>))。其余的标准库函数对象都是表示二元操作符的二元函数对象类。为二元操作符定义的函数调用操作符需要两个给定类型的形参,而一元函数对象类型定义了接受一个实参的调用操作符。
示例
#include "iostream" #include "vector" #include "algorithm" #include "string" #include "functional" using namespace std; class GT_cls { public: GT_cls(size_t val = 0):bound(val){} bool operator()(const string &s) { return s.size() >= bound; } private: std::string::size_type bound; }; int main() { plus<int> intAdd; int sum = intAdd(10, 20); vector<string> svec; sort(svec.begin(), svec.end(), greater<string>() ); cout << sum; }
5、函数对象的函数适配器
标准库提供了一组函数适配器,用于特化和扩展一元和二元函数对象。函数适配器分为如下两类:
1)绑定器,是一种函数适配器,它通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数对象。
2)求反器,是一种函数适配器,它将谓词函数对象的真值求反。
标准库定义了两个绑定器适配器:bind1st 和 bind2nd。每个绑定器接受一个函数对象和一个值。bind1st 将给定值绑定到二元函数对象的第一个实参,bind2nd 将给定值绑定到二元函数对象的第二个实参。
标准库还定义了两个求反器:not1 和 not2。not1 将一元函数对象的真值求反,not2 将二元函数对象的真值求反。
示例
count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10)); count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)));