《C++ Primer》第14章 操作重载与类型转换
14.8节 函数调用运算符 习题答案
练习14.33:一个重载的函数调用运算符应该接受几个运算对象?
【出题思路】
理解调用运算符。
【解答】
0个或多个。
练习14.34:定义一个函数对象类,令其执行if-then-else的操作:该类的调用运算符接受三个形参,它首先检查第一个形参,如果成功返回第二个形参的值,如果不成功返回第三个形参的值。
【出题思路】
本题练习定义调用运算符。
【解答】
#include <iostream>
#include <string>
#include<sstream> //istringstream 必须包含这个头文件
using namespace std;
class IfElseThen
{
public:
IfElseThen() { }
IfElseThen(int i1, int i2, int i3): iVal1(i1), iVal2(i2), iVal3(i3)
{
}
int operator() (int i1, int i2, int i3)
{
return i1 ? i2 : i3;
}
void print()
{
cout << "iVal1 = " << iVal1 << " iVal2 = " << iVal2 << " iVal3 = " << iVal3 << endl;
}
private:
int iVal1, iVal2, iVal3;
};
int main()
{
IfElseThen ifelse;
cout << "ifelse==========" << ifelse(5, 6, 2) << endl;
return 0;
}
运行结果:ifelse==========6
练习14.35:编写一个类似于PrintString的类,令其从istream中读取一行输入,然后返回一个表示我们所读内容的string。如果读取失败,返回空string。
【出题思路】
本题练习定义调用运算符。
【解答】
#include <iostream>
#include <string>
using namespace std;
class ReadString
{
public:
ReadString(istream &is = cin)
:is(is)
{
}
string operator()()
{
string line;
if(!getline(is, line))
{
line = " ";
}
return line;
}
private:
istream &is;
};
int main()
{
ReadString readString;
cout << "call operator() = " << readString() << endl;
return 0;
}
运行结果:
练习14.36:使用前一个练习定义的类读取标准输入,将每一行保存为vector的一个元素。
【出题思路】
本题练习使用调用运算符。
【解答】
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class ReadString
{
public:
ReadString(istream &is = cin)
:is(is)
{
}
string operator()()//重载函数对象运行符
{
string line;
if(!getline(is, line))
{
line = " ";
}
return line;
}
private:
istream &is;
};
void testReadString()
{
ReadString rs;
vector<string> vec;
while(true)
{
string line = rs(); //调用函数对象
if(!line.empty())
{
vec.push_back(line);
}
else
{
break;
}
}
cout << "output==============" << endl;
for(auto iter: vec)
{
cout << iter << endl;
}
}
int main()
{
testReadString();
return 0;
}
运行结果:
练习14.37:编写一个类令其检查两个值是否相等。使用该对象及标准库算法编写程序,令其替换某个序列中具有给定值的所有实例。
【出题思路】
本题练习定义和使用调用运算符。
【解答】
#include <iostream>
#include <vector>
#include <sstream>
#include <string>
#include <algorithm> // std::replace_if
using namespace std;
class IntCompare
{
public:
IntCompare(int v): val(v)
{
}
bool operator()(int v)
{
return val == v;
}
private:
int val;
};
int main()
{
vector<int> vec = {1,2,3,2,1};
const int oldValue = 2;
const int newValue = 200;
IntCompare icmp(oldValue);
std::replace_if(vec.begin(), vec.end(), icmp, newValue);
cout << "icmp==================" << icmp.operator()(3) << endl;
return 0;
}
运行结果:icmp==================0
练习14.38:编写一个类令其检查某个给定的string对象的长度是否与一个阈值相等。使用该对象编写程序,统计并报告在输入的文件中长度为1的单词有多少个、长度为2的单词有多少个、……、长度为10的单词又有多少个。
【出题思路】
本题练习定义和使用调用运算符。
【解答】
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class StrLenIs
{
public:
StrLenIs(int len):m_len(len)
{ }
bool operator()(const string &str)
{
return str.length() == m_len;
}
private:
int m_len;
};
void readStr(istream &is, vector<string> &vec)
{
string word;
while(is >> word)
{
vec.push_back(word);
}
}
int main()
{
vector<string> vec;
readStr(cin, vec);
const int minLen = 1;
const int maxLen = 10;
for(int i = minLen; i <= maxLen; i++)
{
StrLenIs slenIs(i);
//相当于每次调用 slenIs(vec.at(i))
cout << "len:" << i << ",count:" << count_if(vec.begin(), vec.end(), slenIs) << endl;
}
return 0;
}
运行结果:
练习14.39:修改上一题的程序令其报告长度在1至9之间的单词有多少个、长度在10以上的单词又有多少个。
【出题思路】
本题练习定义和使用调用运算符。
【解答】
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class StrLenBetween
{
public:
StrLenBetween(int minLen, int maxLen):
minLen(minLen), maxLen(maxLen)
{ }
bool operator()(const string &str)
{
return str.length() >= minLen && str.length() <= maxLen;
}
private:
int minLen;
int maxLen;
};
class StrNotShorterThan
{
public:
StrNotShorterThan(int len):m_len(len)
{ }
bool operator()(const string &str)
{
return str.length() >= m_len;
}
//重载函数调用符
int operator()() { return m_len; }
private:
int m_len;
};
void readStr(istream &is, vector<string> &vec)
{
string word;
while(is >> word)
{
vec.push_back(word);
}
}
int main()
{
vector<string> vec;
readStr(cin, vec);
StrLenBetween slenBetween(1, 9);
StrNotShorterThan sNotShorterThan(10);
cout << "len 1~9: " << count_if(vec.begin(), vec.end(), slenBetween) << endl;
cout << "len >=10: " << count_if(vec.begin(), vec.end(), sNotShorterThan) << endl;
cout << endl;
return 0;
}
运行结果:
练习14.40:重新编写10.3.2节(第349页)的biggies函数,使用函数对象类替换其中的lambda表达式。
【出题思路】
本题练习定义和使用调用运算符。
【解答】
#include <iostream>
#include <string>
#include <sstream> //istringstream 必须包含这个头文件
#include <vector>
#include <algorithm>
using namespace std;
inline
string make_plural(size_t ctr, const string &word,
const string &ending)
{
return (ctr > 1) ? word + ending : word;
}
class IsShoter
{
public:
bool operator() (const string &s1, const string &s2) const
{
return s1.size() < s2.size();
}
};
class NotShorterThan
{
public:
NotShorterThan(int len): miniLen(len)
{
}
bool operator() (const string &str)
{
return str.size() >= miniLen;
}
private:
int miniLen;
};
class PrintString
{
public:
//PrintString() = delete;
PrintString(ostream &o = cout): os(o)
{
}
void operator() (const string &str)
{
cout << str << " ";
}
private:
ostream &os;
};
void elimDups(vector<string> &words)
{
sort(words.begin(), words.end());
for_each(words.begin(), words.end(), PrintString(cerr));
cerr << endl;
auto end_unique = unique(words.begin(), words.end());
words.erase(end_unique, words.end());
for_each(words.begin(), words.end(), PrintString(cerr));
cerr << endl;
}
void biggies(vector<string> &words, vector<string>::size_type sz)
{
elimDups(words);
IsShoter is;
stable_sort(words.begin(), words.end(), is);
NotShorterThan nst(sz);
auto wc = find_if(words.begin(), words.end(), nst);
auto count = words.end() - wc;
cout << count << " " << make_plural(count, "word", "s") << " of length " << sz << " or longer " << endl;
PrintString ps;
for_each(wc, words.end(), ps);
cout << endl;
}
int main()
{
vector<string> words;
string next_word;
while(cin >> next_word)
{
words.push_back(next_word);
}
biggies(words, 6);
cout << "Hello World!" << endl;
return 0;
}
运行结果:
练习14.41:你认为C++11新标准为什么要增加lambda?对于你自己来说,什么情况下会使用lambda,什么情况下会使用类?
【出题思路】
本题旨在理解lambda。
【解答】
在C++11中,lambda是通过匿名的函数对象来实现的,因此我们可以把lambda看作是对函数对象在使用方式上进行的简化。当代码需要一个简单的函数,并且这个函数并不会在其他地方被使用时,就可以使用lambda来实现,此时它所起的作用类似于匿名函数。但如果这个函数需要多次使用,并且它需要保存某些状态的话,使用函数对象则更合适一些。
练习14.42:使用标准库函数对象及适配器定义一条表达式,令其
(a)统计大于1024的值有多少个。
(b)找到第一个不等于pooh的字符串。
(c)将所有的值乘以2。
【出题思路】
本题练习使用函数对象。
【解答】
(a): count_if(vec.begin(), vec.end(), bind2nd(greater<int>(), 1024));
(b): find_if(vec.begin(), vec.end(), bind2nd(not_equal_to<string>(), "pooh"));
(c): transform(vec.begin(), vec.end(), vec.begin(), bind2nd(multiplies<int>(), 2));
练习14.43:使用标准库函数对象判断一个给定的int值是否能被int容器中的所有元素整除。
【出题思路】
本题练习使用函数对象。
【解答】
#include <iostream>
#include <string>
#include <sstream> //istringstream 必须包含这个头文件
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
bool dividedByAll(vector<int> &ivec, int dividend)
{
int nInt = count_if(ivec.begin(), ivec.end(), bind1st(modulus<int>(), dividend));
cout << "nInt=====================" << nInt << endl;
return nInt == 0;
}
int main()
{
vector<int> nInt = {12, 36, 58, 96, 78, 62};
bool bValue = dividedByAll(nInt, 3);
if(bValue)
cout << "所有的数都能被3整除======" << endl;
else
cout << "有的数不能被3整除======" << endl;
bool bValue2 = dividedByAll(nInt, 2);
if(bValue2)
cout << "所有的数都能被2整除======" << endl;
else
cout << "有的数不能被2整除======" << endl;
cout << "Hello World!" << endl;
return 0;
}
运行结果:
练习14.44:编写一个简单的桌面计算器使其能处理二元运算。
【出题思路】
本题练习使用函数对象。
【解答】
#include <iostream>
#include <map>
#include <string>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;
map<string, function<int (int,int)> > binOps = {
{"+", plus<int>()},
{"-", minus<int>()},
{"*", multiplies<int>()},
{"/", divides<int>()},
{"%", modulus<int>()}
};
int main()
{
int left, right;
string op;
cin >> left >> op >> right;
cout << binOps[op](left, right);
return 0;
}
运行结果: