Exercise 7.1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
struct Sales_data
{
  string bookNo;
  unsigned units_sold = 0;
  double revenue = 0.0;
};
int main()
{
  Sales_data item1, item2;
  if(cin >> item1.bookNo >> item1.units_sold >> item1.revenue)
    {
      while(cin >> item2.bookNo >> item2.units_sold >> item2.revenue)
      {
	// don't worry, Sales_item item is initialized when created
	if(item1.bookNo == item2.bookNo)
	  {
	    item1.units_sold += item2.units_sold;
	    item1.revenue += item2.revenue;
	  }
	else
	  {
	    cout << item1.bookNo << " " << item1.units_sold << " "
		 << item1.revenue << endl;
	    item1 = item2;
	  }
      }
      // the last one
      cout << item1.bookNo << " " << item1.units_sold << " "
	 << item1.revenue << endl;
    }
  else
    {
      cerr << "No data?" << endl;
      return -1;
    }
  return 0;
}

Exercise 7.2

1
2
// See Sales_data.h

Sales_data.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef SALES_DATA_H
#define SALES_DATA_H
struct Sales_data;
istream &read(istream &is, Sales_data &item);
ostream &print(ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &item1, const Sales_data &item2);
struct Sales_data {
  friend istream &read(istream &, Sales_data &);
  friend ostream &print(ostream &, const Sales_data &);
  friend Sales_data add(const Sales_data &item1, const Sales_data &item2);
public:
  // Sales_data(): bookNo(""), units_sold(0), revenue(0) {}
  // Exercise 7.14 above has misleading due to the CN version.
  // It's ok to use the in-class initializer values.
Sales_data(): Sales_data("", 0, 0)
  {cout << " Default";};
Sales_data(const string &s): Sales_data(s, 0, 0)
  {cout << " With string argument";}
Sales_data(const string &s, unsigned n, double p):
  bookNo(s), units_sold(n), revenue(p*n)
  {cout << " With three arguments";}
Sales_data(istream &is): Sales_data()
  {cout << " With istream argument"; read(is, *this);}
  string isbn() const {return bookNo;}
  Sales_data& combine(const Sales_data&);
private:
  double avg_price() const;
  string bookNo;
  unsigned units_sold = 0;
  double revenue = 0.0;
};
#endif

Exercise 7.3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int main()
{
  Sales_data item1, item2;
  if(cin >> item1.bookNo >> item1.units_sold >> item1.revenue)
    {
      while(cin >> item2.bookNo >> item2.units_sold >> item2.revenue)
      {
	// don't worry, Sales_item item is initialized when created
	if(item1.isbn() == item2.isbn())
	  item1.combine(item2);
	else
	  {
	    cout << item1.isbn() << " " << item1.units_sold << " " << item1.revenue << endl;
	    item1 = item2;
	  }
      }
      // the last one
      cout << item1.isbn() << " " << item1.units_sold << " " << item1.revenue << endl;
    }
  else
    {
      cerr << "No data?" << std::endl;
      return -1;
    }
  return 0;
}

Exercise 7.4

1
2
// See Person.h

Person.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef PERSON_H
#define PERSON_H
struct Person {
  friend istream &read(istream &, Person &);
public:				/* These member functions and constructors are nececssary to be accessibile to users, they're interfaces of this class */
  string get_name() const {return name;}
  string get_address() const {return address;}
  /*
   * shuld be const member functions
   * which makes them more flexible
   * for both functions just return but not modify the member of a object
   * and const object of Person type could also be able to call this kind of functions
   */
  Person() = default;
explicit Person(const string &s): name(s) {}
Person(const string &s1, const string &s2):
  name(s1), address(s2) {}
  Person(istream &);
private:			/* data members of class shoud not be accessed directly */
  string name;
  string address;
};
istream &read(istream &is, Person &p);
ostream &print(ostream &os, Person &p);
#endif

Exercise 7.5

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#ifndef PERSON_H
#define PERSON_H
struct Person {
  string get_name() const {return name;}
  string get_address() const {return address;}
  /*
   * shuld be const member functions
   * which makes them more flexible
   * for both functions just return but not modify the member of a object
   * and const object of Person type could also be able to call this kind of functions
   */
  string name;
  string address;
};
#endif

Exercise 7.6

1
2
// See Sales_data.h and Sales_data.cpp

Sales_data.h

Sales_data.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
  units_sold += rhs.units_sold;
  revenue += rhs.revenue;
  return *this;
}
inline double Sales_data::avg_price() const
{
  if(units_sold)
    return revenue/units_sold;
  else
    return 0;
}
istream &read(istream &is, Sales_data &item)
{
  double price;
  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 << " " << item.avg_price();
  return os;
}
Sales_data add(const Sales_data &item1, const Sales_data &item2)
{
  Sales_data result = item1;
  return result.combine(item2);
}

Exercise 7.7

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int main()
{
  Sales_data item1, item2;
  if(read(cin, item1))
    {
      while(read(cin, item2))
      {
	// don't worry, Sales_item item is initialized when created
	if(item1.isbn() == item2.isbn())
	  item1.combine(item2);
	else
	  {
	    print(cout, item1) << endl;
	    item1 = item2;
	  }
      }
      // the last one
      print(cout, item1) << endl;
    }
  else
    {
      std::cerr << "No data?" << std::endl;
      return -1;
    }
  return 0;
}

Exercise 7.8

1
2
3
// the Sales_data object which initializes the corressponding parameter would be modified in read function
// while in print function there is no need to modify.

Exercise 7.9

1
2
// See Person.h and Person.cpp

Person.h

Person.cpp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
istream &read(istream &is, Person &p)
{
  is >> p.name >> p.address;
  return is;
}
ostream &print(ostream &os, Person &p)
{
  os << p.get_name() << " " << p.get_address();
  return os;
}
Person::Person(istream &is)
{
  read(is, *this);
}

Exercise 7.10

1
2
3
4
// if(read(read(cin. data), data2))
// if statement reads two Sales_data object at one time
// check istream object cin's status, if encounting a false input or an EOF, that condition statement evaluated value is false.

Exercise 7.11

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int main()
{
  Sales_data item1;		// using default constrcutor
  string number = "1234567";
  Sales_data item2(number);
  unsigned u = 6;
  double p = 5.6;
  Sales_data item3(number, u, p);
  Sales_data item4(cin);
}

Exercise 7.12

1
2
// See Sales_data.h and Sales_data.cpp

Sales_data.cpp

Sales_data.h

Exercise 7.13

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main()
{
  Sales_data total(cin);
  if(cin)
    {
      Sales_data trans;
      while(read(cin, trans))	// statement like this is more suitable
      {
	if(total.isbn() == trans.isbn())
	  total.combine(trans);
	else
	  {
	    print(cout, total) << endl;
	    total = trans;
	  }
      }
      print(cout, total) << endl;
    }
  else
    {
      cerr << "No data?!" << endl;
    }
}

Exercise 7.14

1
2
// See Sales_data.h and Sales_data.cpp

Sales_data.cpp

Sales_data.h

Exercise 7.15

1
2
// See Person.h and Person.cpp

Person.cpp

Person.h

Exercise 7.16

1
2
3
4
// amount of access specifiers is not limited
// position of access specifiers should at the top level inside a class or a struct.
// constructors and some member functions should be defined after public access specifier, while data members and some member functions as helper functions should be defined after private access specifier.

Exercise 7.17

1
2
3
4
// Of course there is a diference between keyword class and keyword struct
// Using keyword struct means that members defined before the first access spedifier is public;
// Using keyword class means that members defined before the first access spedifier is private

Exercise 7.18

1
2
3
// A separation of implementation from interface
// Encapsulation hides the design details of class, keeps data members from directly modified, sets up a access rule and provides more safety in programming with calss.

Exercise 7.19

1
2
// See Person.h and Person.cpp

Person.cpp

Person.h

Exercise 7.20

1
2
3
// friend is helpful in such a situation: functions as part of interfaces of class but are not member functions, for that data members of class are not accessibile to them, while whith friend declearations inside class, these functions are able to get data members directly.
// The disadvantage is the possibile abusing of this syntax, then functions which are not part of interfaces could also touch data members of class.

Exercise 7.21

1
2
// See Sales_data.h and Sales_data.cpp

Sales_data.cpp

Sales_data.h

Exercise 7.22

1
2
// See Person.h and Person.cpp

Person.cpp

Person.h

Exercise 7.23

1
2
// See Screen.h

Screen.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#ifndef SCREEN_H
#define SCREEN_H
class Screen;
class Window_mgr
{
public:
  using ScreenIndex = vector<Screen>::size_type;
  void clear(ScreenIndex);
private:
  vector<Screen> screens;
};
class Screen
{
  friend void Window_mgr::clear(ScreenIndex);
public:
  using pos = string::size_type;
  Screen() = default;
  Screen(pos ht, pos wd): height(ht), width(wd),
			contents(ht * wd, ' ') {}
  Screen(pos ht, pos wd, char c): height(ht), width(wd),
				contents(ht * wd, c) {}
  char get() const {return contents[cursor];}
  char get(pos, pos) const;
  pos size() const;		/* Exercise 7.33 */
  Screen &move(pos, pos);
  Screen &set(char);
  Screen &set(pos, pos, char);
  Screen &display(ostream &os)
  {do_display(os); return *this;}
  const Screen &display(ostream &os) const
  {do_display(os); return *this;}
private:
  pos cursor = 0;
  pos height = 0, width = 0;
  string contents;
  void do_display(ostream &os) const {os << contents;}
};
inline Screen &Screen::move(pos r, pos c)
{
  pos row = r * width;
  cursor = row + c;
  return *this;
}
inline char Screen::get(pos r, pos c) const
{
  pos row = r * width;
  return contents[row + c];
}
inline Screen::pos Screen::size() const
{
  return height * width;
}
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;
}
inline void Window_mgr::clear(ScreenIndex i)
{
  Screen &s = screens[i];
  s.contents = string(s.height * s.width, ' ');
}
#endif

Exercise 7.24

1
2
// See Screen.h

Screen.h

Exercise 7.25

1
2
// Class screen could safely rely on the default copy and assignment operations which generated by compiler, for that class screen is constructed on the base of vector object and string object(both types support robust copy, assignment and destroy operations, when there is a need to do so to screen object, vector object and string object would have corresponding operations underneath) and built-in types.

Exercise 7.26

1
2
// See Sales_data.h

Sales_data.h

Exercise 7.27

1
2
3
4
5
6
7
8
9
int main()
{
  Screen myScreen(5, 5, 'X');
  myScreen.move(4, 0).set('#').display(cout);
  cout << "\n";
  myScreen.display(cout);
  cout << "\n";
}

Exercise 7.28

1
2
3
// XXXXXXXXXXXXXXXXXXXX#XXXX
// XXXXXXXXXXXXXXXXXXXXXXXXX

Exercise 7.29

1
2
// OK then.

Exercise 7.30

1
2
3
4
5
// Explicitly using pointer this
// Advantages: easy to understand, for the parameters and statements in member functions would not hide 'this' pointer
// Disadvantages: bring in redundant programming work, mistakes would be made in such detailed work
// So let compiler arrange the pointer this implicitly

Exercise 7.31

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class X;
class Y;
class X
{
  Y *py = nullptr;		// p47
};
class Y
{
  X x;
};

Exercise 7.32

1
2
// See Screen.h

Screen.h

Exercise 7.33

1
2
// See Screen.h

Screen.h

Exercise 7.34

1
2
3
4
// If put type membe pos's typedef statement at the end of class Screen,
// the declarations of private data member cursor, height and width would fail,
// for that the pos type specifier is not found in all scopes berfor these declarations.

Exercise 7.35

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
typedef string Type;
Type initVal();			// Type declared before
class Exercise
{
public:
  typedef double Type;
  Type setVal(Type);		// Type declared in class
  Type initVal();		// same
private:
  int val;
};
Exercise::Type Exercise::setVal(Type parm) // type member Type of class Exercise
{
  val = parm + initVal();
  return val;
}
// and Exercise::initVal() should be defined

Exercise 7.36

1
2
3
4
5
6
struct X
{
  X(int i, int j): base(i), rem(base % j) {}
  int base, rem;
};

Exercise 7.37

1
2
3
4
5
6
7
Sales_data first_item(cin);	// Sales_data(istream &is) {read(is, *this);} data members depend on cin
int main()
{
  Sales_data next;		// Sales_data(string s = ""): bookNo(s) {} bookNo "", units_sold 0, revenue 0.0
  Sales_data last("9-999-99999-9"); // Sales_data(string s = ""): bookNo(s) {} bookNo "9-999-99999-9", units_sold 0, revenue 0.0
}

Exercise 7.38

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Sales_data;
istream &read(istream &, Sales_data &);
class Sales_data
{
  friend istream &read(istream &, Sales_data &);
public:
  Sales_data(istream &is = cin) {read(is, *this);}
private:
  string bookNo;
  int units_sold = 0;
  double revenue = 0.0;
};
istream &read(istream &is, Sales_data &item)
{
  double price;
  is >> item.bookNo >> item.units_sold >> price;
  item.revenue = price * item.units_sold;
  return is;
}

Exercise 7.39

1
2
3
// Illegal
// it will introduce a ambiguous-like call, when there is a statememt trying to define a object of Sales_data class type but without arguments, compiler does not know which one is better to be called.

Exercise 7.40

1
2
// See Employee.h

Employee.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Employee;
istream &read(istream &is, Employee &e);
class Employee
{
  friend istream &read(istream &is, Employee &e);
  using str = string;
  str name;
  str address;
  str contact;
  str department;
  str job;
 public:
 Employee(): Employee("") {};
 Employee(str n, str a = "", str c = "", str d = "", str j = ""):
  name(n), address(a), contact(c),  department(d), job(j) {}
  // Exercise 7.40: An Employee object better has a name, left could be filled later
  // And compiler could be able to distinguish above two constructors
 Employee(istream &is): Employee() {read(is, *this);}
};
istream &read(istream &is, Employee &e)
{
  is >> e.name >> e.address >> e.contact
     >> e.department >> e.job;
  return is;
}

Exercise 7.41

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int main()
{
  Sales_data item1;
  cout << "\n\n";
  Sales_data item2("12345");
  cout << "\n\n";
  Sales_data item3("54321", 12, 23.00);
  cout << "\n\n";
  Sales_data item4(cin);
};

Exercise 7.42

1
2
// See Employee.h

Employee.h

Exercise 7.43

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class NoDefault
{
  int im;
public:
  NoDefault(int i): im(i) {}
};
class C
{
  NoDefault n_member;
public:
  C(int i): n_member(NoDefault(i)) {}
  C(): C(0) {}
};

Exercise 7.44

1
2
3
4
5
6
// Based on class type NoDefault defined in exercise 7.44
// vector<NoDefault> vec(10) is illegal
// for that class type NoDefault has a constructor with one argument, so for itself ther is no default constructor
// in this statement only the amount of vector is given, so the element of vector must be initialized by this class' default constructor
// for there is no default constructor, illegal

Exercise 7.45

1
2
3
// Legal
// for there is a default constructor defined inside class C

Exercise 7.46

1
2
3
4
5
// a: false, if no constructor is given, the compiler generates one
// b: false, a constructor provides default arguments for all its paramenters also defines a default constructor
// c: false, define meaningful, troubles will be introduced if it has no default constructor
// d: false, if ther is another constructor explicitly defined, compiler would not generate a default constructor for this class

Exercise 7.47

1
2
3
4
// It should not be explicit
// a String object able to be explicitly transformmed to Sales_data object is programmer friendly, which saves a lot of work
// while sometimes this feature will be abused, String object which is not isbn would be explicitly transformmed to Sales_data object without a second thought

Exercise 7.48

1
2
3
4
5
6
7
// not explicit
// string null_isbn("9-999-99999-9"); direct initialization of string object
// Sales_data item1(null_isbn); direct initialization of Sales_data object
// Sales_data item2("9-999-99999-9"); direct initialization of Sales_data object
// explicit
// no difference from before

Exercise 7.49

1
2
3
4
5
6
7
8
9
// a: Sales_data &combine(Sales_data);
// b: Sales_data &combine(Sales_data &);
// c: Sales_data &combine(const Sales_data &) const;
// i: Sales_data, s: string
// i.combine(s)
// a: implicitly using s to construct a Sales_data temp object, which is passed as the argument of combine, then it is used to initialize the parameter(copy)
// b: illegal, the parameter is a reference which could not be binded to a temp object
// c: illegal, const member function called by const object should not modify the calling object.

Exercise 7.50

1
2
3
// See Person.h
// Not every string is a man's name, so implicitly transform is not allowed.

Person.h

Exercise 7.51

1
2
3
// C type string literal explicitly transformmed to string object is easy to understand and acceptable
// For vector is a class template, external class information must be provided to instantiate a vector with certain class, such class may not has a default constructor, so only giving the amount of vector maybe not enough, see section 7.5.3

Exercise 7.52

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
struct Sales_data		// using aggregate class
{
  string bookNo;
  unsigned units_sold;
  double revenue;
};
int main()
{
  Sales_data item = {"978-0590353403", 25, 15.99};
  // legal
  // item.bookNo = "978-0590353403"
  // item.units_sold = 25
  // item.revenue = 15.99
}

Exercise 7.53

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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() const { 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;
};

Exercise 7.54

1
2
3
// No
// In C++11: these member functions whose name start with 'set_' will modify data members in function body, against to the requirement of constexpr function which should be implicitly const member function

Exercise 7.55

1
2
3
4
// No
// data member s in Data is of strin type, which is not literal type
// so aggregate class Data is not constexpr class

Exercise 7.56

1
2
3
4
// Static member is not contained in objects of class, it is directly related to class itself.
// objects of same class do not store a common data, and if the data is changed, they can use the new value.
// Static data member' class type could be imcomplete; could be passed as a default argument of a member function in a class.

Exercise 7.57

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Account
{
public:
  void calculate() {amount += amount * interestRate;}
  static double rate() {return interestRate;}
  static void rate(double);
private:
  string owner;
  double amount;
  static double interestRate;
  static double initRate();
};

Exercise 7.58

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Example
{
public:
  static double rate;		// generally static data member should defined outside of class
  static const int vecSize = 20;
  static vector<double> vec;	// same reason as before
};
double Example::rate = 6.5;
vector<double> Example::vec(vecSize);