Skip to content

Latest commit

 

History

History

ch07

Exercise 7.8

Define read's Sales_data parameter as plain reference since it's intended to change the revenue's value.

Define print's Sales_data parameter as a reference to const since it isn't intended to change any member's value of this object.

Exercise 7.10

if(read(read(cin, data1), data2))

we can try to divide it like that:

std::istream &firstStep = read(cin, data1);
sdt::istream &secondStep = read(firstStep, data2);
if (secondStep)

the condition of the if statement would read two Sales_data object at one time.

Exercise 7.11 Header|CPP

Exercise 7.14

Sales_data() : units_sold(0) , revenue(0){}

Exercise 7.16

There are no restrictions on how often an access specifier may appear.The specified access level remains in effect until the next access specifier or the end of the class body.

The members which are accessible to all parts of the program should define after a public specifier.

The members which are accessible to the member functions of the class but are not accessible to code that uses the class should define after a private specifier.

Exercise 7.17

The only difference between using class and using struct to define a class is the default access level. (class : private, struct : public)

Exercise 7.18

encapsulation is the separation of implementation from interface. It hides the implementation details of a type. (In C++, encapsulation is enforced by putting the implementation in the private part of a class)


Important advantages:

  • User code cannot inadvertently corrupt the state of an encapsulation object.
  • The implementation of an encapsulated class can change over time without requiring changes in user-level code.

Exercise 7.19

public include: constructors, getName(), getAddress(). private include: name, address.

the interface should be defined as public, the data shouldn't expose to outside of the class.

Exercise 7.20

friend is a mechanism by which a class grants access to its nonpublic members. They have the same rights as members.

Pros:

  • the useful functions can refer to class members in the class scope without needing to explicitly prefix them with the class name.
  • you can access all the nonpublic members conveniently.
  • sometimes, more readable to the users of class.

Cons:

  • lessens encapsulation and therefore maintainability.
  • code verbosity, declarations inside the class, outside the class.

Exercise 7.23 Header|CPP

Exercise 7.25

The class below can rely on it. It goes in Section 7.1.5:

..the synthesized versions are unlikely to work correctly for classes that allocate resources that reside outside the class objects themselves.

Moreover, the synthesized versions for copy, assignment, and destruction work correctly for classes that have vector or string members.

Hence the class below which used only built-in type and strings can rely on the default version of copy and assignment. (by @Mooophy)

Exercise 7.26 Header|CPP

Exercise 7.27 Class|Test

Exercise 7.28

The second call to display couldn't print # among the output, cause the call to set would change the temporary copy, not myScreen.

Exercise 7.29

#with '&'
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXX#XXXX
                   ^^^
# without '&'
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXXXXXXX
                   ^^^

Exercise 7.30

Pros

  • more explicit

  • less scope for misreading

  • can use the member function parameter which name is same as the member name.

      void setAddr(const std::string &addr) {this->addr = addr;}
    

Cons

  • more to read

  • sometimes redundant

      std::string getAddr() const { return this->addr; } // unnecessary
    

Exercise 7.33

[clang]error: unknown type name 'pos'

fixed:

Screen::pos Screen::size() const
{
    return height*width;
}

Exercise 7.34

There is an error in

dummy_fcn(pos height)
           ^
Unknown type name 'pos'

Exercise 7.35

typedef string Type;
Type initVal(); // use `string`
class Exercise {
public:
    typedef double Type;
    Type setVal(Type); // use `double`
    Type initVal(); // use `double`
private:
    int val;
};

Type Exercise::setVal(Type parm) {  // first is `string`, second is `double`
    val = parm + initVal();     // Exercise::initVal()
    return val;
}

fixed

changed

Type Exercise::setVal(Type parm) {
    val = parm + initVal();
    return val;
}

to

Exercise::Type Exercise::setVal(Type parm) {
    val = parm + initVal();
    return val;
}

and Exercise::initVal() should be defined.

Exercise 7.36

In this case, the constructor initializer makes it appear as if base is initialized with i and then base is used to initialize rem. However, base is initialized first. The effect of this initializer is to initialize rem with the undefined value of base!

fixd

struct X {
  X (int i, int j): base(i), rem(base % j) { }
  int base, rem;
};

Exercise 7.37

Sales_data first_item(cin);   // use Sales_data(std::istream &is)

int main() {
  Sales_data next;  // use Sales_data(std::string s = "")
  Sales_data last("9-999-99999-9"); // use Sales_data(std::string s = "")
}

Exercise 7.38

Sales_data(std::istream &is = std::cin) { read(is, *this); }

Exercise 7.39

illegal. cause the call of overloaded 'Sales_data()' is ambiguous.

Exercise 7.40

Such as Book

class Book {
public:
  Book() = default;
  Book(unsigned no, std::string name, std::string author, std::string pubdate):no_(no), name_(name), author_(author), pubdate_(pubdate) { }
  Book(std::istream &in) { in >> no_ >> name_ >> author_ >> pubdate_; }

private:
  unsigned no_;
  std::string name_;
  std::string author_;
  std::string pubdate_;
};

Exercise 7.41 Header|Cpp|Test

Exercise 7.42

class Book {
public:
  Book(unsigned no, std::string name, std::string author, std::string pubdate):no_(no), name_(name), author_(author), pubdate_(pubdate) { }
  Book() : Book(0, "", "", "") { }
  Book(std::istream &in) : Book() { in >> no_ >> name_ >> author_ >> pubdate_; }

private:
  unsigned no_;
  std::string name_;
  std::string author_;
  std::string pubdate_;
};