|
|
|
|
Exercises
Solutions to selected exercises
can be found in the electronic document The Thinking in C++ Annotated
Solution Guide, available for a small fee from
www.BruceEckel.com.
- Implement the inheritance
hierarchy in the OShape diagram in this
chapter.
- Modify the
result of Exercise 1 from Chapter 15 to use the Stack and iterator
in TStack2.h instead of an array of Shape pointers. Add
destructors to the class hierarchy so you can see that the Shape objects
are destroyed when the Stack goes out of
scope.
- Modify
TPStash.h so that the increment value used by inflate( ) can
be changed throughout the lifetime of a particular container
object.
- Modify
TPStash.h so that the increment value used by inflate( )
automatically resizes itself to reduce the number of times it needs to be
called. For example, each time it is called it could double the increment value
for use in the next call. Demonstrate this functionality by reporting whenever
an inflate( ) is called, and write test code in
main( ).
- Templatize
the fibonacci( ) function on the type of value that it produces (so
it can produce long, float, etc. instead of just
int).
- Using
the Standard C++ Library vector as an underlying implementation, create a
Set template class that accepts only one of each type of object that you
put into it. Make a nested iterator class that supports the “end
sentinel” concept in this chapter. Write test code for your Set in
main( ), and then substitute the Standard C++ Library set
template to verify that the behavior is
correct.
- Modify
AutoCounter.h so that it can be used as a member object inside any class
whose creation and destruction you want to trace. Add a string member to
hold the name of the class. Test this tool inside a class of your
own.
- Create a
version of OwnerStack.h that uses a Standard C++ Library vector as
its underlying implementation. You may need to look up some of the member
functions of vector in order to do this (or just look at the
<vector> header
file).
- Modify
ValueStack.h so that it dynamically expands as you push( )
more objects and it runs out of space. Change ValueStackTest.cpp to test
the new
functionality.
- Repeat
Exercise 9 but use a Standard C++ Library vector as the internal
implementation of the ValueStack. Notice how much easier this is.
- Modify
ValueStackTest.cpp so that it uses a Standard C++ Library vector
instead of a Stack in main( ). Notice the run-time behavior: Does
the vector automatically create a bunch of default objects when it is
created?
- Modify
TStack2.h so that it uses a Standard C++ Library vector as its
underlying implementation. Make sure that you don’t change the interface,
so that TStack2Test.cpp works
unchanged.
- Repeat
Exercise 12 using a Standard C++ Library stack instead of a vector
(you may need to look up information about the stack, or hunt through the
<stack> header
file).
- Modify
TPStash2.h so that it uses a Standard C++ Library vector as its
underlying implementation. Make sure that you don’t change the interface,
so that TPStash2Test.cpp works
unchanged.
- In
IterIntStack.cpp, modify IntStackIter to give it an “end
sentinel” constructor, and add operator== and operator!=. In
main( ), use an iterator to move through the elements of the
container until you reach the end
sentinel.
- Using
TStack2.h, TPStash2.h, and Shape.h, instantiate
Stack and PStash containers for Shape*, fill them each with
an assortment of upcast Shape pointers, then use iterators to move
through each container and call draw( ) for each
object.
- Templatize
the Int class in TPStash2Test.cpp so that it holds any type of
object (feel free to change the name of the class to something more
appropriate).
- Templatize
the IntArray class in IostreamOperatorOverloading.cpp from Chapter
12, templatizing both the type of object that is contained and the size of the
internal array.
- Turn
ObjContainer in NestedSmartPointer.cpp from Chapter 12 into a
template. Test it with two different
classes.
- Modify
C15:OStack.h and C15:OStackTest.cpp by
templatizing class Stack so that it automatically
multiply inherits from the contained class and from Object. The generated
Stack should accept and produce only pointers of the contained
type.
- Repeat
Exercise 20 using vector instead of
Stack.
- Inherit
a class StringVector from vector<void*> and redefine the
push_back( ) and operator[] member functions to accept and
produce only string* (and perform the proper casting). Now create a
template that will automatically make a container class to do the same thing for
pointers to any type. This technique is often used to reduce code bloat from too
many template
instantiations.
- In
TPStash2.h, add and test an operator- to PStash::iterator,
following the logic of
operator+.
- In
Drawing.cpp, add and test a function template to call
erase( ) member
functions.
- (Advanced)
Modify the Stack class in TStack2.h to allow full granularity of
ownership: Add a flag to each link indicating whether that link owns the object
it points to, and support this information in the push( ) function
and destructor. Add member functions to read and change the ownership for each
link.
- (Advanced)
Modify PointerToMemberOperator.cpp from Chapter 12 so that the
FunctionObject and operator->* are templatized to work with any
return type (for operator->*, you’ll have to use member
templates, described in Volume 2). Add and test support for zero, one and
two arguments in Dog member
functions.
[59]
With the exception, in Java, of the primitive data types. These were made
non-Objects for efficiency.
[60]
The OOPS library, by Keith Gorlen while he was at NIH.
[61]
The C++ Programming Language by Bjarne Stroustrup (1st edition,
Addison-Wesley, 1986).
[62]
The inspiration for templates appears to be ADA generics.
[63]
All methods in both Smalltalk and Python are weakly typed, and so those
languages do not need a template mechanism. In effect, you get templates without
templates.
|
|
|