C++Primer习题第十四章

//注意:这章的练习我将会十分简略地完成。。。

练习14.1:在什么情况下重载的运算符和内置运算符有所区别?在什么情况下重载的运算符又与内置运算符一样?

答:(标准)

不同点:

重载操作符必须具有至少一个class或者枚举类型的操作数。

重载操作符不保证操作数的求值顺序。

相同点:

对于优先级和结合性及操作数的数目都不变。


练习14.2:为Sales_data类编写重载的输入、输出、加法和复合赋值运算符。

PS:其中>> 、<<和+运算符定义为非成员函数。

+=定义为成员函数。 

istream& Sales_data::operator>>( istream &is, Sales_data &rhs ){
    is >> rhs.bookNo;
    is >> rhs.units_sold;
    is >> rhs.selling_price;
    is >> rhs.sales_price;
    if( is && !selling_price )
        discount = sales_price / selling_price;
    else
        rhs = Sales_data();
    return is;
}

ostream& Sales_data::operator<<( ostream &os, const Sales_data &rhs ){
    os << rhs.bookNo << " "
        << rhs.units_sold << " "
        << rhs.selling_price << " "
        << rhs.sales_price << " "
        << rhs.discount; //不添加换行,换行自行添加,增加操作的灵活性。
    
    return os;
}

Sales_data& Sales_data::operator+=( const Sales_data &rhs ){
//同一本书的零售价应该是相同的,所以selling_price应该相同。
    sales_price = ( sales_price * units_sold + rhs.sales_price * rhs.units_sold )
                / ( units_sold + rhs.units_sold );
    units_sold += rhs.units_sold;
    if( selling_price != 0 )
        discount = sales_price / selling_price;
        
    return *this;
}

Sales_data Sales_data::operator+( const Sales_data &lhs, const Sales_data &rhs ){        
//默认认为两个Sales_data对象的bookNo相同
    Sales_data tmp( lhs );
    tmp += rhs;
    
    return tmp;
}


练习14.3:string和vector都定义了重载的==以比较各自的对象,假设svec1和svec2是存放string的vector,确定在下面的表达式中分别使用了哪个版本的==?

(a) "cobble" == "stone"

直接比较的是字符串首元素的地址。内置版本的==


(b)svec1[0] == svec2[0]

调用的是string的重载的==运算符


(c)svec1 == svec2

调用了vector的重载的==运算符


(d)svec1[0] == "stone"

调用了string的重载的==运算符。字面字符常量被转换为string


练习14.4:如何确定下列运算符是否应该是类的成员?

(a) %

非成员。

(b)%=

成员

(c)++

成员

(d)->

必须是类成员

(e)<<

必须是非成员

(f)&&

非成员。但不应该重载(因为不能保证&&的短路求值属性)

(g)==

非成员

(h)  ()

必须是类成员


练习14.5:在7.5.1节的练习7.40中,编写了下列类中某一个的框架,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。

对于book类:

可以重载 >>输入运算符和<<输出运算符。



练习14.6:为你的Sales_data类定义输出运算符。

见练习14.2。


练习14.7:你在13.5节的练习中曾经编写了一个String类,为它定义一个输出运算符。

注意类内还要加上友元声明。

ostream& operator<<( ostream &os, const String &s )
// C++定义了输出运算符接受字符指针输出字符串的版本
    os << s.p;
    return os;
}


练习14.8:你在7.5.1节的练习7.40中曾经选择并编写了一个类,为它定义一个输出运算符。

class book{
    friend ostream& operator<<( ostream&, const book& );
private:
    string bookName;
    string Author;
    string ISBN;
    string Publisher;
    double price = 0.0;
public:
    book() = default;
    book( std::istream &is ) { is >> *this; }
    book( const string &n, const string &a, const string &I, const string &P, double pr );
};

ostream& operator<<( ostream &os, const book &bk ){
    os << "《" << bk.bookName << "》" << " "
        << bk.Author << " "
        << bk.ISBN << " "
        << bk.Publisher << " "
        << "¥" << bk.price;
    
    return os;
}


练习14.9:为你的Sales_data类定义输入运算符。

见练习14.2。


练习14.10:对于Sales_data的输入运算符来说如果给定了下面的输入将发生什么情况。

(a)正常读入一个Sales_data对象。

(b)输入错误,将得到一个Sales_data对象的默认值



练习14.11:下面的Sales_data输入运算符存在错误吗?如果有,请指出来。对于这个输入运算符如果仍然给定上个练习的输入将发生什么情况。

有错误。题目中的输入运算符定义中没有读取输入后的流进行错误性判断。如果输入错误,那么这个类对象将得到错误数据的数据成员。

如果给定上面联系的输入:

对于(a),输入正常,将正常读入一个Sales_data对象。

对于(b),输入错误,导致数据成员“张冠李戴”。bookNo读入成为10, units_sold读入为24,revenue为24*0.95;此时流的failbit被置位。


练习14.12:你在7.5.1节的练习7.40中国曾经选择并编写了一个类,为它定义一个输入运算符并确保该运算符可以处理输入错误。

#ifndef BOOK_H_INCLUDED
#define BOOK_H_INCLUDED

#include
#include

using namespace std;

class Book{
    //友元声明
    friend istream& operator>>( istream&, Book& );
    friend ostream& operator<<( ostream&, const Book& );
public:
    //默认构造函数
    Book() = default;
    //其他构造函数
    Book( std::istream& );
    Book( const string &bk, const string &a, const string &I, const string &P, double pr ):
        bookName(bk), Author(a), ISBN(I), Publisher(P), price(pr) { }
private:
    string bookName;
    string Author;
    string ISBN;
    string Publisher;
    double price = 0.0;

};

//友元定义
istream& operator>>( istream &is, Book &bk ){
    is >> bk.bookName >> bk.Author
        >> bk.ISBN >> bk.Publisher
        >> bk.price;
    //如果流检测到错误,将对象置为默认状态
    if( !is )
        bk = Book();

    return is;
}
ostream& operator<<( ostream &os, const book &bk ){
    os << "《" << bk.bookName << "》" << " "
        << bk.Author << " "
        << bk.ISBN << " "
        << bk.Publisher << " "
        << "¥" << bk.price;
    
    return os;
}

Book::Book( istream &is ){
    is >> *this;
}


#endif // BOOK_H_INCLUDED

练习14.13:你认为Sales_data类还应该支持哪些其他算术运算符?如果有的话,请给出它们的定义。

综合考虑下应该只需要+、+=、<<、 >>运算符。


练习14.14:你觉得为什么调用operator+=来定义operator+比其他方法更有效?

使用+=可以使得代码更加简洁,而且可读性也更好。


练习14.15:你在7.5.1节的练习7.40中曾经选择并编写了一个类,你认为它应该含有其他算术类型吗?如果是,请实现它们;如果不是,解释原因。

我选择的类是book,我认为不需要含有其他算术类型。因为其中的5个数据成员中书名,作者名,书号,出版社都不适合算术运算,而剩下的价格成员,它的运算也是没有意义的。


练习14.16:为你的StrBlob类、StrBlobPtr类、StrVec类和String类分别定义相等运算符和不相等运算符。

略了。


练习14.17:你在7.5.1节的练习中曾经选择并编写了一个类,你认为它应该含有相等运算符吗?如果是,请实现它;如果不是,解释原因。

我认为需要。5个数据成员中,我认为只需比较其中两个:ISBN 和 price。因为ISBN相同则书名作者肯定也相同,(价格如果是零售价的话:应该也相同)如果价格是实际售价的话,有可能不同,所以价格也需要比较。

代码略了。


练习14.18:为你的StrBlob类、StrBlobPtr类、StrVec类和String类定义关系运算符。

略了。


练习14.19:你在7.5.1节的练习7.40中曾经选择并编写了一个类,你认为它应该含有关系运算符吗?如果是,请实现它;如果不是,解释原因。

可以根据实际需要编写关系运算符:

根据书名、ISBN、作者名、甚至出版社名比较字典序大小应该都可以,也可以根据书的价格大小比较。


练习14.20:为你的Sales_data类定义加法和复合赋值运算符。

见练习14.2。


练习14.21:编写Sales_data类的+和+=运算符,使得+执行实际的加法操作而+=调用+。相比于之前的定义,本题的定义有何缺点?试讨论之。

代码就略了。

性能上,我认为+=运算符会做了冗余的工作。需要用到+运算符返回的值再调用拷贝赋值运算符,而+运算符本身已经构造过一个临时的Sales_data类对象了。

代码上,我认为代码可读性降低了,而且编写起来也更繁杂。


练习14.22:定义赋值运算符的一个新版本,使得我们能把一个表示ISBN的string赋值给一个Sales_data对象。

Sales_data& Sales_data::operator=( const string &str ){
    bookNo = str;
    
    return *this;
}

练习14.23:为你的StrVec类定义一个initializer_list赋值运算符。

略了。


练习14.24:你在7.5.1节的练习7.40中曾经选择并编写了一个类,你认为它应该含有拷贝赋值和移动赋值运算符吗?如果是,请实现它们。



你可能感兴趣的:(C++primer习题)