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
不使用 public 和 private 的话, 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;