C++ Primer课后习题解答(第七章)

Exercises Section 7.1.1

Ex7.1

#include<iostream>
#include<string>

struct Sales_data 
{
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

int main()
{
    Sales_data total;
    if (std::cin >> total.bookNo >> total.units_sold >> total.revenue)
    {
        Sales_data trans;
        while (std::cin >> trans.bookNo >> trans.units_sold >> trans.revenue)
        {
            if (total.bookNo == trans.bookNo)
                total.units_sold += trans.units_sold;
            else 
            {
                std::cout << total.bookNo << " " << total.units_sold << " " << total.revenue << std::endl;
                total = trans;
            }
        }
        std::cout << total.bookNo << " " << total.units_sold << " " << total.revenue << std::endl;
    }
    else 
    {
        std::cerr << "No data?!" << std::endl;
        return -1;
    }
    system("pause");
    return 0;
}

Exercises Section 7.1.2

Ex7.2

struct Sales_data 
{
    std::string isbn() const { return bookNo; }
    Sales_data& combine( const Sales_data&);
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

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

Ex7.3

#include<iostream>
#include<string>

struct Sales_data 
{
    std::string isbn() const { return bookNo; }
    Sales_data& combine( const Sales_data&);
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

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

int main()
{
    Sales_data total;
    if (std::cin >> total.bookNo >> total.units_sold >> total.revenue)
    {
        Sales_data trans;
        while (std::cin >> trans.bookNo >> trans.units_sold >> trans.revenue)
        {
            if (total.isbn() == trans.isbn())
                total.combine(trans);
            else 
            {
                std::cout << total.bookNo << " " << total.units_sold << " " << total.revenue << std::endl;
                total = trans;
            }
        }
        std::cout << total.bookNo << " " << total.units_sold << " " << total.revenue << std::endl;
    }
    else 
    {
        std::cerr << "No data?!" << std::endl;
        return -1;
    }
    system("pause");
    return 0;
} 

Ex7.4

struct Person
{
    std::string name;
    std::string address;
};

Ex7.5

struct Person
{
    std::string getName() const { return name; }
    std::string getAddr() const { return address; }
    std::string name;
    std::string address;
};

Exercises Section 7.1.3

Ex7.6

std::istream &read(istream &is, Sales_data &item)
{
    double price = 0.0;
    is >> item.bookNo >> item.units_sold >> price;
    item.revenue = price * item.units_sold;
    return is;
}

std::ostream &print(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " " << item.revenue;
    return os;
}

Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;
    sum.combine(rhs);
    return sum;
}

Ex7.7

#include<iostream>
#include<string>

using namespace std;

struct Sales_data 
{
    string isbn() const { return bookNo; }
    Sales_data &combine( const Sales_data &);
    string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

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

istream &read(istream &is, Sales_data &item)
{
    double price = 0.0;
    is >> item.bookNo >> item.units_sold >> price;
    item.revenue = price * item.units_sold;
    return is;
}

ostream &print(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " " << item.revenue;
    return os;
}

Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;
    sum.combine(rhs);
    return sum;
}

int main()
{
    Sales_data total;
    if (read(cin, total))
    {
        Sales_data trans;
        while (read(cin, trans))
        {
            if (total.isbn() == trans.isbn())
                total = add(total, trans);
            else 
            {
                print(cout, total);
                cout << endl;
                total = trans;
            }
        }
        print(cout, total);
        cout << endl;
    }
    else 
    {
        std::cerr << "No data?!" << std::endl;
        return -1;
    }
    system("pause");
    return 0;
}

Ex7.8

因为 read() 函数需要传入 cin,改变了定义的变量值;
print() 函数不需要改变变量值故而定义为 const

Ex7.9

struct Person
{
    std::string getName() const { return name; }
    std::string getAddr() const { return address; }
    std::string name;
    std::string address;
};

std::istream &read(istream &is, Person &item)
{
    is >> item.name >> item.address;
    return is;
}

std::ostream &print(ostream &os, const Person &item)
{
    os << item.getName() << " " << item.getAddr();
    return os;
}

Ex7.10

if (read(read(cin, data1), data2)	// 判断 data1 和 data2 是否都有数据输入 

Exercises Section 7.1.4

Ex7.11 7.12 7.13 7.14

#include<iostream>
#include<string>

using namespace std;

struct Sales_data 
{
    Sales_data() = default;
    Sales_data(const std::string &s) : bookNo(s) {}
    Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p * n) {}
    Sales_data(std::istream &);
    std::string isbn() const { return bookNo; }
    Sales_data &combine( const Sales_data &);
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

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

istream &read(istream &is, Sales_data &item)
{
    double price = 0.0;
    is >> item.bookNo >> item.units_sold >> price;
    item.revenue = price * item.units_sold;
    return is;
}

ostream &print(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " " << item.revenue << endl;
    return os;
}
int main()
{
    Sales_data s1("", 0.0, 0.0);
    Sales_data s2("0-201-78134-X");
    Sales_data s3("0-201-78134-X", 10, 0.2);
    Sales_data s4;
    read(cin, s4);
    print(cout, s1);
    print(cout, s2);
    print(cout, s3);
    print(cout, s4);
    system("pause");
    return 0;
}

Ex7.15

struct Person
{
    Person() = default;
    Person(const std::string &s) : name(s) {}
    Person(const std::string &s, const std::string &a) : name(s), address(a) {}
    string getName() const { return name; }
    string getAddr() const { return address; }
    std::string name;
    std::string address;
};

Exercises Section 7.2

Ex7.16

public:后面应该跟函数和方法
private:后面应该跟定义的变量

Ex7.17

不使用 publicprivate 的话, class 后面的为 private 成员,struct 后面的为 public 成员

Ex7.18

封装就是只提供使用该类的接口,而不表明该类是如何实现的;
封装使使用者更方便使该类

Ex7.19

构造函数和 getName()、getAddr()应该为 public 成员;
变量 name 和 address 应该为 private 成员

Exercises Section 7.2.1

Ex7.20

被声明为一个类的友元函数可以调用该类的 private 成员;
友元给函数提供了方便,但是也增加了函数的不安全性

Ex7.21

class Sales_data 
{
public:
    Sales_data() = default;
    Sales_data(const std::string &s) : bookNo(s) {}
    Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p * n) {}
    Sales_data(std::istream &);
    std::string isbn() const { return bookNo; }
    Sales_data &combine( const Sales_data &);

private:
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

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

Ex7.22

class Person
{
public:
    Person() = default;
    Person(const std::string &s) : name(s) {}
    Person(const std::string &s, const std::string &a) : name(s), address(a) {}
    string getName() const { return name; }
    string getAddr() const { return address; }

private:
    std::string name;
    std::string address;
};

Exercises Section 7.3.1

Ex7.23 7.24

class Screen
{
public:
    typedef std::string::size_type pos;
    Screen() = default;
    Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) {}
    Screen(pos ht, pos wd, char c) : heiget(ht), width(wd), cursor(c) {}
    char get() const {  return contents[curosr]; }
    inline char get(pos ht, pos wd) const;
private:
    pos cursor = 0;
    pos height = 0, width = 0;
    std::string contents;
};

Ex7.25

如果未显式定义带参构造函数,那么默认构造函数就是安全的。

Ex7.26

class Sales_data 
{
public:
    Sales_data() = default;
    Sales_data(const std::string &s) : bookNo(s) {}
    Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p * n) {}
    Sales_data(std::istream &);
    std::string isbn() const { return bookNo; }
    Sales_data &combine( const Sales_data &);

private:
    inline double avg_price() const { return units_sold ? revenue / units_sold : 0; }
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

Exercises Section 7.3.2

Ex7.27

#include<iostream>
#include<string>

using namespace std;

class Screen
{
public:
    typedef std::string::size_type pos;
    Screen() = default;
    Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) {}
    char get() const {  return contents[cursor]; }
    inline char get(pos ht, pos wd) const;
    Screen &move(pos r, pos c);
    Screen &set(char);
    Screen &set(pos, pos, char);
    Screen &display(std::ostream &os) { do_display(os); return *this; }
    const Screen &display(std::ostream &os) const { do_display(os); return *this; }

private:
    void do_display(std::ostream &os) const { os << contents; }
    pos cursor = 0;
    pos height = 0, width = 0;
    std::string contents;
};

char Screen::get(pos r, pos c) const 
{
    pos row = r * width;
    return contents[row + c];
}

inline Screen& Screen::move(pos r, pos c)
{
    pos row = r * width;
    cursor = row + c;
    return *this;
}

inline Screen &Screen::set(char c)
{
    contents[cursor] = c;
    return *this;
}

inline Screen &Screen::set(pos r, pos col, char ch)
{
    contents[r * width + col] = ch;
    return *this;
}

int main()
{
    Screen myScreen(5, 5, 'X');
    myScreen.move(4, 0).set('#').display(cout);
    cout << "\n";
    myScreen.display(cout);
    cout << "\n";
    system("pause");
    return 0;
}

在这里插入图片描述

Ex7.28

只会对其副本进行修改,不会改变对象的值。

Ex7.29

在这里插入图片描述

Ex7.30

优点:比较明确
缺点:不够简洁

Exercises Section 7.3.3

Ex7.31

class X
{
    Y *y;
};

class Y
{
    X x;
};

Exercises Section 7.3.4

Ex7.32

class Screen
{
	friend class Window_mgr;
public:
    typedef std::string::size_type pos;
    Screen() = default;
    Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) {}
    char get() const {  return contents[cursor]; }
    inline char get(pos ht, pos wd) const;
    Screen &move(pos r, pos c);
    Screen &set(char);
    Screen &set(pos, pos, char);
    Screen &display(std::ostream &os) { do_display(os); return *this; }
    const Screen display(std::ostream &os) const { do_display(os); return *this; }

private:
    void do_display(std::ostream &os) const { os << contents; }
    pos cursor = 0;
    pos height = 0, width = 0;
    std::string contents;
};

char Screen::get(pos r, pos c) const 
{
    pos row = r * width;
    return contents[row + c];
}

inline Screen &Screen::move(pos r, pos c)
{
    pos row = r * width;
    cursor = row + c;
    return *this;
}

inline Screen &Screen::set(char c)
{
    contents[cursor] = c;
    return *this;
}

inline Screen &Screen::set(pos r, pos col, char ch)
{
    contents[r * width + col] = ch;
    return *this;
}

class Window_mgr
{
public:
    using ScreenIndex = std::vector<Screen>::size_type;
    void clear(ScreenIndex);

private:
    std::vector<Screen> screens{Screen(24, 80, ' ')};
}

void Window_mgr::clear(ScreenIndex i)
{
    Screen &s = screens[i];
    s.contents = string(s.height * s.width, ' ');
}

Exercises Section 7.4

Ex7.33

pos Screen::size() const 	// pos 定义在类内,在类外找不到该类型
{
	return height * width;
}

// 修改如下
Screen::pos Screen::size() const 
{
	return height * width;
}

Exercises Section 7.4.1

Ex7.34

当把 pos 类型声明放到最后,类会出错;前面定义的 pos 类的函数和变量都找不到该类。

Ex7.35

typedef string Type;
Type initVal();     // Type = string
class Exercise
{
public:
    typedef double Type;
    Type setVal(Type);  // Tpye = double
    Type initVal();     // Type = double

private:
    int val;
};
Type Exercise::setVal(Type parm)    // Type = string
{
    val = parm + initVal();
    return val;
}

Exercises Section 7.5.1

Ex7.36

struct X
{
	// base % j 无效
    X (int i, int j) : base(i), rem(base % j) {}
    int rem, base;
};

// 修改如下
struct X
{
    X (int i, int j) : base(i), rem(i % j) {}
    int rem, base;
};

Ex7.37

Sales_data first_item(cin);		// 参数为 std::istream & 的构造函数

int main() 
{
	Sales_data next;	// 默认构造函数
    Sales_data last("9-999-99999-9");	// 参数为 std::string 的构造函数
}

Ex7.38

 Sales_data(std::istream &is = cin);

Ex7.39

不合法;产生二义性

Ex7.40

class Book
{
public:
    Book() = default;
    Book(const std::string s) : bookNo(s) {}
    Book(const std::string s, const std::String n, const double p) : BookNo(s), author_name(n), price(p) {}

private:
    std::string bookNo;
    std::string author_name;
    double price = 0.0;
};

Exercises Section 7.5.2

Ex7.41

class Sales_data 
{
public:
    Sales_data(const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p * n) {}
    Sales_data(std::istream &) : Sales_data("", 0, 0) {}
    Sales_data(const std::string &s) : Sales_data(s, 0, 0) {}
    Sales_data(std::istream &is) : Sales_data("", 0, 0) { read(is, *this); }
    // 其他成员一样
};

Exercises Section 7.5.3

Ex7.43

class NoDefault 
{
public:
    NoDefault(const int) {}
};

class C
{
public:
    C() : my_c(0) {}
private:
    NoDefault my_c;
};

Ex7.44

vector<NoDefault> vec(10);	// 不合法,因为 NoDefault 中没有默认构造函数

Ex7.45

vector<C> vec(10); // 合法,因为 C 中有默认构造函数

Ex7.46

a) 不正确;不提供构造函数的话编译器会提供默认构造函数
b) 不正确;默认构造函数不仅没有参数而且函数体中没有语句
c) 不正确;编译器提供默认构造函数不关心值是否有意义
d) 不正确;只有当没有显式提供任何构造函数时,编译器才会提供默认构造函数

Exercises Section 7.5.4

Ex7.47

防止构造函数进行隐式转换;
优点:可以减少一些难以看懂的代码产生
缺点:减少了能通过编译的代码

Ex7.48

// 非explicit;调用构造函数进行隐式转换
// explicit;发生错误
string null_isbn("9-999-99999-9");
Sales_data item1(null_isbn);	
Sales_data item2("9-999-99999-9");

Ex7.49

// 调用 i.combine(s); i 为 Sales_data 类型, s 为 string 类型
a) Sales_data &combine(Sales_data);	// 合法
b) Sales_data &combine(Sales_data&);	// 非法;std::string& 类型不能转换为 Sales_data 类型
c) Sales_data &combine(const Sales_data&) const;	// 非法;函数后面的 const 表明不能对函数体内成员进行修改

Ex7.50

struct Person 
{
    friend std::istream &read(std::istream &is, Person &person);
    friend std::ostream &print(std::ostream &os, const Person &person);

public:
    Person() = default;
    Person(const std::string sname, const std::string saddr) : name(sname), address(saddr) { }
    explicit Person(std::istream &is) { read(is, *this); }

    std::string getName() const { return name; }
    std::string getAddress() const { return address; }

private:
    std::string name;
    std::string address;
};

std::istream &read(std::istream &is, Person &person)
{
    is >> person.name >> person.address;
    return is;
}

std::ostream &print(std::ostream &os, const Person &person)
{
    os << person.name << " " << person.address;
    return os;//返回类型为引用
}

Ex7.51

vector的单参数构造函数声明为 explicit 避免了一些不必的隐式转换;
string 的单参数构造函数不声明为 explicit 可以方便使用者

Exercises Section 7.5.5

Ex7.52

// 聚合类需要保证类内的成员都无初始值
struct Sales_data
{
	std::string bookNo;
    unsigned units_sold;
    double revenue;
};
Sales_data item = {"978-0590353403", 25, 15.99};

Exercises Section 7.5.6

Ex7.53

class Debug
{
public:
	constexpr Debug(bool b = true) : hw(b), io(b), other(b) {}
    constexpr Debug(bool h, bool i, bool o) : hw(h), io(i), other(o) {}
    constexpr bool any() { return hw || io || other; }
    void set_io(bool b) { io = b; }
    void set_hw(bool b) { hw = b; }
    void set_other(bool b) { hw = b; }

private:
	bool hw;
    bool io;
    bool other;
};

Ex7.54

不应该;声明为 constexpr 的函数应该包含一条 return 语句

Ex7.55

是的; a aggregate class must be a literal class 

Exercises Section 7.6

Ex7.56

static 成员与该类相关,而不是类内的对象;
优点:每个 static 成员都无需存储公共数据,而且更改了数据,每个成员都能使用新值;
static 成员可以声明为它所属的类型;而非 static 成员只能声明为所属类

Ex7.57

class Account
{
public:
    void calculate() { amount += amount * interestRate; }
    static double rate() { return interestRate; }
    static void rate(double);
    
private:
    std::string owner;
    double amount;
    static double interestRate;
    static double initRate();
};

Ex7.58

// example.h
class Example
{
public:
    static double rate = 6.5;	// 静态类内初始化必须是常量表达式
    // 修改: static const double rate = 6.5;
    static const int vecSize = 20;
    static vector<double> vec(vecSize);
};

// example.c
#include "example.h"
double Example::rate;
vector<double> Example::vec;
posted @   astralcon  阅读(19)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示