重载操作符与转换
--调用操作符和函数对象
引言:
可以为类类型的对象重载函数调用操作符:一般为表示操作的类重载调用操作符!
struct absInt
{
int operator() (int val)
{
return val > 0 val : -val;
}
};
通过为类类型的对象提供一个实参表而使用调用操作符,所用的方式看起来系那个一个函数调用:
absInt absObj;
int i = -1;
cout << absObj(i) << endl;
尽管absObj是一个对象而不是函数,我们仍然可以“调用”该对象,效果是运行有absObj对象定义的重载调用操作符,该操作接受一个int值并返回它的绝对值。
函数调用操作符必须声明为成员函数,一个类可以定义函数调用操作符的多个版本,由形参的数目或类型加以区别。
定义了调用操作符的类,其对象常称为函数对象,即它们是行为类似函数的对象!
//P450 习题14.31
struct ifElse
{
int operator() (int x,int y,int z)
{
return x y : z;
}
};
int main()
{
ifElse ifObj;
cout << ifObj(0,1,2) << endl;
cout << ifObj(1,1,2) << endl;
}
一、将函数对象用于标准库算法
函数对象经常用作通用算法的实参。回忆曾经的一段程序:
bool GT6(const string &str)
{
return str.size() > 6;
}
使用GT6作为传给count_if算法的实参,以计算使GT6返回true的单词数目:
vector::size_type wc = count_if(words.begin(),words.end(),GT6);
1、函数对象可以比函数更灵活
通过将GT6定义为带函数调用成员的类,可以使得传递的string与我们想要的长度进行测试,这样,可以使用同一段代码对不同长度的字符串进行计数:
class GT_cls
{
public:
GT_cls(size_t val = 0):bound(val){}
bool operator() (const string &str)
{
return str.size() >= bound;
}
private:
std::string::size_type bound;
};
2、使用GT_cls函数对象
cout << count_if(words.begin(),words.end(),GT_cls(6))
<< " words 6 characters or longer" << endl;
这个count_if调用传递一个GT_cls类型的临时对象而不再是名为GT6的函数。用整型值6来初始化那个临时对象,构造函数将这个值存储在bound成员中。现在,count_if每次调用它的函数形参时,它都使用GT_cls的调用操作符,该调用操作符根据bound的值测试其string实参的长度。
使用函数对象,容易修改程序以根据其他值进行测试,只需为传给count_if的对象改变构造函数实参即可。
//计算长度在5个字符以上的单词数
cout << count_if(words.begin(),words.end(),GT_cls(5))
<< " words 6 characters or longer" << endl;
还可以用来计算长度在1到10个字符的单词数:
for (size_t i = 1; i != 11; ++i)
{
cout << count_if(words.begin(),words.end(),GT_cls(i))
<< " words " << i << " characters or longer" << endl;
}
如果使用函数替代函数对象来编写这个程序,可能需要编写10个(⊙ ⊙b汗)不同的函数,每个函数测试一个不同的值!
//P451 习题14.33
class GT_cls
{
public:
GT_cls(size_t val = 0):bound(val) {}
bool operator() (const string &str)
{
return str.size() > bound; //将>=改为>
}
private:
std::string::size_type bound;
};
int main()
{
vector
words;
ifstream inFile("input");
string word;
while (inFile >> word)
{
words.push_back(word);
}
vector
::iterator findIter = find_if(words.begin(),words.end(),GT_cls(5)); if(findIter != words.end()) { cout << *findIter << endl; } else { cout << "Have No Found!" << endl; } }
//习题14.34
struct IsSame
{
bool operator() (const string &s1,const string &s2)
{
return s1 == s2;
}
};
int main()
{
IsSame isSame;
cout << isSame("xiao","fang") << endl;
cout << isSame("Ha","Ha") << endl;
}
//习题14.35/36
class BET_cls
{
public:
BET_cls(size_t Max = 0,size_t Min = 0):max(Max),min(Min) {}
bool operator() (const string &str)
{
return str.size() <= max && str.size() >= min;
}
private:
std::string::size_type max;
std::string::size_type min;
};
class GT_cls
{
public:
GT_cls(size_t size = 0):bound(size) {}
bool operator() (const string &str)
{
return str.size() >= bound;
}
private:
std::string::size_type bound;
};
int main()
{
ifstream inFile("input");
vector
words;
string word;
while (inFile >> word)
{
words.push_back(word);
}
cout << "The is " << count_if(words.begin(),words.end(),BET_cls(9,1))
<< " words`s size is between 1 and 9" << endl;
cout << "And " << count_if(words.begin(),words.end(),GT_cls(10))
<< " words`s size is equal to 10 or longer" << endl;
}
二、标准库定义的函数对象
标准库定义了一组算术、关系与逻辑函数对象类。标准库还定义了一组函数适配器,使我们能够特化或者扩展标准库所定义的以及自定义的函数对象类。这些标准库函数对象类型是在functional头文件中定义的。
标准库函数对象 |
||
|---|---|---|
类型 |
函数对象 |
所应用的操作符 |
算术函数对象类型 |
plus
|
+ |
minus
|
- |
|
multiplies
|
* |
|
divides
|
/ |
|
modulus
|
% |
|
关系函数对象类型 |
negate
|
- |
equal_to
|
== |
|
not_equal_to
|
!= |
|
greater
|
> |
|
greater_equal
|
>= |
|
less
|
< |
|
less_equal
|
<= |
|
逻辑函数对象类型 |
logical_and
|
&& |
logical_or
|
|| |
|
logical_not
|
! |
|
1、每个类表示一个给定操作符
每个标准库函数对象类表示一个操作符,即每个类都定义了应用命名操作的调用操作符。如plus是表示加法操作符的模板类型,plus模板中的调用操作符对一对操作数使用+运算!
//假设Type类型为int,简单实现一下plus
class Plus
{
public:
int operator() (int a,int b)
{
return a + b;
}
//...
};
有两个一元函数对象类:一元减(negate