C++ Primer(第五版)|练习题答案与解析(第十四章:重载运算与类型转换)
本博客主要记录C++ Primer(第五版)中的练习题答案与解析。
参考:C++ Primer
C++ Primer
练习题14.1
在什么情况下重载的运算符与内置运算符有所区别?在什么情况下重载的运算符又与内置运算符一样?
区别:
- P490,重载运算符必须是一个类的成员或者至少有一个参数是类类型。
- P491,可以直接通过对象调用一个重载运算符,如data1.operator+(data2)。
- P491,使用重载的运算符本质上是函数调用,所以这些运算符指定了运算对象的求值顺序或短路求值属性,这些规则无法应用到重载运算符上,比如逻辑运算符、关系运算符和逗号运算符,不建议使用。
相同
- P490,重载运算符的优先级和结合律与对应的内置运算符保持一致。
练习题14.2
为Sales_data编写重载的输入、输出、加法和复合赋值运算符。
//.h文件
#include <string>
#include <iostream>
class Sales_data {
friend std::istream& operator>>(std::istream&, Sales_data&); // input
friend std::ostream& operator<<(std::ostream&, const Sales_data&); // output
friend Sales_data operator+(const Sales_data&, const Sales_data&); // addition
public:
Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(n*p){
}
Sales_data() : Sales_data("", 0, 0.0f){
}
Sales_data(const std::string &s) : Sales_data(s, 0, 0.0f){
}
Sales_data(std::istream &is);
Sales_data& operator+=(const Sales_data&); // compound-assignment
std::string isbn() const {
return bookNo; }
private:
inline double avg_price() const;
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
std::istream& operator>>(std::istream&, Sales_data&);
std::ostream& operator<<(std::ostream&, const Sales_data&);
Sales_data operator+(const Sales_data&, const Sales_data&);
inline double Sales_data::avg_price() const
{
return units_sold ? revenue/units_sold : 0;
}
//.cpp文件
Sales_data::Sales_data(std::istream &is) : Sales_data()
{
is >> *this;
}
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
std::istream& operator>>(std::istream &is, Sales_data &item)
{
double price = 0.0;
is >> item.bookNo >> item.units_sold >> price;
if (is)
item.revenue = price * item.units_sold;
else
item = Sales_data();
return is;
}
std::ostream& operator<<(std::ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;
}
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;
sum += rhs;
return sum;
}
//测试文件
int main()
{
Sales_data test;
std::cin >> test;
std::cout << test << std::endl;
}
测试:
ISN1913 10 5
ISN1913 10 50 5
练习题14.3
string和vector都定义了重载的==以比较各自的对象,假设svec1和svec2是存放string的vector,确定在下面的表达式中分别使用了哪个版本的==?
(a ) "cobble" == "stone"
string重载的“==”
(b ) svec1[0] == svec2[0]
string重载的“==”
(c ) svec1 == svec2
vector重载的“==”
(d ) svec1[0] == "stone"
string重载的“==”
练习题14.4
如何确定下列运算符是否应该是类的成员?
P493
(a ) %
一般定义为非成员。
(b ) %=
一般定义为类成员,能够改变对象的状态。
(c ) ++
一般定义为类成员,能够改变对象的状态。
(d ) ->
必须定义为类成员
(e ) <<
一般定义为非成员
(f )&&
一般定义为非成员。
(g ) ==
一般定义为非成员。
(h ) ()
必须定义为类成员
练习题14.5
在7.5.1节练习7.40中,编写了下列类中某一个的框架,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。
(a) Book (b) Date © Employee (d) Vehicle (e) Object (f) Tree
//.h文件
#include <iostream>
#include <string>
class Book {
friend std::istream& operator>>(std::istream&, Book&);
friend std::ostream& operator<<(std::ostream&, const Book&);
friend bool operator==(const Book&, const Book&);
friend bool operator!=(const Book&, const Book&);
public:
Book() = default;
Book(unsigned no, std::string name, std::string author, std::string pubdate):no_(no), name_(name), author_(author), pubdate_(pubdate) {
}
Book(std::istream &in) {
in >> *this; }
private:
unsigned no_;
std::string name_;
std::string author_;
std::string pubdate_;
};
std::istream& operator>>(std::istream&, Book&);
std::ostream& operator<<(std::ostream&, const Book&);
bool operator==(const Book&, const Book&);
bool operator!=(const Book&, const Book&);
//.cpp文件
std::istream& operator>>(std::istream &in, Book &book)
{
in >> book.no_ >> book.name_ >> book.author_ >> book.pubdate_;
return in;
}
std::ostream& operator<<(std::ostream &out, const Book &book)
{
out << book.no_ << " " << book.name_ << " " << book.author_ << " " << book.pubdate_;
return out;
}
bool operator==(const Book &lhs, const Book &rhs)
{
return lhs.no_ == rhs.no_;
}
bool operator!=(const Book &lhs, const Book &rhs)
{
return !(lhs == rhs);
}
//测试文件
int main()
{
Book book1(001, "Test", "Andrew", "2020");
Book book2(001, "Test", "Andrew", "2020");
if (book1 == book2)
std::cout << book1 << std::endl;
}
测试:1 Test Andrew 2020
练习题14.6
为你的Sales_data类定义输出运算符。
同14.2。
练习题14.7
你在13.5节的练习(P470)中曾经编写了一个String类,为它定义一个输出运算符。
//.h文件
#include <memory>
#include <iostream>
class String
{
friend std::ostream& operator<<(std::ostream&, const String&);
public:
String() : String("") {
}
String(const char *);
String(const String&);
String& operator=(const String&);
~String();
const char *c_str() const {
return elements; }
size_t size() const {
return end - elements; }
size_t length() const {
return end - elements - 1; }
private:
std::pair<char*, char*> alloc_n_copy(const char*, const char*);
void range_initializer(const char*, const char*);
void free();
private:
char *elements;
char *end;
std::allocator<char> alloc;
};
std::ostream& operator<<(std::ostream&, const String&);
//.cpp文件
#include <algorithm>
#include <iostream>
std::pair<char*, char*>
String::alloc_n_copy(const char *b, const char *e)
{
auto str = alloc.allocate(e - b);
return{
str, std::uninitialized_copy(b, e, str) };
}
void String::range_initializer(const char *first, const char *last)
{
auto newstr = alloc_n_copy(first, last);
elements = newstr.first;
end = newstr.second;
}
String::String(const char *s)
{
char *sl = const_cast<char*>(s);
while (*sl)
++sl;
range_initializer(s, ++sl);
}
String::String(const String& rhs)
{
range_initializer(rhs.elements, rhs.end);
std::cout << "拷贝构造函数" << std::endl;
}
void String::free()
{
if