《C++ Primer》第14章 14.1节习题答案

本篇博客详细介绍了C++中运算符重载的基本概念和应用,包括输入/输出、算术、下标及函数调用运算符的重载,并通过Sales_data和StrBlob类举例说明。同时,探讨了类型转换在重载运算符选择中的作用,特别是涉及多版本重载时的函数匹配规则。此外,提供了多个练习题目,帮助读者深入理解和掌握这些概念。
摘要由CSDN通过智能技术生成

《C++ Primer》第14章 操作重载与类型转换

本章介绍了运算符重载的基本概念,介绍了各种运算符的重载方式,并介绍了类型转换与运算符重载的关系。本章的练习着重让读者掌握各种运算符的重载,包括输入/输出运算符、各种算术运算符、下标运算符以及函数调用运算符等。特别是,结合自定义的Sales_data、StrBlob等较为复杂的类进行运算符重载的练习,让读者体会运算符重载是如何帮助改进代码质量的。此外,还通过一些练习帮助读者弄清类型转换与运算符重载的关系。特别是,当有多个重载版本时,在进行函数匹配时涉及类型转换应如何处理。

14.1节 基本概念 习题答案

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

【出题思路】

理解重载运算符与内置运算符的区别。

【解答】

不同点:

重载操作符必须具有至少一个class或枚举类型的操作数。重载操作符不保证操作数的求值顺序,例如对&&和||的重载版本不再具有“短路求值”的特性,两个操作数都要进行求值,而且不规定操作数的求值顺序。相同点:对于优先级和结合性及操作数的数目都不变。

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

【出题思路】

本题练习重载运算符的声明。

【解答】

几个运算符的声明如下所示:

#ifndef SALES_DATA14_02_H
#define SALES_DATA14_02_H


#include <iostream>
#include <string>

class Sales_item
{
    friend std::istream& operator>>(std::istream&, Sales_item&);
    friend std::ostream& operator<<(std::ostream&, const Sales_item&);
    friend bool operator<(const Sales_item&, const Sales_item&);
    friend bool operator==(const Sales_item&, const Sales_item&);

public:
    Sales_item() = default;
    Sales_item(const std::string &book): bookNo(book) {  }
    Sales_item(std::istream &is) { is >> *this; }

public:
    Sales_item& operator+=(const Sales_item&);
    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_item &lhs, const Sales_item &rhs)
{
    return lhs.isbn() == rhs.isbn();
}

Sales_item operator+(const Sales_item&, const Sales_item&);

inline bool operator==(const Sales_item &lhs, const Sales_item &rhs)
{
    return (lhs.units_sold == rhs.units_sold) &&
           (lhs.revenue == rhs.revenue) &&
           (lhs.isbn() == rhs.isbn());
}

inline bool operator !=(const Sales_item &lhs, const Sales_item &rhs)
{
    return !(lhs == rhs);
}

Sales_item& Sales_item::operator +=(const Sales_item& rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

Sales_item operator +(const Sales_item& lhs, const Sales_item& rhs)
{
    Sales_item ret(lhs);
    ret += rhs;
    return ret;
}

std::istream& operator>>(std::istream& in, Sales_item& s)
{
    double price;
    in >> s.bookNo >> s.units_sold >> price;

    if(in)
        s.revenue = s.units_sold * price;
    else
        s = Sales_item();

    return in;
}

std::ostream& operator <<(std::ostream& out, const Sales_item& s)
{
    out << s.isbn() << " " << s.units_sold << " "
        << s.revenue << " " << s.avg_price();

    return out;
}

double Sales_item::avg_price() const
{
    if(units_sold)
        return revenue / units_sold;
    else
        return 0;
}


#endif // SALES_DATA14_02_H
#include "Sales_data14_02.h"
#include <iostream>


using namespace std;

int main()
{
    Sales_item trans1, trans2;
    std::cout << "请输入两条ISBN相同的销售记录:" << std::endl;
    std::cin >> trans1 >> trans2;
    if(compareIsbn(trans1, trans2))
        std::cout << "汇总信息:ISBN,售出本数,销售额和平均售价为: " << trans1 + trans2 << std::endl;
    else
        std::cout << "两条销售记录的ISBN不同" << std::endl;

    cout << "Hello World!" << endl;
    return 0;
}

运行结果:

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

(a) "cobble" == "stone"                  (b) svec1[0] == svec2[0]
(c) svec1 == svec2                       (d) svec1[0] == "stone"

【出题思路】

本题旨在理解编译器如何选择重载运算符的不同版本。

【解答】

(a)"cobble" == "store"应用了C++语言内置版本的==,比较两个指针。

(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) ()

【出题思路】

理解编译器如何选择重载运算符的不同版本。

【解答】

(a)%通常定义为非成员。

(b)%=通常定义为类成员,因为它会改变对象的状态。

(c)++通常定义为类成员,因为它会改变对象的状态。

(d)->必须定义为类成员,否则编译会报错。

(e)<<通常定义为非成员。

(f)&&通常定义为非成员。

(g)==通常定义为非成员。

(h)()必须定义为类成员,否则编译会报错。

练习14.5:在7.5.1节的练习7.40(第261页)中,编写了下列类中某一个的框加,请问在这个类中应该定义重载的运算符吗?如果是,请写出来。
(a) Book        (b) Date        (c) Employee
(b) Vehicle     (e) Object     (f) Tree   
【出题思路】
学会判断是否需要为类定义重载运算符。
【解答】
以(b)Date为例,为其定义重载的输出运算符,输入运算符可参照实现。显然,为Date定义输入输出运算符,可以让我们像输入输出内置类型对象那样输入输出Date,在易用性和代码的可读性上有明显的好处。因此,定义这两个重载运算符是合理的。

#include <iostream>

using namespace std;

class Date
{
    friend ostream& operator<<(ostream &os, const Date &dt);
public:
    Date();
    Date(int y, int m, int d)
    {
        year = y;
        month = m;
        day = d;
    }

private:
    int year;
    int month;
    int day;
};

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;
}

int main()
{
    Date date(2029, 8, 6);
    cout << "date==========" << date << endl;

    cout << "Hello World!" << endl;
    return 0;
}

运行结果:

date==========year:2029 month:8 day:6

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值