diff --git a/c++ note/chp7/chp7answers.md b/c++ note/chp7/chp7answers.md index 35b747f..44b18ba 100644 --- a/c++ note/chp7/chp7answers.md +++ b/c++ note/chp7/chp7answers.md @@ -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) diff --git a/c++ note/chp7/exercise7_11.cpp b/c++ note/chp7/exercise7_11.cpp new file mode 100644 index 0000000..dfacb96 --- /dev/null +++ b/c++ note/chp7/exercise7_11.cpp @@ -0,0 +1,43 @@ +//test constructors +#include "exercise7_11.h" +#include + +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; +} diff --git a/c++ note/chp7/exercise7_11.h b/c++ note/chp7/exercise7_11.h new file mode 100644 index 0000000..87723a3 --- /dev/null +++ b/c++ note/chp7/exercise7_11.h @@ -0,0 +1,61 @@ +#ifndef EXERCISE7_11_H_ +#define EXERCISE7_11_H_ + +#include +#include + +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 diff --git a/c++ note/chp7/exercise7_15.cpp b/c++ note/chp7/exercise7_15.cpp new file mode 100644 index 0000000..da121c7 --- /dev/null +++ b/c++ note/chp7/exercise7_15.cpp @@ -0,0 +1,28 @@ +// test construtors +#include "exercise7_15.h" +#include + +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; +} diff --git a/c++ note/chp7/exercise7_15.h b/c++ note/chp7/exercise7_15.h new file mode 100644 index 0000000..091b83f --- /dev/null +++ b/c++ note/chp7/exercise7_15.h @@ -0,0 +1,38 @@ +#ifndef EXERCISE7_15_H_ +#define EXERCISE7_15_H_ + +#include +#include +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