《C++ Primer》第14章 操作重载与类型转换
14.3节 算术和关系运算符 习题答案
练习14.13:你认为Sales_data类还应该支持哪些其他算术运算符(参见表4.1,第124页)?如果有的话,请给出它们的定义。
【出题思路】
本题练习重载运算符的实现。
【解答】
对于Sales_data类,其实我们并不需要再为它添加其他算术运算符。但是这里我们可以考虑为它实现一个减法运算符。
#ifndef SALES_DATA14_13_H #define SALES_DATA14_13_H #include#include class Sales_data { friend std::istream& operator>>(std::istream&, Sales_data&); friend std::ostream& operator<<(std::ostream&, const Sales_data&); friend bool operator<(const Sales_data&, const Sales_data&); friend bool operator==(const Sales_data&, const Sales_data&); friend Sales_data operator-(const Sales_data &lhs, const Sales_data &rhs);//重载减法运算符 public: Sales_data() = default; Sales_data(const std::string &book): bookNo(book) { } Sales_data(std::istream &is) { is >> *this; } public: Sales_data& operator+=(const Sales_data&); Sales_data& operator-=(const Sales_data &rhs);//重载-=运算符 std::string isbn() const { return bookNo; } double avg_price() const; private: std::string bookNo; //书号 unsigned units_sold = 0; //出售册数 double revenue = 0.0; //收入 }; inline bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs) { return lhs.isbn() == rhs.isbn(); } Sales_data operator+(const Sales_data&, const Sales_data&); inline bool operator==(const Sales_data &lhs, const Sales_data &rhs) { return (lhs.units_sold == rhs.units_sold) && (lhs.revenue == rhs.revenue) && (lhs.isbn() == rhs.isbn()); } inline bool operator !=(const Sales_data &lhs, const Sales_data &rhs) { return !(lhs == rhs); } Sales_data& Sales_data::operator +=(const Sales_data& rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue; return *this; } Sales_data operator +(const Sales_data& lhs, const Sales_data& rhs) { Sales_data ret(lhs); ret += rhs; return ret; } //添加重载-运算符 Sales_data operator-(const Sales_data &lhs, const Sales_data &rhs) { Sales_data sub = lhs; sub -= rhs; return sub; } //添加重载-=运算符 Sales_data& Sales_data::operator-=(const Sales_data &rhs) { units_sold -= rhs.units_sold; revenue -= rhs.revenue; return *this; } std::istream& operator>>(std::istream& in, Sales_data& s) { double price; in >> s.bookNo >> s.units_sold >> price; if(in) s.revenue = s.units_sold * price; else s = Sales_data(); return in; } std::ostream& operator <<(std::ostream& out, const Sales_data& s) { const char sep = 't'; out << "nt" << s.isbn() << sep << s.units_sold << sep << s.revenue << sep << s.avg_price(); return out; } double Sales_data::avg_price() const { if(units_sold) return revenue / units_sold; else return 0; } #endif // SALES_DATA14_13_H
#include "Sales_data14_13.h" #includeusing namespace std; int main() { Sales_data trans1, trans2; std::cout << "请输入两条ISBN相同的销售记录:" << std::endl; std::cin >> trans1 >> trans2; std::cout << "两条销售记录的差" << trans1 - trans2 << std::endl; cout << "Hello World!" << endl; return 0; }
运行结果:
练习14.14:你觉得为什么调用operator+=来定义operator+比其他方法更有效?
【出题思路】
理解重载运算符的不同实现方式。
【解答】
显然,从头实现operator+的方式与借助operator+=实现的方式相比,在性能上没有优势,而可读性上后者显然更好。因此,在此例中代码复用是最好的方式。
练习14.15:你在7.5.1节的练习7.40(第261页)中曾经选择并编写了一个类,你认为它应该含有其他算术运算符吗?如果是,请实现它们;如果不是,解释原因。
【出题思路】
本题练习实现重载运算符。
【解答】
在练习7.40中,我们编写了类Date。算术运算对Date并没有太大意义,因此不需要为Date重载算术运算符。
练习14.16:为你的StrBlob类(参见12.1.1节,第405页)、StrBlobPtr类(参见12.1.6节,第421页)、StrVec类(参见13.5节,第465页)和String类(参见13.5节,第470页)分别定义相等运算符和不相等运算符。
【出题思路】
本题练习实现相等运算符。
【解答】
//为StrBlob定义==和!=
class StrBlob{
friend bool operator==(const StrBlob &lhs, const StrBlob &rhs);
friend bool operator!=(const StrBlob &lhs, const StrBlob &rhs);
//其他成员
};
bool operator==(const StrBlob &lhs, const StrBlob &rhs)
{
return lhs.data == rhs.data;
}
bool operator!=(const StrBlob &lhs, const StrBlob &rhs)
{
return !(lhs == rhs);
}
//为StrBlobPtr定义==和!=
class StrBlobPtr{
friend bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs);
friend bool operator!=(const StrBlobPtr &lhs, const StrBlobPtr &rhs);
//其他成员
};
bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
auto l = lhs.wptr.lock();
auto r = rhs.wptr.lock();
if(l == r)
//两个指针都为空,或指向相同vector且curr指向相同元素时,相等,否则不等
return (!r || lhs.curr == rhs.curr);
else
return false;//指向不同vector时,不等
}
bool operator!=(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
return !(lhs == rhs);
}
//为StrVec定义==和!=
class StrVec{
friend bool operator==(const StrVec &lhs, const StrVec &rhs);
friend bool operator!=(const StrVec &lhs, const StrVec &rhs);
//其他成员
};
bool operator==(const StrVec &lhs, const StrVec &rhs)
{
if(lhs.size() != rhs.size())
return false;
for(auto itr1 = lhs.begin(), itr2 = rhs.begin(); itr1 != lhs.end(),
itr2 != rhs.end(); itr1++, itr2++)
{
if(*itr1 != *itr2)
return false;
}
return true;
}
bool operator!=(const StrVec &lhs, const StrVec &rhs)
{
return !(lhs == rhs);
}
//为String定义==和!=
class String{
friend bool operator==(const String &lhs, const String &rhs);
friend bool operator!=(const String &lhs, const String &rhs);
//其他成员
private:
const char *str;
};
bool operator==(const String &lhs, const String &rhs)
{
return strcmp(lhs.str, rhs.str);
}
bool operator!=(const String &lhs, const String &rhs)
{
return !(lhs == rhs);
}
练习14.17:你在7.5.1节的练习7.40(第261页)中曾经选择并编写了一个类,你认为它应该含有相等运算符吗?如果是,请实现它;如果不是,解释原因。
【出题思路】
本题练习判断类是否需要相等运算符及实现。
【解答】
在练习7.40中,我们实现了Date类。因为我们可以比较两个日期是否相等,因此需要实现相等运算符。
#includeusing namespace std; class Date { friend std::istream& operator>>(std::istream&, Date&); friend ostream& operator<<(ostream &os, const Date &dt); friend bool operator==(const Date &d1, const Date &d2); friend bool operator!=(const Date &d1, const Date &d2); public: Date() { } Date(int y, int m, int d) { year = y; month = m; day = d; } private: int year; int month; int day; }; istream& operator>>(std::istream& is, Date& inDt) { is >> inDt.year >> inDt.month >> inDt.day; if(!is) { inDt = Date(0, 0, 0); cout << "input data error====================" << endl; } return is; } ostream& operator<<(ostream& os, const Date& d) { const char sep = 't'; os << "year:" << d.year << sep << "month:" << d.month << sep << "day:" << d.day << endl; return os; } bool operator==(const Date &d1, const Date &d2) { return (d1.year == d2.year) && (d1.month == d2.month) && (d1.day == d2.day); } bool operator!=(const Date &d1, const Date &d2) { return !(d1 == d2); } int main() { Date date1(2017, 8, 7); Date date2(2017, 8, 8); bool isEqual = (date1 != date2); cout << "date==========" << isEqual << endl; return 0; }
运行结果:date==========1
练习14.18:为你的StrBlob类、StrBlobPtr类、StrVec类和String类定义关系运算符。
【出题思路】
本题练习实现关系运算符。
【解答】
本题的关键是明确关系运算符的语义。
String类的关系运算符就是比较两个字符串字典序的先后。
//为String定义<, <=, >,>=
class String{
friend bool operator<(const String &s1, const String &s2);
friend bool operator<=(const String &s1, const String &s2);
friend bool operator>(const String &s1, const String &s2);
friend bool operator>=(const String &s1, const String &s2);
//其他成员
private:
const char *str;
};
bool operator<(const String &s1, const String &s2)
{
return strcmp(s1.str, s2.str) < 0;
}
bool operator<=(const String &s1, const String &s2)
{
return strcmp(s1.str , s2.str) <= 0;
}
bool operator >(const String &s1, const String &s2)
{
return strcmp(s1.str, s2.str) > 0;
}
bool operator >=(const String &s1, const String &s2)
{
return strcmp(s1.str, s2.str) >= 0;
}
练习14.19:你在7.5.1节的练习7.40(第261页)中曾经选择并编写了一个类,你认为它应该含有关系运算符吗?如果是,请实现它;如果不是,解释原因。
【出题思路】
本题练习实现关系运算符。
【解答】
在练习7.40中,我们编写了类Date。对于日期,可以比较其大小,因此需要为它重载关系运算符。
#includeusing namespace std; class Date { friend std::istream& operator>>(std::istream&, Date&); friend ostream& operator<<(ostream &os, const Date &dt); friend bool operator==(const Date &d1, const Date &d2); friend bool operator!=(const Date &d1, const Date &d2); friend bool operator<(const Date &d1, const Date &d2); friend bool operator<=(const Date &d1, const Date &d2); friend bool operator>(const Date &d1, const Date &d2); friend bool operator>=(const Date &d1, const Date &d2); public: Date() { } Date(int y, int m, int d) { year = y; month = m; day = d; } private: int year; int month; int day; }; istream& operator>>(std::istream& is, Date& inDt) { is >> inDt.year >> inDt.month >> inDt.day; if(!is) { inDt = Date(0, 0, 0); cout << "input data error====================" << endl; } return is; } ostream& operator<<(ostream& os, const Date& d) { const char sep = 't'; os << "year:" << d.year << sep << "month:" << d.month << sep << "day:" << d.day << endl; return os; } bool operator==(const Date &d1, const Date &d2) { return (d1.year == d2.year) && (d1.month == d2.month) && (d1.day == d2.day); } bool operator!=(const Date &d1, const Date &d2) { return !(d1 == d2); } bool operator<(const Date &d1, const Date &d2) { return (d1.year < d2.year) || (d1.year == d2.year && d1.month < d2.month) ||(d1.year == d2.year && d1.month == d2.month && d1.day < d2.day); } bool operator <=(const Date &d1, const Date &d2) { return (d1 < d2) || (d1 == d2); } bool operator >(const Date &d1, const Date &d2) { return !(d1 <= d2); } bool operator >=(const Date &d1, const Date &d2) { return (d1 > d2) || (d1 == d2); } int main() { Date date1(2017, 8, 7); Date date2(2017, 8, 8); bool isValue = (date1 >= date2); cout << "date==========" << isValue << endl; return 0; }
运行结果:date==========0



