《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 <iostream>
#include <string>
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 << "\n\t" << 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"
#include <iostream>
using 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类。因为我们可以比较两个日期是否相等,因此需要实现相等运算符。
#include <iostream>
using 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。对于日期,可以比较其大小,因此需要为它重载关系运算符。
#include <iostream>
using 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