C++ Primer(第五版)课后习题记录 —— 第七章

第七章 类

练习7.1

@!#%^#()@(#(@#@@!#%%%#%@%))

练习7.2

#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string>

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

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

练习7.3

#include "Sales_data.h"
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

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

    return 0;
}

练习7.4

#ifndef PERSON_H_
#define PERSON_H_
#include <string>
struct Person {
    std::string name;
    std::string addr;
};
#endif // PERSON_H_

练习7.5

#ifndef PERSON_H_
#define PERSON_H_
#include <string>
struct Person {
    std::string retName() const { return name; };
    std::string retAddr() const { return addr; };
    std::string name;
    std::string addr;
};
#endif // PERSON_H_

练习7.6

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

std::ostream& print(std::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;
}

练习7.7

#include "Sales_data.h"
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

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

    return 0;
}

练习7.8

read 函数会改变 Sales_data 参数的值,所以定义成普通引用。
print 函数不存在对该参数的值的操作,所以定义成常量引用。

练习7.9

#include <iostream>
std::istream& readP(std::istream& is, Person& person) {
    is >> person.name >> person.addr;
    return is;
}
std::ostream& printP(std::ostream& os, const Person& person) {
    os << person.name << " " << person.addr;
    return os;
}

练习7.10

一次读入两项指定类型的数据。

练习7.11

//Sales_data.h红添加的部分
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(n * p) {}
    Sales_data(std::istream&);
};
Sales_data::Sales_data(std::istream& is) {
    read(std::cin, *this);
}
//主函数
#include "Sales_data.h"
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int main()
{
    Sales_data in1;
    print(cout, in1) << endl;
    Sales_data in2("sup");
    print(cout, in2) << endl;
    Sales_data in3("hola", 5, 7.6);
    print(cout, in3) << endl;
    Sales_data in4(cin);
    print(cout, in4) << endl;
    return 0;
}

练习7.12

//由于 read 在类外定义,所以应该将 read 函数在类之前先声明一下,改变部分如下
struct Sales_data;
std::istream& read(std::istream&, Sales_data&);
struct Sales_data {
  Sales_data(std::istream& is) {
        read(std::cin, * this);
        };
}

练习7.13

#include "Sales_data.h"
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int main()
{
    Sales_data total(cin);
    if (!total.isbn().empty()) {
       // std::istream& is = std::cin;
        while (cin) {
            Sales_data trans(cin);
            if (total.isbn() == trans.isbn())
                total.combine(trans);
            else {
                print(cout, total) << endl;
                total = trans;
            }
        }
    }
    else {
        std::cerr << "No data?!" << endl;
        return -1;
    }

    return 0;
}

练习7.14

Sales_data() : units_sold(0), revenue(0.0) {}

练习7.15

Person() = default;
Person(std::string n) : name(n) {}

练习7.16

没有限制。
用来作为接口的构造函数与一些成员函数定义在 public 之后。
只能被类的成员函数访问的函数与类的成员定义在 private 之后。

练习7.17

有区别。默认访问权限不一样。

练习7.18

封装可以使类中的一部分成员不被使用该类的代码访问,增强了稳定性。

练习7.19

我会把 name 和 addr 声明成 private,这两个成员不应该被外界直接访问。
其他的成员函数可以声明成 public。

练习7.20

友元在类外函数想要访问声明成 private 的类成员时有用。

练习7.21

//修改的部分
class Sales_data {
friend Sales_data add(const Sales_data&, const Sales_data&);
friend std::istream& read(std::istream&, Sales_data&);
friend std::ostream& print(std::ostream&, const Sales_data&);
    // consturcters
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(n * p) {}
    Sales_data(std::istream& is) {
        read(std::cin, *this);
        }
    std::string isbn() const { return bookNo; }
    Sales_data &combine (const Sales_data&);
private:
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

练习7.22

class Person {
friend std::istream& readP(std::istream&, Person&);
friend std::ostream& printP(std::ostream&, const Person&);
public:
    Person() = default;
    Person(std::string n) : name(n) {};
    std::string retName() const { return name; };
    std::string retAddr() const { return addr; };

private:
    std::string name;
    std::string addr;
};
std::istream& readP(std::istream& is, Person& person) {
    is >> person.name >> person.addr;
    return is;
}
std::ostream& printP(std::ostream& os, const Person& person) {
    os << person.name << " " << person.addr;
    return os;
}

练习7.23 & 练习7.24

#ifndef SCREEN_H
#define SCREEN_H
class Screen {
public:
    using pos = std::string::size_type;
    Screen() = default;
    Screen(pos h, pos w) : height(h), width(w), content(h * w, ' ') {}
    Screen(pos h, pos w, char c) : height(h), width(w), content(h * w, c) {}
    char get() cosnt { return content[cursor]; }
    inline char get(pos, pos) const;    
private:
    pos height = 0;
    pos width = 0;
    pos cursor = 0;
    std::string content;
};

char Screen::get (pos row, pos w=col) {
    return content[row * width + col];
}

#endif // SCREEN_H

练习7.25

可以。因为 Screen 中的成员都是内置类型与 string 类型,所以能安全地使用拷贝与赋值操作的默认版本。

练习7.26

!@%#^!#%&$!^#

练习7.27

#ifndef SCREEN_H
#define SCREEN_H
#include <string>
class Screen {
public:
    using pos = std::string::size_type;
    Screen() = default;
    Screen(pos h, pos w) : height(h), width(w), content(h * w, ' ') {}
    Screen(pos h, pos w, char c) : height(h), width(w), content(h * w, c) {}
    char get() const { return content[cursor]; }
    char get(pos, pos);
    inline char get(pos, pos) const;
    Screen &move(pos, pos);
    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 << content; }
    pos height = 0;
    pos width = 0;
    pos cursor = 0;
    std::string content;
};

char Screen::get (pos row, pos col) {
    return content[row * width + col];
}
inline Screen &Screen::move(pos r, pos c){
    cursor = r * width + c;
    return * this;
}
inline Screen &Screen::set(char c) {
    content[cursor] = c;
    return * this;
}
inline Screen &Screen::set(pos row, pos col, char c) {
    content[row * width + col] = c;
    return * this;
}
#endif // SCREEN_H

练习7.28

第二行的输出与第一行不一样,而是与初始化时的 myScreen 一样。

练习7.29

正确。因为函数返回 Screen 导致这三个操作的 myScreen 本身无影响。

练习7.30

使用 this 指针通常能增加可读性,使代码更易被理解,但是也增加了代码量,显得多余。

练习7.31

class X;
class Y;

class X {
    Y* y = nullptr;
};
class Y {
    X x;
};

练习7.32

// 只包括新添加的部分
class Window_mgr {
public:
    using ScreenIndex = std::vector<Screen>::size_type;
    void clear(ScreenIndex);
private:
    std::vector<Screen> screens;
};
class Screen {
friend void Window_mgr::clear(ScreenIndex);  
};
void Window_mgr::clear(ScreenIndex i) {
    Screen &s = screens[i];
    s.content = string(s.height * s.width, ' ');
}

练习7.33

//pos 是在 Screen 内定义的数据类型
Screen::pos Screen::size() const {
  return height * width;

}

练习7.34

之前有用到 pos 的地方都会报错。

练习7.35

typedef string Type;
Type initVal(); // Type 用的是 string 型
class Exercise {
public:
    typedef double Type;
    Type setVal(Type); // 用的是 double 型
    Type initVal(); // 同上
private:
    int val;
};
//需要修改,因为返回的 val 是 int 型,按上下文,这个的 Type 应该是类中声明的 Type
Exercise::Type Exercise::setVal(Type parm) {  // 修改之前,前一个是 string 型,后一个是 double 型
    val = parm + initVal();     // 用的 double 型
    return val;
}

练习7.36

初始化顺序有误,应该按照声明的顺序先初始化 rem 再初始化 base。

练习7.37

对于 first_item ,他的成员取决于输入。
对于 next , 进行了默认初始化, bookNo = “”, units_sold = 0, revenue = 0.0。
对于 last , 入了只接受一个 string 实参的函数, bookNo = “9-999-99999-9”,
units_sold = 0, revenue = 0.0。

练习7.38

Sales_data(std::istream &is = std::cin) { read(is, *this); }

练习7.39

不合法,那样会使下文中调用函数时混淆。

练习7.40

%%^@ ##^&%&^*

练习7.41

//构造函数标记部分如下
Sales_data(const std::string& s, unsigned n, double p):
        bookNo(s), units_sold(n), revenue(n * p) { std::cout << "core" << std::endl;}
Sales_data() : Sales_data("", 0, 0) { std::cout << "default" << std::endl;}
Sales_data(const std::string& s ) : Sales_data(s, 0, 0) { std::cout << "onlystring" << std::endl;}
Sales_data(std::istream& is) : Sales_data() {
        std::cout << "all inoput" << std::endl;
        read(is, *this);
}
//主函数部分
int main()
{
    Sales_data item1("sada", 213, 213);
    cout << "------------------" << endl;
    Sales_data item2();
    cout << "------------------" << endl;
    Sales_data item3("asfasf");
    cout << "------------------" << endl;
    Sales_data item4(cin);
    cout << "------------------" << endl;
}

练习7.42

(&……)@&@&)&#——&……

练习7.43

class C {
  NoDefault c;
public:
  C() : c(0) {} //默认构造函数
};

练习7.44

不合法,因为容器一开始有10个元素,都应该被初始化,而 NoDefault 类型没有默认构造函数。

练习7.45

合法。因为类型 C 中包含默认构造函数。

练习7.46

(a) 不正确。如果没有显式地定义构造函数,编译器会隐式地定义一个默认构造函数。
(b) 不正确。默认构造函数只是说可以不提供实参也能被调用,也有参数列表不空的默认构造函数。
(c) 不正确。也应该提供默认构造函数为特殊情况着想,比如在其他类中定义声明该类的成员时。
(d) 不正确。 只有在类中没有显式地定义任何构造函数时,编译器才会生成一个默认构造函数。

练习7.47

这样的定义没有太大的意义,但在不同的使用场景中,可能会有不一样要求。

练习7.48

item1 能被正常初始化, item2 不能。
这三行定义与构造函数是不是 explicit 无关。

练习7.49

(a) 正确。
(b) 不正确。因为 sting 型始终不能通过一次隐式转换成 Sales_data& 型。
(c) 声明有误,最后的 const 会导致指向 i 的 this 指针成为一个指向常量的指针,有违函数本身的意图。

练习7.50

没得必要。

练习7.51

容器本身里面的参数类型是需要被定义的,很难进行默认的隐式转换,而 string 型中每个元素的类型都是确定的。

练习7.52

存在问题,因为该 Sales_data 类中包含了类内初始值,所以不能这样初始化。

练习7.53

#ifndef DEBUG_H
#define DEBUG_H

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) { other = b; }
private:
    bool hw;
    bool io;
    bool other;
};
#endif // DEBUG_H

练习7.54

不能吧。 constexpr 函数要求函数体中有且仅有一条 return 语句,而这三个 set 函数都是 void 型的。

练习7.55

不是。 string 类型不是字面值类型。

练习7.56

仅与类的本身相关而与类中的其他对象无关的成员叫做静态成员。它存在与存在与任何对象之外,所有该类的对象也共享这个静态成员。

练习7.57

#ifndef ACCOUNT_H_INCLUDED
#define ACCOUNT_H_INCLUDED
#include <string>
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();
};
void Account::rate(double newRate) {
    interestRate = newRate;
}
double Account::rate(0.668);
double Account::interestRate;
#endif // ACCOUNT_H_INCLUDED

练习7.58

//example.h
class Example {
public:
  static constexpr double rate = 6.5; //类内初始值需为字面值常量类型的 constexpr
  static const int vecSize = 20;
  static vector<double> vec;   //不能在类内初始化
};
//example.C
#include "example.h"
constexpr double Example::rate;
std::vector<double> Example::vec(Example::vecSize);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值