C++Primer第五版 第7章 类 练习
7.1 定义抽象数据类型
练习7.1.1
练习7.1.1:使用2.6.1节练习定义的Sales_data类为1.6节(第21页)的交易处理程序编写一个新版本。
#include <iostream>
#include <string>
using namespace std;
struct Sales_data{
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
void test(){
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.bookNo == trans.bookNo){ // 检查isbn
total.units_sold += trans.units_sold;
total.revenue += trans.revenue; // 更新变量total当前的值
}else {
cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; // 输出结果
total = trans; // 处理下一本书
}
}
cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; // 输出最后的一条交易
} else { //没有输入任何信息
cerr << "No data?!" << endl; // 通知用户
}
}
int main(){
test();
system("pause");
return 0;
}
练习7.1.2
练习7.2:曾在2.6.2节练习(第67页)中编写了一个Sales_data类,请向这个类添加combine和isbn成员。
//一个定义了Sales_data类的头文件Sales_data.h
#include <iostream>
#include <string>
using namespace std;
struct Sales_data{
//关于Sales_data对象的操作
string isbn() const {return this->bookNo;}//返回对象的isbn编号
Sales_data& combine(const Sales_data&);//将一个Sales_data对象加到另一个对象上
double avg_price() const;//返回售出书籍的平均价格
string bookNo; //表示isbn编号
unsigned units_sold = 0; //书的销量
double revenue = 0.0; //书的总销售收入
};
double Sales_data::avg_price()const{//常量成员函数,不会改变Sales_data对象的值
if(units_sold)
return revenue/units_sold;
else
return 0;
}
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold; //把rhs的成员加到this对象的成员上
revenue += rhs.revenue;
return *this; //返回调用该函数的对象
}
练习7.3:修改7.1.1节(第229页)的交易处理程序,令其使用这些成员。
#include <iostream>
#include <string>
#include "Sales_data.h"
using namespace std;
void test(){
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()){ // 检查isbn
total.combine(trans);// 更新变量total当前的值
}else {
cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; // 输出结果
total = trans; // 处理下一本书
}
}
cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; // 输出最后的一条交易
} else { //没有输入任何信息
cerr << "No data?!" << endl; // 通知用户
}
}
int main(){
test();
system("pause");
return 0;
}
练习7.4:编写一个名为Person的类,使其表示人员的姓名和地址。使用string对象存放这些元素,接下来的练习将不断充实这个类的其他特征。
#include <iostream>
#include <string>
using namespace std;
class Person{
public:
string mName;//人员姓名
string mAddress;//人员地址
};
练习7.5:在你的Person类中提供一些操作使其能够返回姓名和住址。这些函数是否应该是
const的呢?解释原因。 答:是const的,原因是这些操作不需要改变对象中成员变量的具体的值,只需要读取成员对象。
练习7.1.3
练习7.6:对于add, read和print,定义你自己的版本。
Sales_data add(const Sales_data& lhs, const Sales_data& rhs){
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
ostream &print(ostream& os, const Sales_data& item){
//将给定对象的内容打印到给定的流当中
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.avg_price();
return os;
}
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;
}
练习7.7:使用这些新函数重写7.1.2节(第233页)练习中的交易处理程序。
void test(){
Sales_data total; // 保存当前求和结果的变量
if (read(cin,total)) { // 读入第一笔交易
Sales_data trans; // 保存下一条交易数据的变量
while(read(cin,trans)) { // 读入剩余的交易
if (total.isbn() == trans.isbn()){ // 检查isbn
total.combine(trans);// 更新变量total当前的值
}else {
print(cout,total); // 输出结果
total = trans; // 处理下一本书
}
}
print(cout,total); // 输出最后的一条交易
} else { //没有输入任何信息
cerr << "No data?!" << endl; // 通知用户
}
}
练习7.8:为什么read函数将其Sales_data参数定义成普通的引用,而print将其参数定义成常量引用?
答: read函数是从给定流中将数据读到给定对象中,需要对Sales_data对象进行改变,其中成员变量revenue,bookNo等全部被更新;而print函数是将给定对象的内容打印到给定的流当中,不需要对Sales_data对象进行改变,只需要读取成员对象
练习7.9:对于7.1.2节(第233页)练习中的代码,添加读取和打印Person对象的操作。
istream &read(istream &is, Person &person)
{
return is >> person.mName >> person.mAddress;
}
ostream &print(ostream &os, const Person &person)
{
return os << person.mName << " " << person.mAddress;
}
练习7.10:在下面这条if语句中,条件部分的作用是什么?
if(read(read(cin,data1),data2))
答:read(cin,data1) ,向data1里输入内容,返回data1;read(read(cin,data1),data2) 即为read(data1,data2),将data1的内容输入到data2;只有当两次读入的内容都不空时,条件为真。
练习7.1.4
练习7.11:在你的Sales_data类中添加构造函数,然后 编写一段程序令其用到没个构造函数
Sales_Data.h
struct Sales_data{
//构造函数 (在类外实现)
Sales_data();
Sales_data(const string &s);
Sales_data(const string &s, unsigned n, double p);
Sales_data(istream &);
//关于Sales_data对象的操作
string isbn() const {return bookNo;}//返回对象的isbn编号
Sales_data& combine(const Sales_data&);//将一个Sales_data对象加到另一个对象上
double avg_price() const;//返回售出书籍的平均价格
string bookNo; //表示isbn编号
unsigned units_sold = 0; //书的销量
double revenue = 0.0; //书的总 销售收入
};
Sales_data.cpp
// Sales_data() = default;
// Sales_data(const string &s): bookNo(s) { }
// Sales_data(const string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n) { }
// // : bookNo(s), units_sold(n), revenue(p*n) 构造函数初始化列表
Sales_data::Sales_data(istream &is){
read(is, *this); //read函数的作用是从is中读取一条交易信息然后存入this对象中
}
Sales_data::Sales_data(const string &s, unsigned n, double p){
this->bookNo = s;
this->units_sold = n;
this->revenue = p*n ;
}
Sales_data::Sales_data(const string &s) {
this->bookNo = s;
}
// Sales_data::Sales_data(){}
Sales_data::Sales_data() = default;
void test(){
Sales_data total01;
print(cout,total01);
cout << endl;
Sales_data total02("1234");
print(cout,total02);
cout << endl;
Sales_data total03("1200",3,3.59);
print(cout,total03);
cout << endl;
Sales_data total04(cin);
print(cout,total04);
}
练习7.12:把只接受一个istream作为参数的构造函数定义到类的内部。
Sales_Data.h
struct Sales_data{
friend istream &read(istream&, Sales_data&);//read函数做友元
//构造函数
Sales_data(istream &is){
read(is, *this); //read函数的作用是从is中读取一条交易信息然后存入this对象中
}
//关于Sales_data对象的操作
string isbn() const {return bookNo;}//返回对象的isbn编号
Sales_data& combine(const Sales_data&);//将一个Sales_data对象加到另一个对象上
double avg_price() const;//返回售出书籍的平均价格
string bookNo; //表示isbn编号
unsigned units_sold = 0; //书的销量
double revenue = 0.0; //书的总 销售收入
};
练习7.13:使用istream构造函数重写第229页程序。
Sales_Data.h
struct Sales_data;
istream &read(std::istream&, Sales_data&);
struct Sales_data{
//构造函数
Sales_data();
// Sales_data() = default;
Sales_data(const string &s);
Sales_data(const string &s, unsigned n, double p);
Sales_data(istream &is){
read(is, *this); //read函数的作用是从is中读取一条交易信息然后存入this对象中
}
//关于Sales_data对象的操作
string isbn() const {return bookNo;}//返回对象的isbn编号
Sales_data& combine(const Sales_data&);//将一个Sales_data对象加到另一个对象上
double avg_price() const;//返回售出书籍的平均价格
string bookNo; //表示isbn编号
unsigned units_sold = 0; //书的销量
double revenue = 0.0; //书的总 销售收入
};
//Sales_data的非成员接口函数
Sales_data add(const Sales_data&, const Sales_data&);
ostream &print(ostream&, const Sales_data&);
练习7.14:编写一个构造函数,令其用我们提供的类内初始值显示地初始化成员
void test(){
Sales_data total(cin); // 读入第一笔交易
if (!total.isbn().empty()) {
istream &is = cin;// 读入剩余的交易
while(is) {
Sales_data trans(is);// 保存下一条交易数据的变量
if (!is) break;//剩余交易没有输入,中止输入
if (total.isbn() == trans.isbn()){ // 检查isbn
total.combine(trans);// 更新变量total当前的值
}else {
print(cout,total)<<endl;// 输出结果
total = trans; // 处理下一本书
}
}
print(cout,total)<<endl; // 输出最后的一条交易
} else { //没有输入任何信息
cerr << "No data?!" << endl; // 通知用户
}
}
练习7.15:为你的Person类添加正确的构造函数
Person.h
class Person{
public:
friend istream &read(istream &, Person &);
Person(){}
Person(string name,string address):mName(name), mAddress(address){}
Person(istream& is){
read(is,*this);
}
string mName;//人员姓名
string mAddress;//人员地址
};
// istream &read(istream &, Person &);
ostream &print(ostream &, const Person &);
Person.cpp
istream &read(istream &is, Person &person)
{
return is >> person.mName >> person.mAddress;
}
ostream &print(ostream &os, const Person &person)
{
return os << person.mName << " " << person.mAddress;
}
int main(){
Person p1;
print(cout,p1) << endl;
Person p2("张三","北京市海淀区");
print(cout,p2) << endl;
Person p3(cin);
print(cout,p3) << endl;
system("pause");
return 0;
}
练习7.1.5
无练习