.5: If a derived class doesn't add any data members to the base class, does the derived class require constructors.. .6: Suppose a base class and a derived class both define a method of
Trang 1talents = 0;
}
ostream & operator<<(ostream & os, const nifty & n)
{
os << n.personality << '\n';
os << n.talent << '\n';
return os;
}
.5: Consider the following class declaration:
class Golfer {
private:
char * fullname; // points to string containing golfer's name int games; // holds number of golf games played
int * scores; // points to first element of array of golf scores public:
Golfer();
Golfer(const char * name, int g= 0);
// creates empty dynamic array of g elements if g > 0 Golfer(const Golfer & g);
~Golfer();
} ;
What class methods would be invoked by each of the following statements?
Golfer nancy; // #1 Golfer lulu("Little Lulu"); // #2 Golfer roy("Roy Hobbs", 12); // #3 Golfer * par = new Golfer; // #4 Golfer next = lulu; // #5 Golfer hazzard = "Weed Thwacker"; // #6
*par = nancy; // #7 nancy = "Nancy Putter"; // #8
a.
Trang 2Clearly, the class requires several more methods to make it useful, but what additional method does it require to protect against data corruption?
b.
A:
Golfer nancy; // default constructor Golfer lulu("Little Lulu"); // Golfer(const char * name, int g) Golfer roy("Roy Hobbs", 12); // Golfer(const char * name, int g) Golfer * par = new Golfer; // default constructor
Golfer next = lulu; // Golfer(const Golfer &g) Golfer hazard = "Weed Thwacker"; // Golfer(const char * name, int g)
*par = nancy; // default assignment operator nancy = "Nancy Putter";// Golfer(const char * name, int g), then // the default assignment operator
Note
Some compilers will additionally call the default assignment operator for statements #5 and #6.
a.
The class should define an assignment operator that copies data rather than addresses.
b.
Chapter 13
.1: What does a derived class inherit from a base class?
A: The public members of the base class become public members of the derived class The protected members of the base class become protected members
of the derived class The private members of the base class are inherited, but cannot be accessed directly The answer to review question 2 provides the
Trang 3exceptions to these general rules.
.2: What doesn't a derived class inherit from a base class?
A: The constructor methods are not inherited, the destructor is not inherited, the assignment operator is not inherited, and friends are not inherited.
.3: Suppose the return type for the baseDMA::operator=() function were defined as void instead of baseDMA & What effect, if any, would that have?
What if the return type were baseDMA instead of baseDMA &?
A: If the return type were void, you would still be able to use single assignment but not chain assignment:
baseDMA magazine("Pandering to Glitz", 1);
baseDMA gift1, gift2, gift3;
gift1 = magazine; // ok gift 2 = gift3 = gift1; // no longer valid
If the method returned an object instead of a reference, the method execution would be slowed a bit because the return statement would involve copying the object.
.4: In what order are class constructors and class destructors called when a derived class object is created and deleted?
A: Constructors are called in the order of derivation, with the most ancestral constructor called first Destructors are called in the opposite order.
.5: If a derived class doesn't add any data members to the base class, does the derived class require constructors?
A: Yes, every class requires its own constructors If the derived class adds no new members, the constructor can have an empty body, but it must exist.
.6: Suppose a base class and a derived class both define a method of the same name and a derived class object invokes the method What method is called?
Trang 4A: Only the derived class method is called It supersedes the base class definition A base class method is called only if the derived class does not redefine the method or if you use the scope resolution operator However, you really should declare as virtual any functions that will be redefined.
.7: When should a derived class define an assignment operator?
A: The derived class should define an assignment operator if the derived class constructors use the new or new [] operator to initialize pointers that are members of that class More generally, the derived class should define an assignment operator if the default assignment is incorrect for derived class members.
.8: Can you assign the address of an object of a derived class to a pointer to the base class? Can you assign the address of an object of a base class to a pointer to the derived class?
A: Yes, you can assign the address of an object of a derived class to a pointer to the base class You can assign the address of a base object to a pointer to a derived class (downcasting) only by making an explicit type cast, and it is not necessarily safe to use such a pointer.
.9: Can you assign an object of a derived class to an object of the base class?
Can you assign an object of a base class to an object of the derived class?
A: Yes, you can assign an object of a derived class to an object of the base class Any data members new to the derived type are not passed to the base type, however The program will use the base class assignment operator.
Assignment in the opposite direction (base to derived) is possible only if the derived class defines a conversion operator, which is a constructor having a reference to the base type as its sole argument, or else defines an assignment operator with a base-class parameter.
.10: Suppose you define a function that takes a reference to a base class object as
an argument Why can this function also use a derived class object as an argument?
A: It can do so because C++ allows a reference to a base type to refer to any
Trang 5type derived from that base.
.11: Suppose you define a function that takes a base class object as an argument
(that is, the function passes a base class object by value) Why can this function also use a derived class object as an argument?
A: Passing an object by value invokes the copy constructor Since the formal argument is a base class object, the base class copy constructor is invoked.
The copy constructor has as its argument a reference to the base class, and this reference can refer to the derived object passed as an argument The net result is producing a new base class object whose members correspond to the base class portion of the derived object.
.12: Why is it usually better to pass objects by reference than by value?
A: Passing an object by reference instead of by value enables the function to avail itself of virtual functions Also, passing an object by reference instead of value may use less memory and time, particularly for large objects The main advantage of passing by value is that it protects the original data, but you can accomplish the same end by passing the reference as a const type.
.13: Suppose Corporation is a base class and PublicCorporation is a derived
class Also suppose that each class defines a head() member function, that
ph is a pointer to the Corporation type, and that ph is assigned the address
of a PublicCorporation object How is ph->head() interpreted if the base class defines head() as a
Regular nonvirtual method
a.
Virtual method
b.
A: If head() is a regular method, then ph->head() invokes Corporation::head()
If head() is a virtual function, then ph->head() invokes
PublicCorporation::head().
.14: What's wrong, if anything, with the following code?
Trang 6class Kitchen {
private:
double kit_sq_ft;
public:
Kitchen() { kit_sq_ft = 0.0; } virtual double area() { return kit_sq_ft * kit_sq_ft; } };
class House : public Kitchen {
private:
double all_sq_ft;
public:
House() { all_sq_ft += kit_sq_ft;}
double area(const char *s) { cout << s; return all_sq_ft; } };
A: First, the situation does not fit the is-a model, so public inheritance is not
appropriate Second, the definition of area() in House hides the Kitchen
version of area() because the two methods have different signatures.
Chapter 14
.1: For each of the following sets of classes, indicate whether public or private derivation is more appropriate for the second column:
class Person, class Automobile class Driver
Trang 7class Bear class PolarBear Public, a polar bear is a kind of bear class
Kitchen
class Home Private, a home has a kitchen
class Person
class Programmer Public, a programmer is a kind of person
class Person
class HorseAndJockey
Private, a horse and jockey team contains aperson
class Person, class
class Driver Automobile
Person public because a driver is a person; Automobile private because a driver has an automobile
.2: Suppose we have the following definitions:
class Frabjous { private:
char fab[20];
public:
Frabjous(const char * s = "C++") : fab(s) {}
virtual void tell() { cout << fab; } };
class Gloam { private:
int glip;
Frabjous fb;
public:
Gloam(int g = 0, const char * s = "C++");
Gloam(int g, const Frabjous & f);
void tell();
};
Given that the Gloam version of tell() should display the values of glip and fb, provide definitions for the three Gloam methods.
Trang 8Gloam::Gloam(int g, const char * s) : glip(g), fb(s) { } Gloam::Gloam(int g, const Frabjous & f) : glip(g), fb(f) { } // note: the above uses the default Frabjous copy constructor void Gloam::tell()
{ fb.tell();
cout << glip << '\n';
}
.3: Suppose we have the following definitions:
class Frabjous { private:
char fab[20];
public:
Frabjous(const char * s = "C++") : fab(s) {}
virtual void tell() { cout << fab; } };
class Gloam : private Frabjous{
private:
int glip;
public:
Gloam(int g = 0, const char * s = "C++");
Gloam(int g, const Frabjous & f);
void tell();
};
Given that the Gloam version of tell() should display the values of glip and fab, provide definitions for the three Gloam methods.
A:
Gloam::Gloam(int g, const char * s) : glip(g), Frabjous(s) { } Gloam::Gloam(int g, const Frabjous & f)
Trang 9: glip(g), Frabjous(f) { } // note: the above uses the default Frabjous copy constructor void Gloam::tell()
{ Frabjous::tell();
cout << glip << '\n';
}
.4: Suppose we have the following definition, based on the Stack template of
Listing 14.14 and the Worker class of Listing 14.11 :
Stack<Worker *> sw;
Write out the class declaration that will be generated Just do the class declaration, not the non-inline class methods.
A:
class Stack<Worker *>
{ private:
enum {MAX = 10}; // constant specific to class Worker * items[MAX]; // holds stack items
int top; // index for top stack item public:
Stack();
Boolean isempty();
Boolean isfull();
Boolean push(const Worker * & item); // add item to stack Boolean pop(Worker * & item); // pop top into item };
.5: Use the template definitions in this chapter to define the following:
An array of String objects
Trang 10A stack of arrays of double
An array of stacks of pointers to Worker objects
How many template class definitions are produced in Listing 14.19 ?
A:
ArrayTP<String> sa;
StackTP< ArrayTP<double> > stck_arr_db;
ArrayTp< StackTP<Worker *> > arr_stk_wpr;
.6: Describe the differences between virtual and nonvirtual base classes.
A: If two lines of inheritance for a class share a common ancestor, the class winds
up with two copies of the ancestor's members Making the ancestor class a virtual base class to its immediate descendants solves that problem.
Chapter 15
.1: What's wrong with the following attempts at establishing friends?
class snap { friend clasp;
} ; class clasp { } ;
a.
class cuff { public:
void snip(muff &) { }
} ; class muff { friend void cuff::snip(muff &);
b.
Trang 11} ;
class muff { friend void cuff::snip(muff &);
} ; class cuff { public:
void snip(muff &) { }
} ;
c.
A:
The friend declaration should be as follows:
friend class clasp;
a.
This needs a forward declaration so that the compiler can interpret void snip(muff &):
class muff; // forward declaration class cuff {
public:
void snip(muff &) { }
};
class muff { friend void cuff::snip(muff &);
};
b.
First, the cuff class declaration should precede the muff class so that the compiler can understand the term cuff::snip() Second, the compiler needs a forward declaration of muff so that it can understand snip(muff
&).
c.
Trang 12class muff; // forward declaration class cuff {
public:
void snip(muff &) { }
};
class muff { friend void cuff::snip(muff &);
};
.2: You've seen how to create mutual class friends Can you create a more restricted form of friendship in which only some members of class B are friends
to class A and some members of A are friends to B? Explain.
A: No For A to have a friend that's a member function of B, the B declaration must precede the A declaration A forward declaration is not enough, for it would tell
A that B is a class, but it wouldn't reveal the names of the class members.
Similarly, if B has a friend that's a member function of A, the complete A
declaration must precede the B declaration These two requirements are mutually exclusive.
.3: What problems might the following nested class declaration have?
class Ribs {
private:
class Sauce {
int soy;
int sugar;
public:
Sauce(int s1, int s2) : soy(s1), sugar(s2) { } } ;
Trang 13
} ;
A: The only access to a class is through its public interface, which means the only thing you can do with a Sauce object is call the constructor to create one The other members (soy and sugar) are private by default.
.4: How does throw differ from return?
A: Suppose function f1() calls function f2() A return statement in f2() causes program execution to resume at the next statement following the f2() function call in function f1() A throw statement causes the program to back up through the current sequence of function calls until it finds a try block that directly or indirectly contains the call to f2() This might be in f1() or in a function that called f1(), and so on Once there, execution goes to the next matching catch block, not to the first statement after the function call.
.5: Suppose you have a hierarchy of exception classes derived from a base exception class In what order should you place catch blocks?
A: You should arrange the catch blocks in the order of most derived class to least derived.
.6: Consider the Grand, Superb, and Magnificent classes defined in this chapter
Suppose pg is a type Grand * pointer assigned the address of an object of one
of these three classes and that ps is a type Superb * pointer What is the difference in how the following two code samples behave?
if (ps = dynamic_cast<Superb *>(pg)) ps->say(); // sample #1
if (typeid(*pg) == typeid(Superb)) (Superb *) pg)->say(); // sample #2
A: For sample #1, the if condition is true if pg points to a Superb object or to an object of any class descended from Superb In particular, it is also true if pg
points to a Magnificent object In sample #2, the if condition is true only for a
Superb object, not for objects derived from Superb.