C++primer第十四章答案(第五版)
代码参考
14.1
在代码实行方面有所不同,但在逻辑方面应该相符,重载的运算符其优先级和结合律与对应的内置运算符保持一致。
14.2
istream& operator>> (istream& is, Sales_data& s)
{
double price;
is >> s.bookNo >> s.units_sold >> price;
s.revenue = price * s.units_sold;
return is;
}
ostream& operator<< (ostream& os, Sales_data& s)
{
os << s.isbn() << "\t" << s.units_sold << "\t" << s.revenue << "\t" << s.avg_price() << endl;
}
14.3
(a)string
(b)string
(c)vector
(d)string
14.4
(a)通常定义为非类成员
(b)通常定义为类成员,因为会改变对象状态
(c)通常定义为类成员,因为会改变对象状态
(d)必须为定义为类成员
(e)通常定义为非成员
(f)通常为非类成员
(g)通常为非类成员
(h)必须为类成员
14.5
#include <iostream>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& os, const Date& d);
friend bool operator==(const Date&, const Date&);
friend bool operator>(const Date&, const Date&);
friend bool operator<(const Date&, const Date&);
public:
Date() = default;
Date(int y , int m , int d ) :year(y), month(m), day(d) {};
int getYear() { return year; }
int getMonth() { return month; }
int getDay() { return day; }
Date& operator+=(const Date& d);
private:
int year;
int month;
int day;
};
bool operator==(const Date&d1, const Date&d2)
{
if (d1.year == d2.year && d1.month == d2.month && d1.day == d2.day)return true;
return false;
}
bool operator<(const Date&d1, const Date&d2)
{
if (d1.year < d2.year) {
return true;
}
else if ((d1.year == d2.year) && (d1.month < d2.month)) {
return true;
}
else if ((d1.month == d2.month) && (d1.day < d2.day)) {
return true;
}
else {
return false;
}
}
bool operator>(const Date& d1, const Date& d2)
{
if (d1.year > d2.year) {
return true;
}
else if ((d1.year == d2.year) && (d1.month > d2.month)) {
return true;
}
else if ((d1.month == d2.month) && (d1.day > d2.day)) {
return true;
}
else {
return false;
}
}
ostream& operator<<(ostream&os,const Date& d)
{
os << d.year << "年" << d.month << "月" << d.day << "日" << endl;
return os;
}
14.6
ostream& operator<< (ostream& os, Sales_data& s)
{
os << s.isbn() << "\t" << s.units_sold << "\t" << s.revenue << "\t" << s.avg_price() << endl;
}
14.7
ostream& operator<<(ostream& os,const String&s)
{
auto p = s.beg;
do
{
os << *p;
} while (p++!=s.end);
return os;
}
14.8
ostream& operator<<(ostream&os,const Date& d)
{
os << d.year << "年" << d.month << "月" << d.day << "日" << endl;
return os;
}
14.9
istream& operator>> (istream& is, Sales_data& s)
{
double price;
is >> s.bookNo >> s.units_sold >> price;
if (is) {
s.revenue = price * s.units_sold;
}
else {
s = Sales_data();
}
return is;
}
14.10
- 输入正确
- 输入错误,初始化为默认。
14.11
本题的输入运算符没有检查流状态的代码,输入错误可能会让我们得到我们不需要的对象。
14.12
istream& operator>>(istream& is, Date& d)
{
is >> d.year >> d.month >> d.day;
if (!is)
d = Date();
return is;
}
14.13
Sales_data operator- (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret (lhs);
ret -= rhs;
return ret;
}
14.14
+=运算符比+运算符更加节省资源和时间
14.15
不应该含有其他算术运算符,因为对时间加减乘除基本没意义。
14.16
StrBlob
bool operator==(const StrBlob&lhs, const StrBlob&rhs)
{
return lhs.data == rhs.data;
}
bool operator!=(const StrBlob& lhs, const StrBlob& rhs)
{
return lhs.data != rhs.data;
}
StrBlobPtr
bool operator==(const StrBlobPtr&lhs, const StrBlobPtr&rhs)
{
return lhs.curr == lhs.curr;
}
bool operator!=(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
return lhs.curr != lhs.curr;
}
StrVec
参考
bool operator== (const StrVec& lhs, const StrVec& rhs)
{
if (lhs.size() != rhs.size()) {
return false;
}
else {
auto l_iter = lhs.begin();
auto r_iter = rhs.begin();
for (l_iter, r_iter; l_iter != lhs.end(); ++l_iter, ++r_iter) {
if (*l_iter != *r_iter) {
return false;
}
}
}
return true;
}
bool operator!= (const StrVec& lhs, const StrVec& rhs)
{
return !(lhs == rhs);
}
String
bool operator== (const String& lhs, const String& rhs)
{
if (lhs.size != rhs.size)
return false;
auto l_iter = lhs.beg;
auto r_iter = rhs.beg;
for (; l_iter != lhs.end; l_iter++, r_iter++)
{
if (*l_iter != *r_iter)
return false;
}
return true;
}
bool operator== (const String& lhs, const String& rhs)
{
return !(lhs == rhs);
}
14.17
bool operator==(const Date&d1, const Date&d2)
{
if (d1.year == d2.year && d1.month == d2.month && d1.day == d2.day)return true;
return false;
}
14.18
Strblob
bool operator<(const StrBlob&lhs, const StrBlob&rhs)
{
return lexicographical_compare(lhs.data->begin(), lhs.data->end(), rhs.data->begin(), rhs.data->end());
/*lexicographical_compare()算法可以比较由开始和结束迭代器定义的两个序列。它的前两个参数定义了第一个序列,
第 3 和第 4 个参数分别是第二个序列的开始和结束迭代器。默认用 < 运算符来比较元素,但在需要时,
也可以提供一个实现小于比较的函数对象作为可选的第 5 个参数。如果第一个序列的字典序小于第二个,
这个算法会返回 true,否则返回 false。所以,返回 false 表明第一个序列大于或等于第二个序列。*/
}
bool operator>(const StrBlob& lhs, const StrBlob& rhs)
{
return lexicographical_compare(rhs.data->begin(), rhs.data->end(),lhs.data->begin(), lhs.data->end());
}
StrblobPtr
bool operator!=(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
return lhs.curr != lhs.curr;
}
bool operator>(const StrBlobPtr&lhs, const StrBlobPtr&rhs)
{
return lhs.curr >lhs.curr;
}
bool operator<(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
return lhs.curr < lhs.curr;
}
StrVec
bool operator<(const StrVec& lhs, const StrVec& rhs)
{
return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
bool operator>(const StrVec& lhs, const StrVec& rhs)
{
return lexicographical_compare( rhs.begin(), rhs.end(), lhs.begin(), lhs.end());
}
String
**bool operator<(const String& lhs, const String& rhs)
{
return lexicographical_compare(lhs.beg, lhs.end, rhs.beg, rhs.end);
}
bool operator>(const String& lhs, const String& rhs)
{
return lexicographical_compare( rhs.beg, rhs.end, lhs.beg, lhs.end);
}**
14.19
bool operator<(const Date&d1, const Date&d2)
{
if (d1.year < d2.year) {
return true;
}
else if ((d1.year == d2.year) && (d1.month < d2.month)) {
return true;
}
else if ((d1.month == d2.month) && (d1.day < d2.day)) {
return true;
}
else {
return false;
}
}
bool operator>(const Date& d1, const Date& d2)
{
if (d1.year > d2.year) {
return true;
}
else if ((d1.year == d2.year) && (d1.month > d2.month)) {
return true;
}
else if ((d1.month == d2.month) && (d1.day > d2.day)) {
return true;
}
else {
return false;
}
}
14.20
Sales_data& operator+ (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs);
ret += rhs;
return ret;
}
Sales_data& Sales_data::operator+= (const Sales_data& s)
{
units_sold += s.units_sold;
revenue += s.revenue;
return *this;
}
14.21
需要一个临时变量存储值,浪费内存与时间。
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
Sales_data temp = *this;
*this = temp + rhs;
return *this;
}
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum;
sum.units_sold = lhs.units_sold + rhs.units_sold;
sum.revenue = lhs.revenue + rhs.revenue;
return sum;
}
14.22
Sales_data& Sales_data::operator=(const std::string& isbn)
{
*this = Sales_data(isbn);
return *this;
}
14.23
StrVec& StrVec::operator=(initializer_list<string>il)
{
auto p = alloc_n_copy(il.begin(), il.end());
free();
elements = p.first;
first_free = cap = p.second;
return *this;
}
14.24
不需要,Date类内部只有三个int数据成员,默认的浅拷贝足够了。
14.25
定义一个参数为string类型的赋值运算符,可以直接用字符串给date对象赋值。
Date& Date::operator=(const string& date)
{
istringstream in(date);
char ch1, ch2;
in >> year >> ch1 >> month >> ch2 >> day;
if (!in || ch1 != '-' || ch2 != '-')
throw std::invalid_argument("Bad date");
if (month < 1 || month >12 || day < 1 || day > 31)
throw std::invalid_argument("Bad date");
return *this;
}
14.26
StrBlob
**string& StrBlob::operator[](size_t n)
{
check(n, "Index out of bounds");
return *((this->data)->begin()+n);
}**
StrBlobPtr
string& StrBlobPtr::operator[](size_t n)
{
return deref(n);
}
string& StrBlobPtr::deref(size_t n)const
{
auto p = check(n, "Undereference");
return (*p)[n];
}
StrVec
string& StrVec::operator[](size_t n)
{
return elements[n];
}
const string& StrVec::operator[](size_t n)const
{
return elements[n];
}
String
char String::operator[] (std::size_t n)
{
if (n < 0 || n > getSize()) {
cout << "out of range." << endl;
return 0;
}
return beg[n];
}
const char String::operator[] (std::size_t n) const
{
if (n < 0 || n > getSize()) {
cout << "out of range." << endl;
return 0;
}
return beg[n];
}
14.27
StrBlobPtr& StrBlobPtr::operator++()
{
++curr;
check(curr, "increment past end of StrBlobPtr");
return *this;
}
StrBlobPtr& StrBlobPtr::operator--()
{
--curr;
check(curr, "decrement past of begin of StrBlobPtr");
return *this;
}
StrBlobPtr& StrBlobPtr::operator++(int)
{
auto ret = *this;
++curr;
return ret;
}
StrBlobPtr& StrBlobPtr::operator--(int)
{
auto ret = *this;
--curr;
return ret;
}
14.28
StrBlobPtr& StrBlobPtr::operator+=(size_t n)
{
curr += n;
check(curr, "increment past end of StrBlobPtr");
return *this;
}
StrBlobPtr& StrBlobPtr::operator-=(size_t n)
{
curr -= n;
check(curr, "decrement past begin of StrBlobPtr");
return *this;
}
StrBlobPtr& operator+(const StrBlobPtr&lhs ,size_t n)
{
auto ret = lhs;
ret += n;
return ret;
}
StrBlobPtr& operator-(const StrBlobPtr& lhs, size_t n)
{
auto ret = lhs;
ret -= n;
return ret;
}
14.29
因为递增和递减都会改变对象的状态,所以不能为const。
14.30
**string& StrBlobPtr::operator*() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
string* StrBlobPtr::operator->()const
{
return&this->operator*();
}**
inline const string* ConstStrBlobPtr::operator->() const
{
return &this->operator*();
}
inline ConstStrBlobPtr& ConstStrBlobPtr::operator*()
{
auto p=(curr, "dereference past end");
return (*p)[curr];
}
14.31
因为在这个类中,我们不需要管理内存空间,使用合成版本的足够了。
14.32
#include"StrBlobPtr.h"
class StrBlobPtr_pointer
{
public:
StrBlobPtr_pointer() = default;
StrBlobPtr_pointer(StrBlobPtr* p) :pointer(p) {};
StrBlobPtr& operator*()const;
StrBlobPtr* operator->()const;
private:
StrBlobPtr* pointer=nullptr;
};
StrBlobPtr& StrBlobPtr_pointer::operator*() const
{
return *pointer;
}
StrBlobPtr* StrBlobPtr_pointer::operator->() const
{
return pointer;
}
14.33
重载运算符函数的参数数量和该运算符作用的运算对象的数量一样多。函数调用运算符()最多可以传256个参数,因此在重载时,最多也能接受256个参数用作运算。
14.34
class if_then_else
{
if_then_else(int n) :num(n) {};
int opterator(int, int, int);
private:
int num;
};
int if_then_else::opterator(int x, int y, int z)
{
return (x == num) ? y : z;
}
14.35
#include <iostream>
#include<string>
using namespace std;
class PrintLine
{
public:
PrintLine(istream& i) :is(i) { }
string& operator()();
private:
string line;
istream& is;
};
string& PrintLine::operator()()
{
if (getline(is, line))
{
return line;
}
return line=string();
}
14.36
#include <iostream>
#include<string>
#include<vector>
using namespace std;
class PrintVec
{
friend ostream& operator<< (ostream& os, PrintVec& ps);
public:
PrintVec(istream& i) :is(i) { }
void operator()();
private:
istream& is;
vector<string>svec;
};
void PrintVec::operator()()
{
string s;
while (getline(is, s))
{
svec.push_back(s);
}
}
ostream& operator<<(ostream& os, PrintVec& pv)
{
for (auto s : pv.svec)
{
os << s << " ";
}
return os;
}
int main()
{
PrintVec s(cin);
s();
cout << s;
}
14.37
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class IsEqual
{
public:
IsEqual(int n) :compare(n) {};
bool operator()(int n)
{
return compare == n;
}
private:
int compare;
};
int main()
{
vector<int>ivec{ 1,2,7,4,5,6 };
replace_if(ivec.begin(), ivec.end(), IsEqual(7), 3);
for (auto i : ivec)
{
cout << i << " ";
}
}
14.38
#include <iostream>
#include<fstream>
#include<vector>
#include<map>
using namespace std;
class IsInRange
{
public:
IsInRange(size_t s):size(s) {};
bool operator()(size_t s)
{
return size == s;
}
size_t getSize() { return size; }
private:
size_t size;
};
int main()
{
vector<IsInRange>vec;
map<size_t, int>len_cnt_table;
for (int i = 1; i < 11; i++)
{
vec.push_back(i);
len_cnt_table[i] = 0;
}
ifstream fs("C:\\Users\\Kaji\\Desktop\\test.txt");
string word;
while (fs >> word)
{
for (auto i : vec)
{
if (i(word.size()))
{
++len_cnt_table[i.getSize()];
}
}
}
for (auto i : len_cnt_table) {
cout << i.first << " " << i.second << endl;
}
}
14.39
#include <iostream>
#include<string>
#include<fstream>
#include<vector>
#include<map>
using namespace std;
class IsInRange
{
public:
IsInRange(size_t l,size_t b):lowest(l),biggest(b) {};
bool operator()(const string&s)
{
return lowest <= s.size() && s.size() <= biggest;
}
size_t getLowest() { return lowest; }
size_t getBiggest() { return biggest; }
private:
size_t lowest;
size_t biggest;
};
int main()
{
vector<IsInRange>vec;
map<string, int>len_cnt_table;
vec.push_back({ 1,9 });
vec.push_back({ 1,9 });
ifstream fs("C:\\Users\\Kaji\\Desktop\\test.txt");
string word;
while (fs >> word) {
for (auto i : vec) {
if (i(word)) {
++len_cnt_table[to_string(i.getLowest()) + "-" + to_string(i.getBiggest())];
}
}
}
for (auto i : len_cnt_table) {
cout << "The length of word in range " << i.first << " is " << i.second << endl;
}
}
14.40
class compareSize
{
public:
compareSize() {}
compareSize(std::size_t len) : sz(len) {}
bool operator() (const std::string& lhs, const std::string& rhs)
{
std::cout << “operator() (const std::string& lhs, const std::string& rhs)” << std::endl;
return lhs.size() >= rhs.size();
}
bool operator() (const std::string& s)
{
std::cout << “operator() (const std::string& s)” << std::endl;
return s.size() > sz;
}
private:
std::size_t sz;
};
void biggies(vector& words, size_t sz)
{
elimDups(words);
printVec(words);
stable_sort(words.begin(), words.end(), compareSize());
auto wc = partition(words.begin(), words.end(), compareSize(sz));
printVec(words);
}
14.41
增加了lambda使得某些程序变得直观简单。
当使用次数不多,实现简单的情况下使用lambda。
当使用次数多,实现复杂的情况下使用类。
14.42
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
using namespace std::placeholders;
using namespace std;
int main()
{
vector<int>ivec{ 1,10,100,1111,2048,4096 };
int count = count_if(ivec.begin(), ivec.end(), bind(greater<int>(), _1, 1024));
cout << count << endl;
vector<string>svec{ "pooh","pooh","pooch","pooh" ,"poog" };
auto iter=find_if(svec.begin(), svec.end(), bind(not_equal_to<string>(), _1, "pooh"));
cout << *iter << endl;
vector<int>ivec2{ 1,2,3,4,5 };
transform(ivec2.begin(), ivec2.end(),ivec2.begin(), bind(multiplies<int>(), _1, 2));
for (auto i : ivec2)
cout << i << " ";
}
14.43
#include <iostream>
#include<functional>
#include<vector>
#include<algorithm>
using namespace std;
void test(int n)
{
vector<int>ivec{ 2,4,6,8 };
modulus<int>mod;
auto f = all_of(ivec.begin(), ivec.end(), [&mod, n](int i)->bool {return mod(i, n) == 0; });
cout << (f ? "Yes!" : "No!") << endl;
}
int main()
{
test(2);
test(3);
}
14.44
#include <iostream>
#include<functional>
#include<map>
using namespace std;
class add
{
public:
int operator()(int n1,int n2)
{
return n1 + n2;
}
};
class division
{
public:
int operator()(int n1, int n2)
{
return n1 / n2;
}
};
class subtraction
{
public:
int operator()(int n1, int n2)
{
return n1 - n2;
}
};
class multiplication
{
public:
int operator()(int n1, int n2)
{
return n1 * n2;
}
};
class module
{
public:
int operator()(int n1, int n2)
{
return n1 % n2;
}
};
void Calculator()
{
map<string, function<int(int,int)>>binops;
binops.insert({ "+", add() });
binops.insert({ "/",division() });
binops.insert({ "-",subtraction() });
binops.insert({ "*",multiplication() });
binops.insert({ "%",module() });
int num1, num2;
string ope;
if (cin >> num1 >> ope >> num2)
{
cout << num1 << ope << num2 << " = " << binops[ope](num1, num2) << endl;
}
else
{
cout << "Please enter the correct expression" << endl;
}
}
14.45
explicit operator std::string() const { return bookNo; }
explicit operator double() const { return revenue; }
14.46
应该声明为explicit,防止使用者无意中使用了隐式转换而产生与预期不符的结果。
14.47
- 第一个是转化为const int类型
- 第二个是防止改变对象的数据成员,返回一个int
14.48
应该有,可以用来检测日期是否合法。
应该为explicit,防止意外的转化。
14.49
bool isLeapYear() const { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); }
explicit operator bool() const
{
vector<vector> days_per_month = {{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
return 1 <= month && month <= 12 && 1 <= day && day <= days_per_month[isLeapYear()? 1 : 0][month - 1];
}
14.50
struct LongDouble {
LongDouble (double = 0.0);
operator double();
operator float();
};
LongDouble ldObj;
int ex1 = ldObj; // 在将ldObj转换为int时,类定义的类型转换都无法精准匹配,因此会产生二义性,可能先执行 operator double(), 再进行double到int的转换。
// 也可能调用operator float(),再进行float到int的转换。
float ex2 = ldObj; // 调用operator float()
14.51
优先使用void calc(int),因为这用到的是标准类型转换,而LongDouble是用户自定义的转换类型
14.52
ld = si + ld;具有二义性,调用1需将si转换为LongDouble,ld转换为SmallInt。
调用2需要将si转换为LongDouble,ld转换为double。
ld = ld + si;精确匹配LongDouble operator+ (const SmallInt&);
若调用LongDouble operator+(LongDouble&, double);还需将si转换为double。
14.53
不合法
其中s1可以转化为int再通过标准类型转换为double,也可以将3.14通过标准类型转换为int在调用SmallInt的构造函数转化为SmallInt。
可以改为double d=s1+SmallInt(3.14);