Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
Solutions
to selected exercises can be found in the electronic document The Thinking
in C++ Volume 2 Annotated Solution Guide, available for a small fee from www.MindView.net.
1. Create a base class X with a single constructor that takes
an int argument and a member function f( ), which takes no
arguments and returns void. Now derive Y and Z from X,
creating constructors for each of them that take a single int argument.
Next, derive A from Y and Z. Create an object of class A,
and call f( ) for that object. Fix the problem with explicit
disambiguation.
2. Starting with the results of Exercise 1, create a pointer to an X
called px and assign to it the address of the object of type A
you created before. Fix the problem using a virtual base class. Now fix X
so you no longer have to call the constructor for X inside A.
3. Starting with the results of Exercise 2, remove the explicit
disambiguation for f( ) and see if you can call f( )
through px. Trace it to see which function gets called. Fix the problem
so the correct function will be called in a class hierarchy.
4. Make an Animal interface class with a makeNoise( )
function declaration. Make a SuperHero interface class with a savePersonFromFire( )
function declaration. Place a move( ) function declaration in both
interface classes. (Remember to make your interface methods pure virtual.) Now
define three separate classes: SuperlativeMan, Amoeba (a
superhero of uncertain gender), and TarantulaWoman; SuperlativeMan
implements the SuperHero interface while Amoeba and TarantulaWoman
implement both Animal and SuperHero. Define two global functions animalSound(Animal*)
and saveFromFire(SuperHero*). Invoke all the methods that are callable
from each interface in both of these functions.
5. Repeat the previous exercise, but use templates instead of
inheritance to implement the interfaces, as we did in Interfaces2.cpp.
6. Define some concrete mixin classes that represent superhero
capabilities (such as StopTrain, BendSteel, ClimbBuilding,
etc.). Redo exercise 4 so that your derived SuperHero classes derive
from these mixins and call their member functions.
7. Repeat the previous exercise using templates by making your
superhero powers mixin template parameters. Use these powers to do some good in
the community.
8. Dropping the Animal interface from exercise 4, redefine Amoeba
to only implement SuperHero. Now define a SuperlativeAmoeba class
that inherits from both SuperlativeMan and Amoeba. Try to pass a SuperlativeAmoeba
object to saveFromFire( ). What do you have to do to make this
legal? How does using virtual inheritance change the size of your objects?
9. Continuing with the previous exercise, add an integer strengthFactor
data member to SuperHero from exercise 4, along with a constructor to
initialize it. Add constructors in the three derived classes to initialize strengthFactor
as well. What must you do differently in SuperlativeAmoeba?
10. Continuing with the previous exercise, add an eatFood( )
member function to both SuperlativeMan and Amoeba (but not SuperlativeAmoeba),
such that the two versions of eatFood( ) take different types of
food objects (so the signatures of the two functions differ). What must you do
in SuperlativeAmoeba to call either eatFood( ) function?
Why?
11. Define a well-behaved output stream inserter and assignment
operator for SuperlativeAmoeba.
12. Remove SuperlativeAmoeba from your hierarchy and modify Amoeba
to derive from both SuperlativeMan (which still derives from SuperHero)
and SuperHero. Implement a virtual workout( ) function in
both SuperHero and SuperlativeMan (with identical signatures),
and call it with a Amoeba object. Which function gets called?
13. Redefine SuperlativeAmoeba to use composition instead of
inheritance to act as a SuperlativeMan or Amoeba. Use conversion
operators to provide implicit upcasting. Compare this approach to the
inheritance approach.
14. Suppose you are given a pre-compiled Person class (you
only have the header and compiled object file). Suppose also that Person
has a non-virtual work( ) function. Have SuperHero be able
to act as a mild-mannered ordinary Person by deriving from Person
and using the implementation of Person::work( ), but make SuperHero::work( )
virtual.
15. Define a reference-counted error logging mixin class, ErrorLog,
that holds a static file stream to which you can send messages. The class opens
the stream when its reference count exceeds 0 and closes the stream when the
count returns to 0 (and always appends to the file). Have objects of multiple
classes send messages to the static log stream. Watch the stream open and close
via trace statements in ErrorLog.
16. Modify BreakTie.cpp by adding a class named VeryBottom
that derives (non-virtually) from Bottom. VeryBottom should look
just like Bottom except change Left to Right in the using
declaration for f. Change main( ) to instantiate a VeryBottom
instead of a Bottom object. Which f( ) gets called?