update to Exercise 7.15.

This commit is contained in:
Shine wOng
2019-05-22 14:40:18 +08:00
parent 7e56b42089
commit 485e9f44cb
5 changed files with 260 additions and 1 deletions

View File

@@ -65,7 +65,7 @@ Because in `read`, the `Sales_data` object will be modified. While in `print`, t
> Exercise 7.9: Add operations to `read` and `print` Person objects to the code you wrote for the exercises in § 7.1.2 (p. 260).
```
```cpp
istream& read(istream &is, Person &person){
is >> person.name >> person.address;
return is;
@@ -81,3 +81,92 @@ ostream& print(ostream &os, Person const &person){
`if (read(read(cin, data1), data2))`
Take in two objects(data1 and data2) at the same time, and step into the `if` block only when both objects are valid.
> Exercise 7.11: Add constructors to your Sales_data class and write a program to use each of the constructors.
[exercise7_11.h](exercise7_11.h)
[exercise7_11.cpp](exercise7_11.cpp)
> Exercise 7.12: Move the definition of the Sales_data constructor that takes an istream into the body of the Sales_data class.
```cpp
struct Sales_data {
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
//constructors
Sales_data() = default;
Sales_data(istream &is){
double price;
is << bookNo << units_sold << price;
revenue = price * units_sold;
}
Sales_data(string isbn) : bookNo(isbn) {};
Sales_data(string isbn, unsigned n, double price) : bookNo(isbn), units_sold(n), revenue(n * price) {};
string isbn() const { return bookNo; }
double avg_price() const { return revenue / units_sold; }
Sales_data& combine(Sales_data const &data); //behave same as the `+=` operator, thus return a left-value
};
```
> Exercise 7.13: Rewrite the program from page 255 to use the istream constructor.
```cpp
int main(){
Sales_data total(cin); // variable to hold the running sum
if (cin) { // read the first transaction
Sales_data trans(cin); // variable to hold data for the next transaction
while (cin) { // read the remaining transactions
if (total.isbn() == trans.isbn()) // check the isbns
total.combine(trans); // update the running total
else {
print(cout, total) << endl; // print the results
total = trans; // process the next book
}
trans = Sales_data(cin);
}
print(cout, total) << endl; // print the last transaction
}
else { // there was no input
cerr << "No data?!" << endl; // notify the user
}
system("pause");
return 0;
}
```
This can be weird, for the `cin` operation is seperated from the `if-condition`.
> Exercise 7.14: Write a version of the default constructor that explicitly initializes the members to the values we have provided as in-class initializers.
```cpp
struct Sales_data {
string bookNo;
unsigned units_sold;
double revenue;
//constructors
Sales_data(){units_sold = 0, revenue = 0.0;}
Sales_data(istream &is){
double price;
is << bookNo << units_sold << price;
revenue = price * units_sold;
}
Sales_data(string isbn) : bookNo(isbn) {};
Sales_data(string isbn, unsigned n, double price) : bookNo(isbn), units_sold(n), revenue(n * price) {};
string isbn() const { return bookNo; }
double avg_price() const { return revenue / units_sold; }
Sales_data& combine(Sales_data const &data); //behave same as the `+=` operator, thus return a left-value
};
```
But there's a drawback in this manner. For example, in constructor3, `Sales_data(string isbn)`, we also have to explicitly initializes all the members, which causes redundance.
> Exercise 7.15: Add appropriate constructors to your Person class.
[exercise7_15.h](exercise7_15.h)
[exercise7_15.cpp](exercise7_15.cpp)

View File

@@ -0,0 +1,43 @@
//test constructors
#include "exercise7_11.h"
#include <cassert>
using std::cin;
using std::cout;
using std::cerr;
void test_constructor();
int main(){
test_constructor();
system("pause");
return 0;
}
void test_constructor(){
//test default constructor
Sales_data data1;
assert(data1.units_sold == 0);
assert(data1.revenue == 0.0);
//test constructor2
Sales_data data2(cin); // cin >> 123456789 2 20.5
assert(data2.bookNo == "123456789");
assert(data2.revenue == 41.0);
assert(data2.units_sold == 2);
//test constructor3
Sales_data data3("123456789");
assert(data3.bookNo == "123456789");
assert(data3.revenue == 0.0);
assert(data3.units_sold == 0);
//test constructor4
Sales_data data4("123456789", 2, 20.5);
assert(data4.bookNo == "123456789");
assert(data4.revenue == 41.0);
assert(data4.units_sold == 2);
cout << "All tests passed." << endl;
}

View File

@@ -0,0 +1,61 @@
#ifndef EXERCISE7_11_H_
#define EXERCISE7_11_H_
#include <iostream>
#include <string>
using std::istream;
using std::ostream;
using std::endl;
using std::string;
struct Sales_data {
string bookNo;
unsigned units_sold;
double revenue;
//constructors
Sales_data() { units_sold = 0, revenue = 0.0; }
Sales_data(istream &is);
Sales_data(string isbn) : bookNo(isbn) {};
Sales_data(string isbn, unsigned n, double price) : bookNo(isbn), units_sold(n), revenue(n * price) {};
string isbn() const { return bookNo; }
double avg_price() const { return revenue / units_sold; }
Sales_data& combine(Sales_data const &data); //behave same as the `+=` operator, thus return a left-value
};
//constructors
Sales_data::Sales_data(istream &is){
double price;
is >> bookNo >> units_sold >> price;
revenue = price * units_sold;
}
Sales_data& Sales_data::combine(Sales_data const &data) {
units_sold += data.units_sold;
revenue += data.revenue;
return *this;
}
Sales_data add(Sales_data const &one, Sales_data const &two) {
Sales_data res = one;
return res.combine(two);
}
istream& read(istream &is, Sales_data &data) {
is >> data.bookNo;
is >> data.units_sold;
is >> data.revenue;
return is;
}
ostream& print(ostream &os, Sales_data const data) {
os << "book number: " << data.bookNo << endl;
os << "units sold: " << data.units_sold << endl;
os << "total revenue: " << data.revenue << endl;
os << "averge price: " << data.avg_price(); // no endl at the end
return os;
}
#endif

View File

@@ -0,0 +1,28 @@
// test construtors
#include "exercise7_15.h"
#include <cassert>
using std::cout;
using std::cin;
using std::endl;
int main(){
//test constructorss
Person person1;
// here we see non-builtin type(such as string) would not have undefined value
assert(person1.getAddr() == string());
assert(person1.getName() == string());
Person person2("shine", "shanghai");
// and string can directly be compare with literal character string
assert(person2.getName() == "shine");
assert(person2.getAddr() == string("shanghai"));
Person person3(cin); // cin >> shine >> shanghai;
assert(person2.getName() == "shine");
assert(person2.getAddr() == string("shanghai"));
cout << "All tests passed." << endl;
system("pause");
return 0;
}

View File

@@ -0,0 +1,38 @@
#ifndef EXERCISE7_15_H_
#define EXERCISE7_15_H_
#include <string>
#include <iostream>
using std::string;
using std::istream;
using std::ostream;
struct Person;
istream& read(istream &is, Person &person);
ostream& print(ostream &os, Person const &person);
struct Person {
string name;
string address;
//construtors
Person() = default;
Person(istream& is) { read(is, *this); }
Person(string name, string address) : name(name), address(address) {};
string getName() const { return name; }
string getAddr() const { return address; }
};
istream& read(istream &is, Person &person) {
is >> person.name >> person.address;
return is;
}
ostream& print(ostream &os, Person const &person) {
os << person.name << ' ' << person.address;
return os;
}
#endif