《C++ Primer》第7章 类
7.1节 定义抽象数据类型
练习7.1:使用2.6.1节练习定义的Sales_data类为1.6节(第21)的交易处理程序编写一个新版本。
【出题思路】
程序的思路是:只要ISBN相同,就不断累加销量并重新计算平均售价,直至输入新的书籍为止。
【解答】
满足题意的程序如下所示:
//Sales_data.h
#ifndef SALES_DATA_H
#define SALES_DATA_H
// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>
class Sales_data {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator >> (std::istream&, Sales_data&);
friend std::ostream& operator << (std::ostream&, const Sales_data&);
friend bool operator < (const Sales_data&, const Sales_data&);
friend bool operator == (const Sales_data&, const Sales_data&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_data() = default;
Sales_data(const std::string &book): bookNo(book) { }
Sales_data(std::istream &is) { is >> *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_data& operator += (const Sales_data&);
// operations on Sales_item objects
std::string isbn() const { return bookNo; }
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
unsigned units_sold = 0; // explicitly initialized
double revenue = 0.0;
};
// used in chapter 10
inline bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_data operator + (const Sales_data&, const Sales_data&);
inline bool operator == (const Sales_data &lhs, const Sales_data &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool operator != (const Sales_data &lhs, const Sales_data &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_data& Sales_data::operator += (const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_data operator + (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
std::istream& operator >> (std::istream& in, Sales_data& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_data(); // input failed: reset object to default state
return in;
}
std::ostream& operator << (std::ostream& out, const Sales_data& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_data::avg_price() const
{
if (units_sold)
return revenue/units_sold;
else
return 0;
}
#endif // SALES_DATA_H
#include <iostream>
#include "Sales_data.h"
using namespace std;
int main() {
cout << "请输入交易记录(ISBN, 销售量,原价,实际售价):" << endl;
Sales_data total; //保存下一条交易记录的变量
//读入并处理剩余交易记录
if(cin >> total)
{
Sales_data trans;
while (cin >> trans)
{
//如果我们仍在处理相同的书
if(total.isbn() == trans.isbn())
{
total += trans; //更新总销售额
}
else
{
//打印前一本书的结果
cout << "前一本书的结果:" << total << endl;
total = trans; //total现在表示下一本书的销售额
}
}
cout << "total:" << total << endl; //打印最后一本书的结果
}
else
{
//没有输入!警告读者
cerr << "No data!" << endl;
return -1; //表示失败
}
return 0;
}
运行结果:
//定义公有函数成员
public:
// isbn函数只有一条语句,返回bookNo
std::string isbn() const { return bookNo; }
//combine函数用于把两个ISBN相同的销售记录合并在一起
Sales_data& combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold; //累加书籍的销售量
saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold)
/ (rhs.units_sold + units_sold); //重新计算实现销售价格
discount = saleprice / sellingprice; //重新计算实际折扣
return *this; //返回合并后的结果
}
// 定义私有数据成员
private:
std::string bookNo; // 书籍编号,隐式初始化为空串
unsigned units_sold = 0; // 销售量,显式初始化为0
double sellingprice = 0.0; // 原始价格,显式初始化为0.0
double saleprice = 0.0; // 实售价格,显式初始化为0.0
double discount = 0.0; // 折扣,显式初始化为0.0
练习3:修改7.1.1节(第229页)的交易处理程序,令其使用这些成员。
【出题思路】
该程序的作用是累加相同编号的书籍销售记录并输出,直至遇到下一个编号为止。改写程序时,用上一题定义的isbn函数获取书籍的编号,用combine函数把两条销售记录相加。
【解答】
满足题意的程序如下所示:
#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <iostream>
#include <string>
class Sales_data {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator >> (std::istream&, Sales_data&);
friend std::ostream& operator << (std::ostream&, const Sales_data&);
friend bool operator < (const Sales_data&, const Sales_data&);
friend bool operator == (const Sales_data&, const Sales_data&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_data() = default;
Sales_data(const std::string &book): bookNo(book) { }
Sales_data(std::istream &is) { is >> *this; }
//定义公有函数成员
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_data& operator += (const Sales_data&);
// operations on Sales_item objects
double avg_price() const;
std::string isbn() const { return bookNo; }
//combine函数用于把两个ISBN相同的销售记录合并在一起
Sales_data& combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold; //累加书籍的销售量
//std::cout << "units_sold==================" << units_sold << std::endl;
saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold)
/ (rhs.units_sold + units_sold); //重新计算实现销售价格
discount = saleprice / sellingprice; //重新计算实际折扣
revenue += rhs.revenue; //总销售额
return *this; //返回合并后的结果
}
// 定义私有数据成员
private:
std::string bookNo; // 书籍编号,隐式初始化为空串
unsigned units_sold = 0; // 销售量,显式初始化为0
double sellingprice = 0.0; // 原始价格,显式初始化为0.0
double saleprice = 0.0; // 实售价格,显式初始化为0.0
double discount = 0.0; // 折扣,显式初始化为0.0
double revenue = 0.0; // 总收入
};
// used in chapter 10
inline bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_data operator + (const Sales_data&, const Sales_data&);
inline bool operator == (const Sales_data &lhs, const Sales_data &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool operator != (const Sales_data &lhs, const Sales_data &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_data& Sales_data::operator += (const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_data operator + (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
//接收4个参数分别为:ISBN,销售量,原价,实际售价
std::istream& operator >> (std::istream& in, Sales_data& s)
{
in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * s.saleprice;
else
s = Sales_data(); // input failed: reset object to default state
return in;
}
std::ostream& operator << (std::ostream& out, const Sales_data& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_data::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
#endif
#include <iostream>
#include "Sales_data.h"
using namespace std;
int main()
{
cout << "请输入交易记录(ISBN),销售量,原价,实际售价:" << endl;
Sales_data total;//保存下一条交易记录的变量
//读入第一条交易记录,并确保有数据可以处理
if(cin >> total)
{
Sales_data trans;//保存和的变量
//读入并处理剩余交易记录
while(cin >> trans)
{
//如果我们仍在处理相同的书
if(total.isbn() == trans.isbn())
{
total.combine(trans); //更新总销额
}
else
{
//打印前一本书的结果
cout << total << endl;
total = trans;//total现在表示下一本书的销售额
}
}
cout << total << endl;//打印最后本书的结果
}
else
{
//没有输入! 警告读者
cerr << "No data?!" << endl;
return -1;//表示失败
}
return 0;
}
#include <iostream>
#include "Sales_data.h"
using namespace std;
int main()
{
cout << "请输入交易记录(ISBN),销售量,原价,实际售价:" << endl;
Sales_data total;//保存下一条交易记录的变量
//读入第一条交易记录,并确保有数据可以处理
if(cin >> total)
{
Sales_data trans;//保存和的变量
//读入并处理剩余交易记录
while(cin >> trans)
{
//如果我们仍在处理相同的书
if(total.isbn() == trans.isbn())
{
total.combine(trans); //更新总销额
}
else
{
//打印前一本书的结果
cout << total << endl;
total = trans;//total现在表示下一本书的销售额
}
}
cout << total << endl;//打印最后本书的结果
}
else
{
//没有输入! 警告读者
cerr << "No data?!" << endl;
return -1;//表示失败
}
return 0;
}
运行结果:
练习7.4:编写一个名为Person的类,使其表示人员的姓名和信址,使用string对象存放这些元素,接下来的练习不断充实这个类的其他特征。
【出题思路】
练习定义类并添加必要的数据成员。
【解答】
满足题意的Person类是:
class Person
{
private:
std::string strName;
std::string strAddress;
};
练习5:在你的Person 类中提供一些操作使其能够返回姓名和住址。这些函数是否应该是const的呢,解释原因。
【出题思路】
练习向类添加函数成员的方法,理解常量成员函数。
【解答】
修改后的Person类是:
class Person
{
public:
string getName() const { return strName; }
string getAddress() const {return strAddress;}
private:
std::string strName;
std::string strAddress;
};
上述两个函数应该被定义成常量成员函数,因为不论返回姓名还是返回地址,函数体内都是只读取数据成员的值,而不会做任何改变。
练习6:对于函数add,read和print,定义你自已的版本
【出题思路】
参考书中的示例,定义自己的版本,注意读入和输出的具体信息应与类的数据成员保持一致。
【解答】
满足题意的add、read和print函数分别如下所示:
//add
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
//read
std::istream &read(std::istream &is, Sales_data &item)
{
is >> item.bookNo >> item.units_sold >> item.sellingprice >> item.saleprice;
return is;
}
//print
std::ostream &print(std::ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " " << item.sellingprice << " " << item.saleprice << " " << item.discount;
return os;
}
练习7:使用这些新函数重写7.1.2节(第233页)练习中的交易处理程序。
【出题思路】
用read函数替代>>,print函数替代<<,add函数替代combine函数。
【解答】
我们自定义的print函数不负责输出回车符,满足题意的程序如下所示:
#ifndef SALES_DATA_7_7_H
#define SALES_DATA_7_7_H
#include <iostream>
#include <string>
class Sales_data {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
friend std::istream& operator >> (std::istream&, Sales_data&);
friend std::ostream& operator << (std::ostream&, const Sales_data&);
friend bool operator < (const Sales_data&, const Sales_data&);
friend bool operator == (const Sales_data&, const Sales_data&);
//add
friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
//read
friend std::istream &read(std::istream &is, Sales_data &item);
//print
friend std::ostream &print(std::ostream &os, const Sales_data &item);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_data() = default;
Sales_data(const std::string &book): bookNo(book) { }
Sales_data(std::istream &is) { is >> *this; }
//定义公有函数成员
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_data& operator += (const Sales_data&);
// operations on Sales_item objects
double avg_price() const;
std::string isbn() const { return bookNo; }
//combine函数用于把两个ISBN相同的销售记录合并在一起
Sales_data& combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold; //累加书籍的销售量
saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold)
/ (rhs.units_sold + units_sold); //重新计算实现销售价格
discount = saleprice / sellingprice; //重新计算实际折扣
revenue += rhs.revenue; //总销售额
return *this; //返回合并后的结果
}
// 定义公有数据成员,外部普通函数要调用
public:
std::string bookNo; // 书籍编号,隐式初始化为空串
unsigned units_sold = 0; // 销售量,显式初始化为0
double sellingprice = 0.0; // 原始价格,显式初始化为0.0
double saleprice = 0.0; // 实售价格,显式初始化为0.0
double discount = 0.0; // 折扣,显式初始化为0.0
double revenue = 0.0; // 总收入
};
//add
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
//read
std::istream& read(std::istream &is, Sales_data &item)
{
is >> item.bookNo >> item.units_sold >> item.sellingprice >> item.saleprice;
return is;
}
//print
std::ostream& print(std::ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " " << item.sellingprice << " " << item.saleprice
<< " " << item.discount;
return os;
}
// used in chapter 10
inline bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_data operator + (const Sales_data&, const Sales_data&);
inline bool operator == (const Sales_data &lhs, const Sales_data &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool operator != (const Sales_data &lhs, const Sales_data &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_data& Sales_data::operator += (const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_data operator + (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
//接收4个参数分别为:ISBN,销售量,原价,实际售价
std::istream& operator >> (std::istream& in, Sales_data& s)
{
in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * s.saleprice;
else
s = Sales_data(); // input failed: reset object to default state
return in;
}
std::ostream& operator << (std::ostream& out, const Sales_data& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_data::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
#endif // SALES_DATA_7_7_H
#include <iostream>
#include "Sales_data_7_7.h"
using namespace std;
int main()
{
cout << "请输入交易记录(ISBN),销售量,原价,实际售价:" << endl;
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; //total现在表示下一本书的销售额
}
}
print(cout, total);
cout << endl; //打印最后本书的结果
}
else
{
//没有输入! 警告读者
cerr << "No data?!" << endl;
return -1; //表示失败
}
return 0;
}
运行结果:
练习9:对于7.1.2节(第233页)练习中的代码,添加读取和打印Person对象的操作。
【出题思路】
仿照Sales_data类,为Person类添加相应的read和print函数。
【解答】
满足题意的read和print函数如下所示:
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
string getName() const {return strName; }
string getAddress() const {return strAddress; }
public:
string strName;
string strAddress;
};
std::istream &read(std::istream &is, Person &per)
{
is >> per.strName >> per.strAddress;
return is;
}
std::ostream &print(std::ostream &os, const Person &per)
{
os << "name: " << per.getName() << " address: " << per.getAddress() << endl;
return os;
}
int main()
{
Person person;
if(read(cin, person))
{
print(cout, person);
}
else
{
//没有输入! 警告读者
cerr << "No data?!" << endl;
return -1;//表示失败
}
return 0;
}
运行结果:
练习11:在你的Sales_data类中添加构造函数,然后编写一段程序令其用到每个构造函数。
【出题思路】
在不同情况下,初始化Sales_data对象所需的数据有所不同,分别为其设计构造函数,同时也利用C++11新标准提供的=default定义默认构造函数。
【解答】
满足题意的4个构造函数分别如下所示:
#ifndef SALES_DATA_7_11_H
#define SALES_DATA_7_11_H
#include <iostream>
#include <string>
using namespace std;
class Sales_data
{
friend std::istream& operator >> (std::istream&, Sales_data&);
friend std::ostream& operator << (std::ostream&, const Sales_data&);
public:
Sales_data() = default;
Sales_data(const std::string &book): bookNo(book) {}
Sales_data(const std::string &book, const unsigned num,
const double sellp, const double salep);
Sales_data(std::istream &is);
double avg_price() const;
std::string isbn() const { return bookNo; }
private:
std::string bookNo; //书籍编号,隐式初始化为空串
unsigned units_sold = 0; //销售量,显示初始化为0
double sellingprice = 0.0; //原始价格,显示初始化为0.0
double saleprice = 0.0; //实售价格,显式初始化为0.0
double discount = 0.0; //折扣,显式初始化为0.0
double revenue = 0.0; // 总收入
};
//接收4个参数分别为:ISBN,销售量,原价,实际售价
std::istream& operator >> (std::istream& in, Sales_data& s)
{
in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * s.saleprice;
else
s = Sales_data(); // input failed: reset object to default state
return in;
}
std::ostream& operator << (std::ostream& out, const Sales_data& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_data::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
Sales_data::Sales_data(const std::string &book, const unsigned num,
const double sellp, const double salep)
{
bookNo = book;
units_sold = num;
sellingprice = sellp;
if(sellingprice != 0)
discount = saleprice / sellingprice;
}
Sales_data::Sales_data(std::istream &is)
{
is >> *this;
}
#endif // SALES_DATA_7_11_H
#include <iostream>
#include "Sales_data_7_11.h"
#include <string>
using namespace std;
int main()
{
cout << "构造函数调用:" << endl;
Sales_data data1;
Sales_data data2("978-7-121-15535-2");
Sales_data data3("978-7-121-15535-2", 100, 128, 109);
Sales_data data4(cin);
cout << "书籍的销售情况是:" << endl;
cout << "data1:" << data1 << endl;
cout << "data2:" << data2 << endl;
cout << "data3:" << data3 << endl;
cout << "data4:" << data4 << endl;
return 0;
}
运行结果:
练习12:把只接受一个istream作为能数的构造函数定义移到类的内部。
【出题思路】
构造函数既可以定义在类的外部,也可以定义在类的内部。
【解答】
按照题目要求,把只接受一个istream作为参数的构造函数定义到类的内部之后,类的形式如下所示:
#include <iostream>
#include <string>
using namespace std;
class Sales_data
{
friend std::istream& operator >> (std::istream&, Sales_data&);
friend std::ostream& operator << (std::ostream&, const Sales_data&);
public:
Sales_data() = default;
Sales_data(const std::string &book): bookNo(book) {}
Sales_data(const std::string &book, const unsigned num,
const double sellp, const double salep);
Sales_data(std::istream &is) {is >> *this;};//构造函数实现定义到类的类部
double avg_price() const;
std::string isbn() const { return bookNo; }
private:
std::string bookNo; //书籍编号,隐式初始化为空串
unsigned units_sold = 0; //销售量,显示初始化为0
double sellingprice = 0.0; //原始价格,显示初始化为0.0
double saleprice = 0.0; //实售价格,显式初始化为0.0
double discount = 0.0; //折扣,显式初始化为0.0
double revenue = 0.0; // 总收入
};
练习13:使用istream构造函数重写第229页的程序。
【出题思路】
原来的程序使用Sales_data类的默认构造函数,本题改为使用接受istream的构造函数。
【解答】
改写后的程序如下所示:
#ifndef SALES_DATA_7_13_H
#define SALES_DATA_7_13_H
#include <iostream>
#include <string>
class Sales_data
{
friend std::istream& operator >> (std::istream&, Sales_data&);
friend std::ostream& operator << (std::ostream&, const Sales_data&);
friend bool operator < (const Sales_data&, const Sales_data&);
friend bool operator == (const Sales_data&, const Sales_data&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
Sales_data() = default;
Sales_data(const std::string &book): bookNo(book) { }
Sales_data(std::istream &is);
Sales_data(const std::string &book, const unsigned num, const double sellp, const double salep);
//定义公有函数成员
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
Sales_data& operator += (const Sales_data&);
// operations on Sales_item objects
double avg_price() const;
std::string isbn() const { return bookNo; }
//combine函数用于把两个ISBN相同的销售记录合并在一起
Sales_data& combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold; //累加书籍的销售量
saleprice = (rhs.saleprice * rhs.units_sold + saleprice * units_sold)
/ (rhs.units_sold + units_sold); //重新计算实现销售价格
discount = saleprice / sellingprice; //重新计算实际折扣
revenue += rhs.revenue; //总销售额
return *this; //返回合并后的结果
}
// 定义公有数据成员,外部普通函数要调用
public:
std::string bookNo; // 书籍编号,隐式初始化为空串
unsigned units_sold = 0; // 销售量,显式初始化为0
double sellingprice = 0.0; // 原始价格,显式初始化为0.0
double saleprice = 0.0; // 实售价格,显式初始化为0.0
double discount = 0.0; // 折扣,显式初始化为0.0
double revenue = 0.0; // 总收入
};
Sales_data::Sales_data(const std::string &book, const unsigned num, const double sellp, const double salep)
{
bookNo = book;
units_sold = num;
sellingprice = sellp;
saleprice = salep;
if(0 != sellingprice)
{
discount = saleprice / sellingprice; //计算实际折扣
}
}
Sales_data::Sales_data(std::istream &is)
{
is >> *this;
}
//add
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
//read
std::istream& read(std::istream &is, Sales_data &item)
{
is >> item.bookNo >> item.units_sold >> item.sellingprice >> item.saleprice;
return is;
}
//print
std::ostream& print(std::ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " " << item.sellingprice << " " << item.saleprice
<< " " << item.discount;
return os;
}
// used in chapter 10
inline bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_data operator + (const Sales_data&, const Sales_data&);
inline bool operator == (const Sales_data &lhs, const Sales_data &rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool operator != (const Sales_data &lhs, const Sales_data &rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_data& Sales_data::operator += (const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_data operator + (const Sales_data& lhs, const Sales_data& rhs)
{
Sales_data ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
//接收4个参数分别为:ISBN,销售量,原价,实际售价
std::istream& operator >> (std::istream& in, Sales_data& s)
{
in >> s.bookNo >> s.units_sold >> s.sellingprice >> s.saleprice;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * s.saleprice;
else
s = Sales_data(); // input failed: reset object to default state
return in;
}
std::ostream& operator << (std::ostream& out, const Sales_data& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_data::avg_price() const
{
if (units_sold)
return revenue / units_sold;
else
return 0;
}
#endif // SALES_DATA_7_13_H
#include <iostream>
#include "Sales_data_7_13.h"
using namespace std;
int main()
{
cout << "请输入交易记录(ISBN),销售量,原价,实际售价:" << endl;
Sales_data total(cin); //保存当前求和结果的变量
if(cin)
{ //读入第一笔交易记录
Sales_data trans(cin); //保存和的变量
do //保存下一条交易数据的变量
{
//读放剩余的交易
if(total.isbn() == trans.isbn()) //检查isbn
{
total.combine(trans); //更新变量total当前的值
}
else
{
print(cout, total) << endl; //输出结果
total = trans; //处理下一本书
}
}while(read(cin, trans));
print(cout, total) << endl; //输出最后一条交易
}
else
{
cerr << "No data?!" << endl; //没有输入! 警告读者
return -1; //表示失败
}
return 0;
}
运行结果:
Sales_data(const std::string &book)
:bookNo(book), units_sold(0), sellingprice(0), saleprice(0), discount(0) { }
练习7.15:为你的Person类添加正确的构造函数。
【出题思路】
仿照Sales_data类,为Person类添加默认构造函数、接受两个实参的构造函数和从标准输入流中读取数据的构造函数。
【解答】
添加上述3个构造函数之后,新的Person类如下所示:
#include <iostream>
#include <string>
using namespace std;
class Person
{
friend std::istream& operator >> (std::istream&, Person&);
private:
string strName; //姓名
string strAddress; //地址
public:
Person() = default;
Person(const string &name, const string &add)
{
strName = name;
strAddress = add;
}
Person(std::istream &input) { input >> *this; }
string getName() const
{
return strName; //返回姓名
}
string getAddress() const
{
return strAddress; //返回地址
}
};
std::istream& operator >> (std::istream& in, Person& per)
{
in >> per.strName >> per.strAddress;
return in;
}
int main()
{
cout << "请输入姓名和地址:" << endl;
Person person(cin);
cout << "name: " << person.getName() << " address: " << person.getAddress() << endl;
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/442a34f56ac19fcb2ba50fb2d24063c0.png)