OOPinC byJohnsonbaughMartin
OOPinC byJohnsonbaughMartin
MARTIN KALIN
Object-Oriented
n
a
m
iP
rg
o
C
+
www.MathSchoolinternational.com
Object-Oriented
Programming in C + +
Richard Johnsonbaugh
Martin Kalin
D E P A U L U N IV E R S IT Y
www.MathSchoolinternational.com
Cover photograph: Autograph score of Schubert’s Great C major Symphony,
Gesellschaft der Musikfreunde.
Used by permission
10 9 8 7 6 5 4 3 2 1
ISBN 0-05-3bDbfl2-7
www.MathSchoolinternational.com
Trademark Notices
www.MathSchoolinternational.com
,v'J.
I
{
www.MathSchoolinternational.com
Ik
Preface
www.MathSchoolinternational.com
viii PREFACE
O verview
During the 1980s and 1990s, C became the language of choice for many
applications and systems programmers. Most major software available for
personal computers is written in C: spreadsheets, word processors, databases,
communications packages, statistical software, graphics packages, and so on.
Virtually all software written for the UNIX environment is likewise written
in C, and many mainframe systems meant to be ported from one platform
to another are also coded in C. In the early 1980s, Bjarne Stroustrup of
A T& T Bell Labs developed C + + as an extension of C that supports object-
oriented programming, a type of programming that is well suited to the large,
complex software systems now written for all platforms, from the cheapest
personal computers to the most expensive mainframes. C + + also corrects
some shortcomings in C, which C + + includes as a subset, and it supports
abstract data types. C + + ’s popularity has grown in tandem with that of
object-oriented design in software. Accordingly, we cover object-oriented
design and C + + programming.
C + + is a complex language. Fortunately, most C + + programmers can
benefit from its power without mastering each and every one of its features.
Because ours is an introductory book, we focus on the most useful aspects
of the language; but we also cover all of the language’s constructs. We
emphasize using C + + to write practical applications based on sound object-
oriented design.
The book includes the following features:
• Examples and exercises that cover a wide range of applications.
• Sample applications.
• A broad variety of programming exercises. The book contains 59 pro
gramming exercises.
• End-of-chapter lists of common programming errors.
• Discussion of the standard C + + input/output class library (Chapter
7).
• Self-study exercises to enable readers to check their mastery of a section.
The book contains nearly 500 such exercises. Answers to the odd-
numbered exercises are in the back of the book.
• Figures to facilitate the learning process.
• Major data structures, including stacks (Section 3.2), strings (Section
4.1), binary search trees (Section 4.4), and files (Section 7.6), imple
mented in C ++.
• A number of appendixes.
• Understandable code. We opt for clarity over subtlety throughout the
book.
www.MathSchoolinternational.com
PREFACE ix
www.MathSchoolinternational.com
X PREFACE
application that builds a random access file class through inheritance from
a library file class. Second, the chapter uses the input/output library as
a major, sophisticated example of object-oriented design realized in C ++.
Chapter 7 pays close attention to manipulators, which are powerful ways
to do sophisticated input/output in C + + . We believe Chapter 7 offers an
unrivaled examination of C + + ’s input/output.
Chapter 8 covers advanced topics such as exception handling, run-time
type identification, and namespaces. These topics are recent additions to
C + + . The chapter also contrasts C + + with other object-oriented languages
such as Eiffel, Objective C, and Smalltalk. The chapter concludes with a
discussion of the future of object-oriented design and programming.
This book is devoted to C + + independent of any particular operating
system. However, the basic commands needed to run C + + programs are
given in Appendixes C and D for the UNIX g++ and Borland C + + compilers.
In addition, Appendix C contains an extended discussion of UNIX.
We rely heavily on short examples, pictures, tables, and other figures to
illustrate specific points about the syntax and semantics of C + + . From our
experience in teaching C + + and other languages, we are convinced that no
single method is appropriate for clarifying every aspect about a language.
Most of our students agree with us that learning and using C + + is fun.
We have tried to incorporate this view by using interesting examples, sample
problems, programming exercises, and short slices of code.
C hapter Structure
www.MathSchoolinternational.com
PREFACE xi
Exercises
The book contains nearly 600 section review exercises, the answers to which
are short answers, code fragments, and, in a few cases, entire programs.
These exercises are suitable as homework problems or as self-tests. The
answers to the odd-numbered exercises are in the back of the book, and
the answers to the even-numbered exercises are in the Instructor’s Guide.
Our experience teaching C + + has convinced us of the importance of these
exercises.
The applications covered in the programming exercises at the ends of the
chapters include the following:
• Semaphores (Programming Exercise 3.7)
• Local area networks (Programming Exercises 4.3 and 5.2)
• Scheduling (Programming Exercise 4.7)
• Graphs (Programming Exercises 4.9 and 5.6)
• Spreadsheets (Programming Exercises 4.8 and 6.9)
• Indexed files (Programming Exercise 7.5)
Not every reader will be interested in all of these applications; however, we
think that it is important to show the variety of problems that C + + can
address.
Appendixes
Four appendixes are provided for reference. Appendix A contains the ASCII
table. Appendix B contains a list of some of the most useful C + + functions
and class methods. We describe the parameters and return values for each,
the header file to include (when specified), and what the function or method
does.
For those readers using C + + under UNIX, we have included Appendix
C. We describe the GNU C + + compiler command g++ in some detail. In ad
dition to the g++ command, we also discuss the make utility, the file system,
commands for handling files (e.g., Is, cp), directories and several commands
www.MathSchoolinternational.com
xii PREFACE
for navigating within directories (e.g., pwd, mkdir), pipes, man (the on-line
help utility), the grep and fin d utilities, and run-time libraries.
Appendix D tells how to compile, link, and run a C + + program in
Borland C + + . Explanations are included for single-file and multiple-file
programs.
Instructor Supplements
Acknowledgm ents
R.J.
M.K.
www.MathSchoolinternational.com
Contents
1 Introduction 1
2 Basic C + + 17
3 Classes 73
www.MathSchoolinternational.com
xiv CONTENTS
5 Inheritance 203
www.MathSchoolinternational.com
CONTENTS xv
Appendix 449
A A S C I I Table 449
B Selected C + + Functions 453
C U N IX 481
D B orland C + + 495
Index 539
www.MathSchoolinternational.com
I
www.MathSchoolinternational.com
L
Object-Oriented Programming in C + +
www.MathSchoolinternational.com
www.MathSchoolinternational.com
111
Chapter 1
Introduction
www.MathSchoolinternational.com
2 CHAPTER 1 IN TR O D U C TIO N
www.MathSchoolinternational.com
1.1 OBJECT-ORIENTED DESIGN 3
circle line
www.MathSchoolinternational.com
4 CHAPTER 1 IN TR O D U C TIO N
main
g e t-fig u re draw
/ \
p u t_p rom p t get_response :
/ w
: :
Figure 1.1.2 Top-down design.
www.MathSchoolinternational.com
1.1 OBJECT- ORIENTED DESIGN 5
Exercises
4. How would the object-oriented design of this system using the objects and
methods of Exercises 1 and 2 differ from the top-down design of Exercise
3?
5. Answer Exercises 1-4 for a system that lays out the pages in the chapters
of this book.
www.MathSchoolinternational.com
6 CHAPTER 1 IN TR O D U C TIO N
www.MathSchoolinternational.com
CLASSES AN D A B STR A C T DATA TYPES 7
class strin g {
char v a l [ 80 ] ;
p u b lic:
void s to re ( char * ) ;
in t len gth ( ) ;
>;
The class s trin g consists of data (the array v a l) together with methods
store and length. Objects in the class strin g consist of the data (charac
ters stored in the array v a l) together with operations on this data: store
to store a C string (a null-terminated array of char) in an object belonging
to the C + + class s trin g and length to compute the length of the string
represented by the s trin g object.
C + + likewise supports information hiding. The keyword public makes
the methods store and length accessible to the outside world. Yet because
v a l is not in the public section of the class string, it is p rivate by default
and therefore not accessible to the outside world. The class strin g isolates
the representation of a string, which happens to be stored in the array val,
from the methods store and length, which are publicly accessible. The
user need not be concerned with how the characters that make up the string
are represented. The user concentrates instead on the operations available
for manipulating objects in the class string. □
A class declaration such as that of Example 1.2.1 does not create any
objects and does not allocate storage. After declaring a class and writing
the code that implements the methods, we can define objects in that class
following the C syntax for defining variables. We defer the discussion of how
to implement methods to Chapter 3.
Exam ple 1.2.2. Given the class declaration of Example 1.2.1, the defini
tion
strin g s, t ;
www.MathSchoolinternational.com
CHAPTER 1 IN TR O D U C TIO N
defines two objects s and t belonging to the class string. Storage is allo
cated for each object; s now has an array named data of size 80 and t also
has a (distinct) array named data of size 80. □
0
C + + borrows C’s syntax for structures to reference members of a class.
Suppose that s is an object in a class with data member x and method f.
The member x is referenced by writing
s. x
and the method f is invoked by writing
s . f ( arguments )
If p tr is a pointer to s, x is referenced by writing
p tr -> x
and the method f is invoked by writing
p tr -> f ( arguments )
Exam ple 1.2.3. Given the class declaration of Example 1.2.1 and the
definitions of s and t as in Example 1.2.2, we could pass a message to object
s to store the C string "Hi Mom" in the object s by writing
s .s t o r e ( "Hi Mom" ) ;
To store the length of s in the variable len we could write
len = s .len g th O ;
□
Exam ple 1.2.4. Suppose that we replace the class declaration of Example
1.2.1 with
class strin g {
char data[ 80 ] ;
in t len;
p u b lic :
void s to re ( char * ) ;
in t length( ) ;
>;
We now represent a string by storing its characters without a null termina
tor. To locate the end of the string we store the index of the last character
in the member len. We also reimplement the methods store and length to
reflect this change in representation. These changes are transparent to users
www.MathSchoolinternational.com
1.2 CLASSES AN D ABSTR A C T DATA TYPES 9
of this class. Code that accesses this class through its public members need
not be changed at all. For example, the code of Example 1.2.3 could use the
class of Example 1.2.1 or the new version of the class. □
Exercises
1. The string class of Example 1.2.1 has two methods. List some other
methods that one might expect to find in a string class.
2. In words, not in code, explain how to implement the methods store and
length in the string class of Example 1.2.1.
3. In words, not in code, explain how to implement the methods store and
length in the string class of Example 1.2.4. How would this implementa
tion differ from the implementation of these methods in the string class
of Example 1.2.1?
4. Suggest a way different from those of Examples 1.2.1 and 1.2.4 of repre
senting strings. Given this representation, how would the implementation
of the methods store and length differ from the implementation of these
methods in the string classes of Examples 1.2.1 and 1.2.4?
www.MathSchoolinternational.com
10 CH APTER 1 IN T R O D U C T IO N
1.3 Inheritance
In an object-oriented language, we can produce a new class by deriving the
new class from an already existing class. The mechanism for this derivation
is inheritance and the derived class is said to be inherited from the original
class. In CH—I- the new class is called the derived class and the original
class is called the base class. Following standard practice, we also call a
derived class a subclass of the original class, which in turn is a superclass
of the derived class. The derived class inherits all the data and methods from
the existing class, but the derived class may add additional data or methods
and, under certain circumstances, the derived class can redefine inherited
methods so that they behave differently than they do in the original class.
Deriving a class from a base class promotes code reusability and reusing
already correct code promotes code robustness.
www.MathSchoolinternational.com
1.3 INH ERITANCE 11
pen
x
base class
y
status
set_status
set__location
colored_pen
status ■ pen
set_status
set_location
color
set_color
makes all of the base class’s public members public in the derived class.
(If the keyword public is omitted, the base class’s public members become
private in the derived class.) Thus the methods set_status, set_location ,
and set_color can be invoked on an object of type colored_pen anywhere
in the program.
We could put a public method move in the class pen that would move
the pen from its current position (given by members x , y) to a new location
supplied as an argument to move. If the ink were on, move would then draw
a line from the original location to the new location. In the derived class, we
would need to redefine move so that, if the ink were on, move would draw a
colored line from the original location to the new location. The color would
be specified by the member color in the class colored_pen. In Chapter 5,
we explain how to redefine methods in derived classes. □
www.MathSchoolinternational.com
12 CHAPTER 1 IN TR O D U C TIO N
container
set
X X list
t
sorted_set stack
/ \ queue
t
H u ma n s 1
t
El ephants
Exam ple 1.3.2. Figure 1.3.3 shows a class hierarchy that uses multiple
inheritance. The following information is given:
• Bipeds, FeatherlessBeasts, WarmbloodedAnimals, and PinkThings
are classes. None is depicted here as derived from any other class.
• Humans is a class that is derived through multiple inheritance from
Bipeds, FeatherlessBeasts, and WarmbloodedAnimals.
Inheritance may be used in two broad ways to create a new class from
already existing classes. Single inheritance may be used to specialize an
existing class, whereas multiple inheritance may be used to combine two
existing classes. We illustrate with two examples.
www.MathSchoolinternational.com
1.3 INH ERITANCE 13
Win
t
ScrollWin
>;
>;
has attributes such as an x-coordinate, a y-coordinate, a width, and a
height. However, a Win does not have horizontal and vertical scroll bars.
The derived classScrollWin is a specialization of a Win in that a ScrollWin
has all the attributes or properties of a Win and, in addition, horizontal and
vertical scroll bars (see Figure 1.3.4). □
>;
>;
may be combined to create a ScrollPopupMenu
class ScrollPopupMenu :
public PopupMenu, public ScrollWin {
>;
www.MathSchoolinternational.com
14 CHAPTER 1 IN TR O D U C TIO N
Menu Win
t
PopupMenu ScrollWin
t
ScrollPopupMenu
Exercises
2. Derive a class book_loan that includes the members and methods de
clared in Exercise 1, but also adds members and methods to keep track
of whether someone has borrowed the book and, if so, who.
3. Declare a class person with data members name and address. In words,
not in code, explain how you would use this class and the class book of
www.MathSchoolinternational.com
1.4 PO LYM O RPH ISM 15
shape
c ir c le lin e
4. Show a class hierarchy with classes that might be used to track customers
and accounts at a bank.
1.4 Polymorphism
The word poly comes from a Greek word meaning many, and morphism
comes from a Greek word meaning form; thus, polym orphism means many
forms. In object-oriented programming, polymorphism refers to identically-
named methods that have different behavior depending on the type of object
that they reference. For example, the classes pen and colored_pen of Sec
tion 1.3 might each have a method move with parameters x and y of type in t
that determines where the object moves. If the ink is on, the method move
in class pen would draw a black line from its current position to the position
with coordinates x,y, whereas the method move in class colored_pen would
draw the line in a previously set color. When the method move is invoked,
polymorphism assures that the appropriate operation occurs by determin
ing at run time whether a pen or a colored_pen is the object in question.
Polymorphism is useful in providing a common abstract interface to users of
a class hierarchy.
The following C + + example shows why it is sometimes useful to delay
until run time the decision about which object is being referenced.
Exam ple 1.4.1. Suppose that we have a class shape with subclasses c ir c le
and lin e (see Figure 1.4.1). Suppose further that shape has a method draw
that has been redefined in both subclasses so that when c ir c le ’s draw is
invoked, a circle is drawn, and when lin e ’s draw is invoked, a line is drawn.
Suppose further that composite_f ig is an array of 100 pointers to objects
of type shape:
shape* com posite_fig[ 100 ] ;
One of the rules in C + + is that a pointer of type “pointer to base class”
can, without casting, point to any object in a derived class. Thus we assume
that each cell in composite_f ig contains the address of either a c ir c le
www.MathSchoolinternational.com
16 CHAPTER 1 IN TR O D U C TIO N
object or a lin e object. If we then step through the array and first draw the
figure to which composite_f i g [ 0 ] points, then draw the figure to which
composite_f ig [ 1 ] points, and so on, we draw the composite figure. Using
polymorphism, the following loop carries out this task
fo r ( i = 0; i < 100; i++ )
com posite_fig[ i ] -> drawO;
When this loop executes, the system determines what type of object is at ad
dress com posite_fig[ i ]. If the object is of type c ir c le , c ir c le ’s draw
is invoked; if the object is of type lin e, lin e ’s draw is invoked. Note that
we can reload the array composite_f ig with addresses of different objects,
even objects from other classes derived from shape, and draw the new com
posite figure using exactly the same loop. □
Exercises
1. Suppose that the base class book has derived classes manual and text.
Define an array book_array of 50 pointers to book. Suppose that book
has a method p rin t that is redefined in manual and text, and suppose
that book_array has been initialized with the addresses of 50 objects of
type manual or text. Write code that will print the books pointed to in
the array book_array.
2. Give an example different from Example 1.4.1 which illustrates the use
fulness of polymorphism.
www.MathSchoolinternational.com
Chapter 2
Basic C-f
17
www.MathSchoolinternational.com
18 CH APTER 2 BASIC C + +
Com m ents
Two slashes denote the beginning of a comment, which extends to the end
of the line. The C-style comment /* comment */ also can be used.
Exam ple 2.1.1. The following code illustrates the new style of comment:
// fin d largest
fo r ( i = 1, max = a [ 0 ] ; i < end; i++ )
i f ( a [ i ] > max ) // found la rg e r, so update
max = a [ i ] ;
□
Casts
the values of the in t variables h its and at_bats are converted to flo a t by
using the cast operator before division. In C + + , this could be written
average = f l o a t ( h its ) / f l o a t ( at_bats );
*We use the term “define” to refer to a statement that allocates storage for a variable or to refer
to the header and body of a function. We use the term “declare” to refer to the description of a data
type.
www.MathSchoolinternational.com
2.1 SOME MISCELLANEOUS EXTENSIONS IN C + + 19
Structures
const
The type qualifier const first appeared in C + + but was subsequently added
to standard C. We illustrate some of its uses.
www.MathSchoolinternational.com
CHAPTER 2 BASIC C + +
The keyword const, which stands for constant, allows the programmer
to designate storage whose contents or value cannot be changed.
The advantage of a const variable over the #define directive is that the
variable becomes a bona fide part of the pfogram and, as such, can be
referenced by name by the debugger, has storage allocated for it, has a
type, and so on. On the other hand, a #define directive is handled by the
preprocessor prior to compilation; consequently, the macro name cannot be
referenced by the debugger, has no storage allocated for it, and has no type.
The type qualifier const applies to the type. For example, in the defini
tion
char s [ ] = "Hi Mom";
const char* p tr = s;
const applies to char* so it is not legal to change what p tr points to, but
it is legal to change p tr’s value. For example,
p t r [ 1 ] = ’ o ’ ; // * * * * * ERROR: can’t change "Hi Mom"
is an error but
p tr = "Hi Dad"; // * * * * * OK: can change ptr
is legal.
To define a pointer constant (a pointer whose value cannot be changed),
we would write
char s [ ] = "Hi Mom";
char* const ptr = s;
Now it is legal to change what p tr points to, but it is an error to change the
value of ptr itself. For example,
p t r [ 1 ] = ’ o ’ ; // * * * * * OK: can change what p tr points to
is legal but
ptr = "Hi Dad"; // * * * * * ERROR: can’t change ptr
is an error.
The following example shows how to use const parameters.
www.MathSchoolinternational.com
2.1 SOME M ISCELLANEOUS EXTENSIONS IN C + + 21
D efining Variables
www.MathSchoolinternational.com
22 CHAPTER 2 BASIC C + +
at i ] = a [ s ize - 1 - i ] ;
a [ size - 1 - i ] = temp;
>
Exercises
4. in t a [ ] = { 2, 4, 6 } ;
in t i ;
const in t* p = a;
p = &i;
www.MathSchoolinternational.com
2.2 FUNCTIONS 23
5. in t a [ ] = { 2 , 4, 6 > ;
const in t* p = a;
p [ 1 ] = 12;
6. in t a [ ] = { 2, 4, 6 >;
in t* const p = a;
pC 1 ] = 12;
7. in t a [ ] = { 2 , 4, 6 } ;
in t i ;
in t* const p = a;
p = &i;
10. Write a function reverse that reverses an array of floats. The argu
ments are a, a pointer to the first flo a t, and size, the number of elements
in the array. Declare appropriate parameters as const.
11. Write a complete program to read up to 100 flo a ts from the standard
input, compute the average of the numbers read, and then print each
number and its absolute difference from the average. Use const to define
any constants that are needed. Define variables near the point at which
they are first used. Use //-style comments.
2.2 Functions
In this section, we highlight some of the ways that C + + has extended C
functions.
Prototypes
www.MathSchoolinternational.com
24 CHAPTER 2 BASIC C + +
>
is written in prototype form.
If grade is invoked in a function assign and the definition of grade
appears before the definition of assign, grade’s definition can also serve as
its declaration:
// d efin itio n of grade
char grade( const int examl,
const int exam2,
const flo a t examl_weight )
>
>
If grade is defined after assign or in a different file, grade must be
declared in prototype form either in or before assign:
// declaration of grade
char grade( const int examl,
const int exam2,
const flo a t examl_weight ) ;
c = grade( 9, 7, 0.6 ) ;
>
www.MathSchoolinternational.com
2.2 FUNCTIO NS 25
>
The compiler can use prototypes to check for matches between argu
ments and parameters of functions and issue appropriate warning and error
messages if it detects problems. The compiler can also use prototypes to
convert one type to another, if possible, when the types do not match. For
example, if the prototype declaration specified a flo a t parameter, but the
function was called with an in t argument, the compiler would convert the
in t argument to a flo a t.
Subject to certain restrictions to be discussed in the Overloading Func
tions subsection, C + + , unlike C, allows distinct functions with the same
name. When a function f is invoked and there is more than one function
named f, C + + determines which f to invoke by checking for a match be
tween the types of arguments supplied and the types of parameters specified
in the prototype declarations of the various f ’s.
In C + + , empty parentheses in a function prototype are interpreted as
specifying no parameters. For example,
in t p r in t( ) ;
specifies that the function p rin t has no parameters and returns an int. This
is quite different from the meaning in standard C, where the specification
is that no information is being supplied about p rin t’s parameters and no
checking of arguments and parameters is to be done when p rin t is called.
Thus in C + + there is really no “empty” parameter list. The declaration
in t p r in t( ) ;
is equivalent to
in t p r in t( void ) ;
Every program must contain a function called main where execution of the
program begins. Since the system does not declare a prototype for main,
its type is implementation dependent. However, C + + guarantees that every
implementation support either
www.MathSchoolinternational.com
26 CHAPTER 2 BASIC C + +
in t mainO
{
>
or
in t main( in t argc, char* argv[ ] )
>
As in C, in the latter form, argc is the number of arguments passed to the
program, and argv[ 0 ] through argv[ axgc - 1 ] are the addresses of
the passed arguments. Other definitions of main such as
void mainO
{
>
may not be supported by a particular implementation.
The return statement
return status;
in main terminates the main function and thus the program as a whole and
returns the value status to the invoking process. The status values
EXIT_SUCCESS EXIT_FAILURE
defined in stdlib.h are used to signal normal and abnormal termination, re
spectively. (Other status values may be available in a particular implemen
tation.)
References
www.MathSchoolinternational.com
2.2 FUNCTIONS 27
Pass by Reference
int main()
int i = 7, j = -3;
swap( i , j ) ;
p rin tf ( " i = °/,d, j = %d\n", i , j );
return EXIT_SUCCESS;
>
www.MathSchoolinternational.com
28 CHAPTER 2 BASIC C + +
i ______ J
a t>
in t t ;
t = a;
a = b;
b = t;
>
the prototype
void swap( intfe, intfe ) ;
specifies that the arguments to swap axe passed by reference. Thus when
the arguments i and j in main are passed to swap
swap( i , j ) ;
swap receives the addresses of i and j . The ampersands in swap’s header
void swap( intfe a, intfe b )
signal that no dereferencing of the parameters a and b is required in swap’s
body. The names a and b in swap’s body refer directly to the storage in
main named i and j (see Figure 2.2.1). The function swap works not with
copies of i and j but directly with i and j . The output of the program is
i = -3, j = 7
□
void swap_C_version( in t* , in t* ) ;
www.MathSchoolinternational.com
2.2 FUNCTIONS 29
in t main()
{
in t i = 7, j = -3;
return EXIT.SUCCESS;
>
void swap_C_version( in t* a, in t* b )
in t t ;
t = *a;
* a = *b;
*b = t ;
>
R etu rn by Reference
The following example illustrates how a function can return a value by ref
erence.
return a [ i - 1 ] ;
>
The return designation int& signals that the function is returning an in t
by reference. In effect, the address of a [ i - 1 ] is returned, but the user
need not use the dereference operator. The function new_index could be
invoked as
va l = new_index( a, 8 ) ;
□
www.MathSchoolinternational.com
30 CHAPTER 2 BASIC C + +
Inline Functions
t = a;
a = b;
b = t;
}
www.MathSchoolinternational.com
2.2 FUNCTIONS 31
in t mainO
{
in t i = 7, j = -3;
swap( i , j ) ;
p r in t f( 11i = */,d, j = '/.d\n", i , j ) ;
return EXIT_SUCCESS;
>
Assuming that the compiler honors the request to expand swap inline, no
function call occurs at the line
swap( i , j ) ;
Because swap is an inline function, the compiler replaces the line
swap( i , j ) ;
with the code that implements swap. □
>
has default values for the parameters s, t, and msg but no default value for
the parameter val.
Legal invocations of f are
f( 14, 48.3, ’ \ t \ "OK" ) ;
f( 14, 48.3, ’ \t> ) ;
f( 14, 48.3 ) ;
f( 14 ) ;
In the invocation
f ( 14, 48.3, ’ \ t ’ , "OK" ) ;
arguments are supplied for all of the parameters. Therefore, the initial values
of the parameters are
www.MathSchoolinternational.com
CHAPTER 2 BASIC C + +
Example 2.2.8 shows that it is legal to supply default values for some
parameters but not for others. However, all the parameters without default
values must come first in the parameter list and then be followed by all the
parameters with default values.
}
is illegal because the parameter val with a default value is followed by the
parameter s without a default value. □
www.MathSchoolinternational.com
2.2 FUNCTIONS 33
Overloading Functions
C + + permits identically named functions within the same scope if they can
be distinguished by number and type of parameters. If there are multiple
definitions of a function f , f is said to be overloaded. The compiler deter
mines which version of an overloaded function to invoke by choosing from
among the identically named functions the one function whose parameters
best match the arguments supplied.^
in t mainO
{
p r in t( 7 ) ;
p r in t( "Yo. L e t ’ s rap" ) ;
return EXIT_SUCCESS;
>
void p r in t( in t i )
{
p rin tf ( "7,d\n" , i ) ;
}
void p r in t( char* s )
{
p rin tf ( M‘/,s\n", s ) ;
>
contains two distinct functions named print. When the line
p r in t( 7 ) ;
is executed, the function
void p r in t( in t i )
p r in tf ( "*/,d\n", i ) ;
}
1The precise rules for determining which function is the “best match” are complicated (see, e.g.,
Working Paper fo r Draft Proposed International Standard fo r Information Systems—Programming
Language C + + ); however, an exact match is always the best match.
www.MathSchoolinternational.com
34 CHAPTER 2 BASIC C + +
is invoked because the argument is of type int. However, when the line
p r in t ( "Yo. L et 's rap" ) ;
is executed, the function
void p r in t( char* s )
p r i n t f ( "’/,s\n", s ) ;
}
is invoked because the argument is of type char*. □
O verloading O perators
.* : : ?: s ize o f
Exercises
www.MathSchoolinternational.com
2.2 FUNCTIO NS 35
2. Find the errors and provide corrections for the following code:
#include <stdio.h>
mainO
{
int a [ size ] ;
reverse( a ) ;
return EXIT_SUCCESS;
}
3. int mainO
{
>
>
www.MathSchoolinternational.com
36 CHAPTER 2 BASIC C + +
5. mainO
{
>
6. void mainO
>
7. in t main( void )
■c
>
struct strin g {
char s [ 80 ] ;
>;
#include <stdio.h>
#include <stdlib.h>
struct point {
in t x, y;
>;
q.x— ;
q-y++;
>
in t mainO
point p;
p.x = 5;
p . y = "12;
www.MathSchoolinternational.com
2.2 FUNCTIONS 37
move( p ) ;
p rin tf ( "x = */.d, y = ‘/(d\n", p .x, p.y ) ;
return EXIT_SUCCESS;
>
#include <stdio.h>
#include <stdlib.h >
struct point {
int x, y;
>;
int mainO
{
point p;
p.x = 5;
p.y = -12;
move( p ) ;
p rin tf ( "x = ’/.d, y = ‘/.d\n", p .x , p.y ) ;
return EXIT_SUCCESS;
>
#include <stdio.h>
#include <stdlib.h >
struct point {
int * x , * y ;
>;
www.MathSchoolinternational.com
CHAPTER 2 BASIC C + +
+ + *q .y ;
>
int mainO
■c
point p;
int a = 5, b = -12;
p.x = &a;
p.y = &b;
move( p ) ;
p rin tf ( "x = '/,d, y = 7,d\n", *p .x, *p.y ) ;
return EXIT.SUCCESS;
>
#include <stdio.h>
#include <stdlib.h>
struct point {
int *x, *y;
>;
*q.x;
++*q .y ;
>
int mainO
point p;
int a = 5, b = -12;
p.x = &a;
p.y = &b;
move( p ) ;
p r in t f ( "x = %d, y = %d\n", *p .x, *p.y ) ;
return EXIT.SUCCESS;
>
www.MathSchoolinternational.com
FUNCTIO NS 39
13. Write a version of the function of Example 2.2.6 in C. How would the
lines
val = new_index( a, 8 );
new_index( a, 8 ) = -16;
have to be rewritten?
15. Write a version of prin t (see Example 2.2.10) that receives a s trin g
(declared in Exercise 8) and prints the member s. Pass the argument by
reference.
#include <stdio.h>
#include <stdlib.h>
int mainO
{
print( 10 );
return EXIT_SUCCESS;
>
www.MathSchoolinternational.com
40 CHAPTER 2 BASIC C + +
Description Operator
Scope resolution II
Value construction type ()
Storage allocation new
Storage release (single cell) d elete
Storage release (vector) d e le te [ ]
Member object selector .*
Member pointer selector ->*
Throw exception throw
2.3CH—|- Operators
C + + has extended C by adding the operators shown in Figure 2.3.1. In
Figure 2.3.2, we list the C + + operators, including those from C, together
with their precedence and associativity rules. We discuss each of the new
operators in turn.
void f ( in t n )
flo a t x; // lo c a l (auto) x
x = 1.5; // f ’ s x
::x = 2.5; // extern x
}
the extern x would ordinarily be inaccessible within the function f because
f defines an identically named variable. The scope resolution operator makes
it possible to refer to the extern x within f . □
www.MathSchoolinternational.com
2.3 C + + OPERATORS 41
II
II
PP *
>\
www.MathSchoolinternational.com
42 CHAPTER 2 BASIC C + +
The second form c l: :m, which is used throughout the remainder of the
book, is used to refer to member m in class cl. The subsection, The Mem
ber Selector Operators, illustrates one use of the second form of the scope
resolution operator.
The new, delete, and d elete [ ] operators are used to allocate and free
storage dynamically, (d elete frees a single cell, whereas d e le te [ ] frees a
vector of cells.) They work much like the C library functions malloc and
fre e . Unlike malloc and free, however, new, delete, and d elete [ ] are
built-in operators rather than library functions. Finally, new and d elete are
C + + keywords.
The new operator is used to allocate storage dynamically. The basic
syntax is the keyword new followed by a type. For example,
new in t
requests storage for one int. If new is successful in allocating the storage,
the value of the expression
new in t
is a pointer to the allocated storage; otherwise, the value of the expression
is 0. If in t_p tr is a pointer to int, a typical statement to allocate storage
is
in t_ p tr = new in t;
In the analogous C allocation statement,
in t_p tr = ( in t* ) m alloc( s ize o f ( in t ) ) ;
a cast to in t* is required on malloc’s return value and malloc must be
given, as an argument, the number of bytes to allocate. These requirements
are dropped from new, which is therefore easier to use. The new operator
infers the return type and the number of bytes to allocate from the type of
storage requested. In sum, new behaves like a smart malloc.
The new operator can also be used to allocate dynamically an arbitrary
number of contiguous cells, which is a cell vector. A cell vector is the
dynamic counterpart of an array. For example, the code slice
www.MathSchoolinternational.com
2.3 C + + OPERATORS 43
in t_p tr = new i n t [ 50 ] ;
requests a vector of 50 in t cells. If new succeeds in allocating 50 contiguous
cells, the first cell’s address is stored in in t_ptr. Otherwise, new returns 0,
which is stored in int_ptr.
The d elete operator is used to free storage allocated by new. If in t_p tr
points to a single in t cell allocated by new, we can release this storage by
writing
d elete in t_p tr;
If in t_p tr points to a vector of in t cells allocated by new, we can release
this storage by writing^
d e le te [ ] in t_ p tr ;
Example 2.3.2. The following program constructs a linked list using stor
age cells allocated at run time. After constructing the list, the program
prints the contents of the cells and then steps through the list and frees the
allocated nodes.
#include <stdio.h>
#include <stdlib.h>
struct elephant {
char name[ 10 ] ;
elephant* next;
>;
in t mainO
elephant* s ta rt;
s ta rt = get_elephants( ) ;
print_elephants( sta rt ) ;
f r e e _ l i s t ( staxt ) ;
return EXIT_SUCCESS;
>
www.MathSchoolinternational.com
44 CHAPTER 2 BASIC C + +
elephant* get_elephants()
{
elephant *current, * f i r s t ;
int response;
// allocate f i r s t node
current = f i r s t = new elephant;
www.MathSchoolinternational.com
2.3 C + + OPERATORS 45
p r in t f( "\n\n\n" ) ;
while ( p tr != 0 ) {
p r in t f ( "\nElephant number '/,d is 7,s.",
count++, p tr -> name ) ;
p tr = p tr -> next;
}
>
void f r e e _ l i s t ( elephant* p tr )
{
elephant* temp_ptr;
while ( p tr != 0 ) {
temp_ptr = p tr -> next;
d elete p tr;
p tr = temp_ptr;
>
}
□
www.MathSchoolinternational.com
CHAPTER 2 BASIC C + +
struct C {
int x;
flo a t y;
flo a t z;
int m a i n O
// reset c l.y
www.MathSchoolinternational.com
C + + OPERATORS 47
c l.* f_ p t r = -777.77;
illustrates the syntax for defining and using a pointer to a class member.
The syntax
c l.* f_ p t r = 3.14;
A different error occurs when we try to make f _ptr point to data member
x, which is an in t rather than a flo a t member of C. Once defined, f_ p tr
may point to either y or z, as both members are floats.
Finally, a pointer that is not class specific may be used to access data
members. In our example, i_ p tr of type in t* can be assigned the address
of c l.x because c l.x is an int. □
www.MathSchoolinternational.com
48 CH APTER 2 BASIC C + +
struct C {
in t x;
flo a t y;
flo a t z;
in t mainO
// define a pointer to C
C* c_ptr;
// make f_ p tr point to z
f_ p tr = &C::z;
// set c l . z to 123.321
c_ptr ->* f_ p tr = 123.321;
// make f_ p tr point to y
f_ p tr = &C::y;
>
www.MathSchoolinternational.com
C + + OPERATORS 49
Pointer c_ptr is of type C* and so can hold the address of either c l or c2.
Pointer f_ p tr is again of type “pointer to flo a t member of C” and so can
hold the address of either C: : y or C: : z. In an expression such as
// set c2.y to -111.99
c_ptr ->* f_ p tr = -111.99;
the operator ->* may be viewed as performing two tasks. First, the arrow
-> gives us access to the class object, in this case c2, by dereferencing c_ptr.
Second, the star * gives us access to a particular data member, in this case
c2. y, by dereferencing f _ptr. The syntax ->* thus says: Access the member
through the pointer to the object (->) by dereferencing the pointer to the
member (*). The white space on each side of ->* is optional. We could have
written
// set c2.y to -111.99
c_p tr-> *f_p tr = -111.99;
□
Example 2.3.5. The following program shows how to define and use point
ers to class methods:
struct C {
in t x;
short f ( in t ) ;
short g ( in t ) ;
>;
in t mainO
{
short s;
C c;
www.MathSchoolinternational.com
50 CHAPTER 2 BASIC C + +
// pointer to object c
C* ptr = &c;
>
□
T he T h ro w Exception O perator
Exercises
#include <stdio.h>
#include <stdlib.h>
short m = 18;
int m a i n O
short m = 4;
p rin tf ( "'/.d #
/,d\n", : :m, m ) ;
return EXIT_SUCCESS;
>
www.MathSchoolinternational.com
C + + OPERATORS 51
2. Write a statement to allocate one cell of type double and store its address
in the pointer dbl_ptr.
4. Write a statement to allocate 100 cells of type pointer to char and store
the address of the first cell in the char pointer str.
6. Change Example 2.3.2 so that the user can choose to supply no names.
struct odometer {
long m iles;
in t tenths;
void set_m iles( long ) ;
>;
odometer o d l, od2;
10. Use the pointer of Exercises 8 and 9 to set o d l’s miles to 83117.
11. Use the pointer of Exercises 8 and 9 to set od2’s miles to 15004.
14. Use the pointers of Exercises 8, 9, 12, and 13 to set od l’s miles to 73893.
17. Use the pointer of Exercises 15 and 16 to invoke o d l’s set_m iles with
argument 69402.
www.MathSchoolinternational.com
52 CH APTER 2 BASIC C + +
Stream
^ P l a n 9 F r o m Out er Space
Input
P l a n 9 F r o m Out er Space
Stream
P l a n 9 P r o m Out e r Space — ^
Output
cin » x;
www.MathSchoolinternational.com
IN T R O D U C T IO N TO C + + IN P U T / O U T P U T 53
reads a flo a t value from the standard input and stores it in x. The input
is converted to flo a t because the variable x is of type flo at. If len is a
long, the statement
cout « len;
writes the value of len to the standard output. The value is converted from
long because the variable len is of type long. □
The next example shows how multiple variables may be read or written
in a single statement.
Example 2.4.2. The following program prompts the user for three values:
an int, a flo a t, and a string, and then writes the values to the standard
output.
#include <iostream.h>
#include <stdlib.h >
int m a i n O
{
int id;
flo a t av;
char name[ 20 ] ;
return EXIT_SUCCESS;
>
The operators » and « associate from the left; so in the line
cin » id » av » name;
first a value is read into id, then a value is read into av, and then a value is
read into name. Similarly, in the line
cout « "Id " << id « ’ \n’
<< "Name " << name << J\n’
« "Average " « average « ’ \nJ;
first Id is written, then the value of id is written, then the newline is written,
and so on. □
The default action of the input operator » is to skip white space before
reading the next input item. The situation is similar to that of the C library
www.MathSchoolinternational.com
CH APTER 2 BASIC C + +
function scanf, except that even if the variable is of type char, the operator
» skips white space before reading the character. (It is possible to change
the default action of skipping white space— see io s : : skipws in Section 7.2.)
If the variable is of type char* (e.g., name in Example 2.4.2), after skipping
white space, all characters up to but not including the next white space
character are read and stored.
The methods get and read may also be used with cin to read data. If
c is a char
c in .g e t ( c )
reads the next character without skipping white space and stores it in c.
This version of get resembles the C function get char.
Another version of get resembles the C function fgets. If buff is an
array of char,
c in .g e t ( b u ff, max_line )
reads the next line from the standard input and stores it in buff. The “next
line” consists of
The next max_line — 1 characters,
or
All characters up to and but not including the next newline character,
or
All characters up to the end of the input,
whichever is shortest. The method get then stores the characters read
and adds a terminating null ’ \0 ’ . Notice that get never stores more than
max_line characters (including ’ \0’ ). The terminating newline is not re
moved from the standard input nor is it stored in buff.
The variant
c in .g e t ( b u ff, max_line, end_mark )
has the same behavior as get described in the previous paragraph except
that the arbitrary character end_mark marks the end of the line rather than
the default ’ \n’ .
If get is successful in reading at least one character, it returns nonzero;
otherwise, it returns zero.
www.MathSchoolinternational.com
IN TR O D U C TIO N TO C + + IN P U T / O U T P U T 55
int mainO
return EXIT_SUCCESS;
}
#include <iostream.h>
#include <stdlib.h>
in t mainO
{
const in t i = 91;
return EXIT_SUCCESS;
>
www.MathSchoolinternational.com
56 CH APTER 2 BASIC C + +
is
i = 91 (decimal)
i = 133 (o c ta l)
i = 5b (hexadecimal)
i = 91 (decimal)
If dec were omitted from the last line, the output would again be in hex
adecimal because once the status of cout is changed by using a manipulator,
the status remains in effect until changed again. □
Exam ple 2.4.5. The following program numbers lines. The line numbers
are right aligned.
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
in t mainO
in t line_no = 0;
char c, buff [ b u ffs ize ] ;
www.MathSchoolinternational.com
IN TR O D U C TIO N TO C + + IN P U T / O U T P U T 57
if ( ! cin.g e t( c ) I I c == ’\ n ’ )
break;
cout « setw( 4 ) « ++line_no
« " « buff « endl;
>
return EXIT_SUCCESS;
>
If the input is this source code, the output is
1: #include <iostream.h>
2: #include <iomanip.h>
3: #include <stdlib.h>
4:
5: const in t b u ffs ize = 256;
6:
7: in t mainO
8: {
9: in t line_no = 0;
10: char c, b u ff[ b u ffs ize ] ;
11:
12: while ( c in .g e t( b u ff, b u ffsize ) ) {
13: // d elete rest of lin e including newline
14: fo r ( ; ; )
15: if ( !c in .g e t( c ) || c == ’ \n’ )
16: break;
17: cout « setw( 4 ) « ++line_no
18: « 11: 11 « buff « endl;
19:
20:
21: return EXIT.SUCCESS;
22: }
The default field width is zero. Therefore, to right-justify the line num
bers, in line 16 we first set the field width to 4 by using the manipulator
setw. The line number is then printed in the first four columns; by default,
it is right justified. After printing the line number, the field width auto
matically returns to its default value of zero. We then print a colon and a
space, the contents of b u ff, and a newline. In C+-1-, as in C, if the output is
bigger than the field width, it is printed anyway using the minimum number
of columns. □
Using the C input/output library functions (p rin tf and the like) and the
C + + class library (cout and the like) in the same program can cause prob
lems because reads and writes from the two libraries are not automatically
www.MathSchoolinternational.com
58 CH APTER 2 BASIC C + +
Exercises
1. Write a line that uses cin to read a short value into i, a long double
value into x, and a string into the char array str.
2. Write a line that uses cout to print the values read in Exercise 1.
3. What will happen in the program of Example 2.4.3 if we delete the lines
fo r ( ; ; )
if ( !c in .g e t( c ) I I c == ’ \n’ )
break;
2. The definition of p
promises not to change what p points to, although the value of p itself
can be changed. Thus
www.MathSchoolinternational.com
CO M M O N PRO G R A M M IN G ERRORS 59
is an error, but
in t b [ 4 ] ;
p = b; // * * * * * OK * * * * *
is legal.
3. The definition of p
promises not to change the value of p, although the value of what p points
to can be changed. Thus
in t b [ ] = { 1, 2 , 3, 4 >;
p = b; // * * * * * ERROR * * ***
is an error, but
p [ 2 ]+ + ; // * * * * * OK * * * * *
is legal.
void f ( const in t i )
{
i = 8; // * * * * * ERROR * * * * *
>
p[ 1 ] *= 2 .0 ; // * * * * * ERROR * * * * *
>
#include <iostream.h>
#include <stdlib.h>
www.MathSchoolinternational.com
CHAPTER 2 BASIC C + +
int m a i n O
■C
in t i = 1, j = 3;
return EXIT_SUCCESS;
>
int t;
t = a;
a = b;
b = t;
>
#include <iostream.h>
#include <stdlib.h >
int t ;
t = a;
a = b;
b = t;
}
int main()
>
#include <iostream.h>
#include <stdlib.h>
www.MathSchoolinternational.com
CO M M O N PR O G R A M M IN G ERRORS 61
in t mainO
•C
>
#include <iostream.h>
#include <stdlib.h>
in t main()
{
void swap( intfe, intfe ) ;
in t i = 1, j = 3;
in t mainO
#include <stdio.h>
#include <stdlib.h>
in t mainO
{
// * * * * * CORRECT *** * *
p r in t f ( "Here’ s lo o k in ’ at you kid.\n" ) ;
www.MathSchoolinternational.com
CH APTER 2 BASIC C + +
return EXIT_SUCCESS;
>
int f ( ) ;
int f ( ) ;
int mainO
int mainO
{
and
>
www.MathSchoolinternational.com
CO M M O N PR O G R A M M IN G ERRORS 63
struct strin g {
char s [ 80 ] ;
>;
strcpy( s t r .s , t ) ;
11. An inline function is visible only from the point at which it is declared to
the end of the file. For this reason, the following is an error:
#include <stdio.h>
#include <stdlib.h >
int m a i n O
{
int i = 9, j = 10;
return EXIT_SUCCESS;
}
www.MathSchoolinternational.com
CH APTER 2 BASIC C + +
t = a;
a = b;
b = t;
>
#include <iostream.h>
#include <stdlib.h>
t = a;
a = b;
b = t;
}
int mainO
#include <iostream.h>
#include <stdlib.h>
int mainO
#include <iostream.h>
#include <stdlib.h>
www.MathSchoolinternational.com
C O M M O N PR O G R A M M IN G ERRORS 65
in t mainO
{
in lin e void swap( intfe, intfe ) ;
int i = 1, j = 3;
12. All parameters without default values must come first in the parameter
list and then be followed by all the parameters with default values. For
this reason, the following is an illegal function header:
13. If a parameter does not have a default value, an argument must be sup
plied when the function is invoked. For example, if the header of f is
// * * * * * LEGAL * * * * *
f ( 93.6, 0, »\t» ) ;
f ( 93.6, 0 ) ;
but
is illegal.
15. Do not use new and d elete with the C storage management functions:
www.MathSchoolinternational.com
CH APTER 2 BASIC C + +
18. To use the C + + classes and predefined objects for input and output, the
file iostream.h must be included:
in t mainO
return EXIT_SUCCESS;
}
c in .g e t( b u ff, max_line )
does not store the terminating newline and it does not remove it from the
standard input. For this reason, the following is an infinite loop:
char buff [ 80 ] ;
20. After a manipulator is placed into the stream, all subsequent input or
output is formatted accordingly except for the field width, which reverts
to zero after a string or number is printed. Do not assume that at the end
of a statement, all input/output reverts to default settings. For example,
in the following code, the input is written in decimal, then in hexadecimal
twice:
in t n = 100;
cout « n « endl;
cout « hex « n « endl;
cout « n « endl; // s t i l l hex
www.MathSchoolinternational.com
C O M M O N PR O G R A M M IN G ERRORS 67
ios::sync_with_stdio
#include <stdio.h>
#include <iostream.h>
#include <stdlib.h >
int m a i n O
{
int a = 2 , b = 5 ;
// * * * * * RISKY * * * * *
p rin tf ( "*/,d ", a ) ;
cout « b « endl;
return EXIT_SUCCESS;
>
is risky; but
#include <stdio.h>
#include <iostream.h>
#include <std lib.h >
int m a i n O
int a = 2 , b = 5 ;
// * * * * * OK * * * * *
ios::sync_with_stdio();
printf ( "'/.d ", a ) ;
cout << b << endl;
return EXIT_SUCCESS;
>
is acceptable.
www.MathSchoolinternational.com
68 CH APTER 2 BASIC C + +
Program m in g Exercises
2.1. Write a program that reads integers from the standard input until the
end of the file and then prints the largest and smallest values.
2.2. Write a program that echoes the standard input to the standard output,
except that each tab is replaced by the appropriate number of spaces.
Assume that tabs are set every 8 columns, unless the user specifies a
different tab setting on the command line.
in t x = 6;
d b l( x ) ;
cout « x; // output is 12
Write a main function that invokes dbl to demonstrate that dbl is working
properly.
struct twodim {
in t r;
in t c;
flo a t * a;
>;
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 69
2.6. Given
struct numeric {
long a [ 10 ] ;
>;
struct s trin g {
char a [ 10 ] ;
>;
n++;
www.MathSchoolinternational.com
CHAPTER 2 BASIC C + +
( CurrentYr
NextYr = Rate • CurrentYr » ^1 - ^ 5 5 5 5 5 5 "
which calculates next year’s population of, say, waxwings on the basis
of the current population and the growth rate. The variable Rate con
trols the growth rate and takes on values between 0 and 4. The variable
CurrentYr gives the current value of the waxwing population and is as
sumed to have a value between 0 and 1,000,000. The variable NextYr
gives the value of the waxwing population one year later. The formula
guarantees that NextYr will also have a value between 0 and 1,000,000.
For example, if CurrentYr is 100,000 and Rate is 2.6, NextYr is 234,000.
Now suppose that we initialize CurrentYr to 100,000 and Rate to 2.6 and
compute the waxwing population 25 years hence by solving for NextYr,
setting CurrentYr to NextYr, solving again for NextYr, and so on for 25
iterations. The waxwing population turns out to be roughly 615,385. We
get the same result if we initialize CurrentYr to, say, 900,000 but leave
Rate set to 2.6. In fact, the population stabilizes at roughly 615,385 for
any value of CurrentYr so long as Rate is 2.6! For some values of Rate,
the population oscillates. For example, if Rate is 3.14, after about 40
years the waxwing population takes on this pattern from one year to the
next: 538,007 to 780,464 to 538,007 to 780,464, and so on indefinitely.
For Rate equal to approximately 3.57, however, the population does not
stabilize or oscillate but rather varies randomly from one year to the next.
Write a program that prompts the user for Rate, an initial CurrentYr,
and a number of iterations. On each iteration, the program prints the
year and the current waxwing population.
2.9. Simulate the Monty Hall puzzle, which gets its name from the host of
the television game show Let’s Make a Deal. The puzzle involves a game
played as follows. A contestant picks one of three doors; behind one of the
doors is a car, and behind the other two are goats. After the contestant
picks a door, the host opens an unpicked door that hides a goat. (Because
there are two goats, the host can open a door that hides a goat no matter
which door the contestant first picks.) The host then gives the contestant
the option of abandoning the picked door in favor of the still closed and
unpicked door. The puzzle is to determine which of three strategies the
contestant should follow:
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 71
2.10. This programming exercise is based on Lewis Carroll’s system for encod
ing and decoding text. We assume ASCII representation of characters.
The encoding and decoding use the following table:
Across the top and along the side we list, in order, the (printable) ASCII
characters blank (b l) through ~ (see Appendix A). The first row inside
the table is identical to the list across the top. Thereafter, each row is
the same as the previous row, except that each character is shifted one
position to the left, and the last character of a row is the first character
of the preceding row.
To encode text, a string, called a code string, is chosen arbitrarily. To
illustrate the encoding method, we assume that the code string is Walrus
and the text to encode is
Meet me in S t . Louis
Characters other than blank through ~ are not altered. We write the code
string, repeated as often as necessary, on top of the text to be encoded:
WalrusWalrusWalrusWa
Meet me in S t. Louis
www.MathSchoolinternational.com
CHAPTER 2 BASIC C + +
The pairs of characters WM, ae, l e , ..., one on top of the other, are used
as indexes into the preceding table. The encoded text results from finding
the entries in the table that correspond to these pairs. The entry in row
W and column M is "/,, so the first character of the encoded text is '/,. The
entry in row a and column e is G; the entry in row 1 and column e is R;
and so on. Thus the text is encoded as
7,GRgua=aVauGLol?eiAU
www.MathSchoolinternational.com
Chapter 3
Classes
73
www.MathSchoolinternational.com
74 CH APTER 3 CLASSES
class members
www.MathSchoolinternational.com
CREATING CLASSES 75
A typical class has several data members that provide the internal repre
sentation and several methods that define operations on the data members.
A data member is defined inside the class declaration, just as a struct mem
ber is defined inside a struct declaration. A method, too, may be defined
inside the class declaration, in which case the method is inline regardless of
whether the keyword in lin e is used. However, it is legal merely to declare
a method inside the class declaration and then to define the method outside
the class declaration. We illustrate with an example.
www.MathSchoolinternational.com
CH APTER 3 CLASSES
char, and String, where String is a user-defined data type. The data type
String must be visible to the declaration of class Win for a variable of type
S tring to be included in class Win.
The class declaration also specifies three methods: moveWin, getName,
and minWin. Method minWin is defined inside the declaration, whereas
methods moveWin and getName are only declared inside the class declara
tion. Functions declared but not defined inside the class declaration must
be defined outside the declaration. A function defined inside a class decla
ration is thereby inline, even if the keyword in lin e is not used. Method
minWin is thus inline. (Recall that the code for inline functions, including
methods, is substituted in place.)
The method moveWin is declared but not defined inside Win’s declara
tion. Therefore, moveWin must be defined elsewhere. The scope resolution
operator must be used to indicate that moveWin is a Win method rather than
a method in some other class or even a toplevel function (i.e., a function that
is not a method in any class). The method’s proper name is Win: :moveWin.
Here is how it might be defined:
// define W in::moveWin
void W in::moveWin( short new.x, short new_y )
{
x = new_x;
y = new_y;
>
Whether to define a method inside or outside a class declaration is judg
ment that should involve two considerations. First, a method defined inside
a class declaration is automatically inline. Second, defining long methods in
side a class declaration may clutter the declaration. Even a method defined
outside the declaration can be made inline by using the keyword in lin e. We
can revise our example by moving the definition of method minWin outside
Win’s declaration and keep it inline:
// Window displayed on a screen
class Win {
int id; // unique id e n t ifie r
short x, y; // cartesian coordinates
short width,height; // dimensions in plane
char v is ib le ; // 1 == yes, 0 — no
String name; // user-defined type
p u b lic :
void moveWin( short, short ) ;
char* getName( ) ;
void minWinO ; // declare minWin
>;
www.MathSchoolinternational.com
CREATING CLASSES 77
width = height = 0;
}
void f ( Win w )
Our class declarations typically place the data members together and the
methods together, and our declarations typically have the methods follow
the data members. This is a matter of style. Data members and methods
may occur in any order within the declaration. However, it is important to
keep in mind that any class member, data member or method, defaults to
p riva te if a class is declared with the keyword class.
www.MathSchoolinternational.com
78 CH APTER 3 CLASSES
class C {
flo a t r; // defaults to private
p u b lic :
int ml( ) ; // public
flo a t m 2(); // public
p riv a te :
char c; // private
p u b lic :
void m 3(); // public
int z; // public data member!
p riv a te :
char cc; // private
>;
intermixes data members and methods. □
www.MathSchoolinternational.com
3.1 CREATING CLASSES 79
The keyword union has the same effect as struct in creating classes: data
members are public by default. Data members in a class created with the
keyword union share storage, just as union members do in C. The storage
shared is enough to accommodate the largest data member in the union.
Classes might be created with the keyword union when there is a need to
economize on storage.
>;
www.MathSchoolinternational.com
80 CH APTER 3 CLASSES
in t mainO
{
class Inside {
>;
>
class Outside is visible from where its declaration occurs to the end of the
file; hence, Outside is visible in main. By contrast, class Inside is visi
ble only within main’s body because its declaration occurs only within that
block. We say that class Outside has file scope, whereas class Inside has
only block scope. □
Exam ple 3.1.7. Assume that our declarations for classes Cl, C2, and C3
occur in the header file classes, h and that we need access to these classes in
the file code.cc. We include the preprocessor directive
#include " classes.h"
in file code.cc to make the classes visible. The #include gives file scope to
all the class declarations in the #included file. □
Exercises
1. If a class is created with the keyword class, are its data members private
by default and its methods public by default?
2. If a class is created with the keyword struct, are only its data members
public by default?
3. Create a class with the keyword union. Make the data members private
and the methods public.
4. In a class declaration, must the data members come before the methods?
5. Change the class declaration so that the data members are p riva te but
the methods are public:
www.MathSchoolinternational.com
CREATING CLASSES 81
class Dilemma {
enum Horn { Hornl, Horn2 >;
p u b lic:
in t horn_crushed( Horn ) ;
void reso lve_p ea cefu lly ( ) ;
char h orn l[ 100 ] ;
chax horn2[ 100 ] ;
>;
6. Is this class declaration legal?
class Dilemma {
enum Horn { Hornl, Horn2 } ;
p u b lic:
in t horn_crushed( Horn ) ;
p r iv a te :
char h orn l[ 100 ] ;
char horn2[ 100 ] ;
p u b lic:
void re s o lv e _ p e a c e fu lly ();
>;
7. Explain the difference between the visibility of class members in these
two class declarations:
// struct keyword
struct Dilemma {
enum Horn { Hornl, Horn2 } ;
in t horn_crushed( Horn ) ;
char h orn l[ 100 ] ;
char horn2[ 100 ] ;
void r e s o lv e _ p e a c e fu lly ();
>;
// class keyword
class Dilemma ■[
enum Horn { Hornl, Horn2
in t horn_crushed( Horn ) ;
char h orn l[ 100 ] ;
char horn2[ 100 ] ;
void reso lve_p ea cefu lly ( ) ;
>;
8. Write a definition for a variable of type Dilemma (see Exercise 7).
9. Write a code slice that invokes method horn_ crushed on the variable you
defined in Exercise 8.
www.MathSchoolinternational.com
82 CH APTER 3 CLASSES
class Dilemma {
enum Horn { Hornl, Horn2 >;
in t horn_crushed( Horn ) ;
char h orn l[ 100 ] ;
char horn2[ 100 ] ;
void re s o lv e _ p e a c e fu lly ();
>;
i n t m a in O
{
Dilemma d l;
strcpy( d l.h orn l, "The barber shaves h im self." ) ;
>
11. Write a declaration for class Employee that has at least six data members
and at least six methods.
12. Write code slices that define Employee objects and invoke each of the
methods.
14. Must a class have the same number of data members and methods?
16. Must the data types of a class’s data members be the same?
class C {
p u b lic:
void w r ite ( ) ;
>
www.MathSchoolinternational.com
3.2 SAM PLE APPLIC A TIO N : A STACK CLASS 83
the top.
S o lu tio n _______________________________________
We create a Stack class with methods that allow the user to push an element
onto the Stack (insertion), pop an element off the Stack (deletion), and
print all the Stack elements top to bottom. To ensure Stack integrity,
we first check that the Stack is not full before pushing and that is not
empty before popping. Stack elements are chars. We practice information
hiding by making a Stack’s internal representation private. We practice
encapsulation by including methods within a Stack.
C + + Implementation
class Stack {
enum { FullStack = MaxStack, EmptyStack = -1 } ;
enum { False = 0, True = 1 } ;
char item s[ MaxStack ] ;
in t top;
p u b lic:
// methods
void i n i t ( ) ; // set top
void push( char ) ; // add an item
char popO ; // remove an item
in t empty( ) ; // no elements?
in t f u l l O ; // too many elements?
void dump_stack(); // top to bottom
>;
void Stack:: i n i t ()
{
top = EmptyStack;
>
// any room le f t ?
i f ( fu llO )
retu rn;
// i f s o , move top and add item
item s[ ++top ] = c;
www.MathSchoolinternational.com
84 CH APTER 3 CLASSES
char Stack::pop()
-C
// anything to remove?
i f ( empty() )
return EmptyFlag;
e ls e
return item s[ top— ] ;
>
in t S t a c k ::fu ll()
in t St ack: : empty()
if ( top == EmptyStack ) {
cerr « "Stack empty" « endl;
return True;
>
else
return False;
>
void Stack::dump_stack()
{
fo r ( in t i = top; i >= 0; i — )
cout « item s[ i ] « endl;
>
After class Stack has been declared, we can define Stack objects in the same
way that we define, say, in t or flo a t objects: through variable definitions.
A code slice such as
Stack s i; // define a Stack object
s l.in itO ; // invoke s i ’ s in it method
www.MathSchoolinternational.com
3.2 SAM PLE A PPLIC A TIO N : A STACK CLASS 85
sl.push( ’ a’ ); // in sert a
si.push( ’ b’ ); // in sert b
cout « s i.p o p ( ) ; // remove and p rin t b
sl.push( , c >) ; // in sert c
cout « s l.p o p O ; // remove and p rin t c
si.push( ’b’ ); // in sert b
sl.push( ’ c ’ ); // in sert c
si.dum p_stack(); // p rin t cba, removingnone
s i .in it ();
class Stack {
// * * * * * ERROR: I l l e g a l in it ia liz a t io n
int top = EmptyStack;
>;
If a member is to be initialized when it is created, a method must be used.
Normally, the programmer would access Stack objects through methods
push, pop, and dump_stack. All three methods are public, which ensures
that the programmer can invoke them wherever class Stack is visible in the
program. There is no need for the programmer to access directly a Stack’s
internal representation, in this case the array of char cells that store the
Stack’s elements; therefore, items is private, which promotes program
security through information hiding. A code slice such as
void f ( )
Stack s;
s . in it O ;
s.push( ’ A’ ) ; // ok
>
www.MathSchoolinternational.com
86 CH APTER 3 CLASSES
occur inside the class declaration and so are restricted in scope; because the
enums are private, the constants FullStack, EmptyStack, True, and False
axe accessible only by Stack methods or frien d functions. The enums have
class scope. The enum constant EmptyStack, with value -1, is used to
initialize data member top. Before a char is pushed onto a Stack, method
push first checks whether the Stack is full by invoking method fu ll. If the
Stack is not full, the preincremented top serves as index into items, an
array of char that represents the Stack:
void Stack::push( char c )
{
// any room le ft ?
i f ( f u llO )
return;
Exercises
1. Write a method view_top that prints the top item on the Stack without
removing it from the Stack.
www.MathSchoolinternational.com
3.3 A F IR S T LO O K A T CONSTRUCTORS A N D DESTRUCTORS 87
3. Take and defend a stand for or against the proposition that methods f u l l
and empty ought to be p riva te in class Stack.
4. Write a method fin d that takes a char argument and returns 1 if the
char is currently somewhere in the Stack and 0 otherwise. The method
must not alter the Stack.
Constructors
Example 3.3.1. The Stack class of Section 3.2 has an in it method that
initializes data member top to EmptyStack:
void S tack:: i n i t ( )
{
top = EmptyStack;
>
Correct Stack manipulation through pushes and pops requires that top be
initialized to EmptyStack. The problem is that the programmer is responsi
ble for invoking in it explicitly in a code slice such as
Stack s i; // create a stack
s i . i n i t ( ) ; // i n i t i a l i z e the stack
... / / d o pushes and pops
If the programmerforgets to invoke in it, then top contains junk;that is,
top contains, instead of EmptyStack, some random value that is almostsure
to cause problems during Stack manipulation. □
www.MathSchoolinternational.com
CH APTER 3 CLASSES
Exam ple 3.3.2. We amend the Stack class by replacing in it with a con
structor that initializes top to EmptyStack when a Stack is created.
class Stack {
enum { FullStack = MaxStack, EmptyStack = -1 >;
enum { False = 0, True = 1
char item s[ MaxStack ] ;
in t top;
p u b lic :
// methods
StackO; // set top to EmptyStack
void push( char ) ; // add an item
char popO ; // remove an item
in t empty( ) ; // no elements?
in t f u l l O ; // too many elements?
void dump_stack(); // top to bottom
top = EmptyStack;
>
Now that Stack has constructor Stack: :Stack, the programmer no longer
has to worry about invoking a method such as in it. Instead, the compiler
ensures that the constructor is invoked whenever a Stack is created. In this
example, the constructor initializes top to EmptyStack. In general, a con
structor can do whatever initializing work is appropriate. □
A class may have more than one constructor, which overloads the con
structor’s name. Even in this case, the compiler rather than the programmer
typically generates a call to whatever constructor is appropriate.
www.MathSchoolinternational.com
A F IR S T LO O K A T CONSTRUCTORS AN D DESTRUCTORS 89
Example 3.3.3. In the following code slice, the class Color has two con
structors.
class Color {
flo a t red;
flo a t green;
flo a t blue;
p u b lic:
ColorO { red = green = blue = 0.0; >
C olor( flo a t , flo a t , flo a t ) ; // parameterized
>;
www.MathSchoolinternational.com
90 CH APTER 3 CLASSES
Constructor Initialization
www.MathSchoolinternational.com
A F IR ST LO O K A T CONSTRUCTORS AND DESTRUCTORS 91
class C2 {
in t iC2;
flo a t fC2;
p u b lic:
// in it ia liz a t io n in constructor header
C2( in t a l, flo a t a2 ) : iC2( al ) , fC2( a2 ) { }
>;
class C3 {
in t iC3;
flo a t fC3;
p u b lic:
// mixed in it ia liz a t io n
C3( in t a l, flo a t a2 ) : iC3( al ) { fC3 = a2; }
>;
illustrate different styles of data member initialization. C l’s constructor does
all initialization in its body using the assignment operator. By contrast, C2’s
constructor initializes data members in its header rather than its body. The
expression
iC2( al )
in C2’s header initializes data member iC2 to parameter al. Note that the
two header initializations are separated by a comma and that C2’s body is
empty because all the work has been done already in the header. C3’s con
structor has a mixed style: iC3 is initialized in the header, whereas fC3 is
initialized in the body. □
www.MathSchoolinternational.com
92 CH APTER 3 CLASSES
p u b lic :
X( char* m ) { strcpy( moniker, m ) ; >
>;
class Y {
in t num;
X x; //X object nested in Y
p u b lic :
Y( in t a l , char* a2 ) : num( a l ) , x ( a 2 ) { >
>;
must initialize data member x in its header since x is an object in another
class. □
C opy Constructors
www.MathSchoolinternational.com
3.3 A F IR S T LO O K A T CONSTRUCTORS AN D DESTRUCTORS 93
Convert Constructors
www.MathSchoolinternational.com
CH APTER 3 CLASSES
stores a time and has a method print_tim e to print the time in the form
xx:xx XX
www.MathSchoolinternational.com
3.3 A F IR S T LO O K A T CONSTRUCTORS A N D DESTRUCTORS 95
p u b lic:
CO;
>;
C: :CO
{
tex t = new char[ 20 ] ; // a llo ca te
strcpy( te x t, // i n i t i a l i z e
"North By Northwest" ) ;
>
y
C c; // create a C object
has a data member te x t of type char*. The constructor C: :C dynamically
allocates storage, sets te x t to the address of the first cell, and then initial
izes the storage to a character string. □
If a class has no constructor, then the class’s data members are not initialized
automatically when a class object is created.
www.MathSchoolinternational.com
96 CH APTER 3 CLASSES
class C {
in t dml;
in t dm2;
>;
C c;
class C has no constructor. Accordingly, data members c . dml and c . dm2 are
not initialized when c is defined. The programmer rather than the compiler
now assumes responsibility for initializing the data members. □
Constructors axe invoked whenever and wherever class objects are defined,
which means that constructors should be public so that they can work
correctly.
in t mainO
>
the default constructor is private, which means that it cannot be invoked
in main, which is neither a method nor a frien d of C. The obvious solution
is to make all constructors public, including the default constructor. □
Destructors
www.MathSchoolinternational.com
A F IR S T LO O K A T CONSTRUCTORS AN D DESTRUCTORS 97
>
the programmer dynamically allocates a billion char cells but forgets to re
lease them (with a call to the library function fr e e ) before control leaves
big_garbage. Therefore, b s. strin g becomes a dangling pointer. Because
structure variable bs has auto as its default storage class, bs and its mem
ber variables can be accessed only within big_garbage. Once control leaves
big_garbage, the billion char cells to which b s. strin g points remain allo
cated but the program has no way to access them. Each time big_garbage
exits, it leaves behind big garbage— a billion bytes worth. □
www.MathSchoolinternational.com
CH APTER 3 CLASSES
class BigStr {
char* strin g;
long size ;
p u b lic :
B ig S trO ; // constructor
"B igS trO { d e le te [ ] strin g; } // destructor
>;
BigStr: :BigStrO
d e le t e [ ] strin g;
instead of
www.MathSchoolinternational.com
3.3 A FIR ST L O O K A T CONSTRUCTORS AN D DESTRUCTORS 99
d elete strin g;
because strin g points to the first in an aggregate of cells rather than to a
single, standalone cell. □
// constructor
BigStr: :B igStrO
{
strin g = new chart OneBillion + 1 ] ;
fo r ( long i = 0; i < OneBillion; i++ )
s tr in g [ i ] = ’ $’ ;
s tr in g [ OneBillion ] = ’ VO’ ;
size = OneBillion;
>
// destructor
BigStr: : "B igStrO
{
d e le te [ ] strin g;
>
□
www.MathSchoolinternational.com
100 CH APTER 3 CLASSES
must be the tilde ("). If a destructor is defined outside the class declaration,
then its name must include the scope resolution operator, as Example 3.3.15
illustrates. A destructor never has arguments. Accordingly, the argument
list must be empty in a destructor’s definition or declaration.
A class has only one destructor and the programmer is responsible for
writing it. The compiler does not provide a destructor if the programmer
does not write one. Destructors are not allowed to have arguments because
their job is highly specialized: a destructor simply releases any storage that
a constructor dynamically allocates before such storage can become garbage.
To perform this task, a destructor needs no arguments. To prevent a de
structor from trying to perform any other task, C + + disallows destructors
with arguments. Destructors, again like constructors, perform tasks that
require no return value, especially because the programmer typically does
not explicitly invoke a destructor. Invoking a destructor is normally left to
the compiler.
Exercises
2. Write the declaration for the default constructor for class Mystery.
www.MathSchoolinternational.com
3.3 A F IR S T LO O K A T CONSTRUCTORS A N D DESTRUCTORS 101
class C {
char* p tr;
p u b lic:
void C ( ) ;
>;
class C {
chax* p tr;
p u b lic:
CO;
C( char* c ) { . . . }
C( in t c ) { . . . >
C( char* c ) { . . . }
>;
6. Can a class have more than one destructor? Explain why or why not.
class C {
char* p tr;
p u b lic:
CO;
CO;
>;
class C {
in t x;
p u b lic:
C( in t x = 4, y = 6 ) ;
>;
www.MathSchoolinternational.com
102 CHAPTER 3 CLASSES
class C {
in t x;
p u b lic:
C( C ) ; // copy constructor
>;
How should the copy constructor be declared?
12. One destructor might free storage with the d elete operator, whereas
another might free storage with the d elete [ ] operator. Explain the
difference.
13. If the programmer does not write a default constructor for a class, does
the compiler provide one?
14. If the programmer does not write a copy constructor for a class, does the
compiler provide one?
class C {
in t x;
p u b lic:
in t C (); // default
>;
16. If a class does not use any dynamically allocated storage, does it need a
destructor?
class C {
char* p tr;
p u b lic:
CO { ptr = new char[ 100 ] ; }
~C() { d e le te [ ] p tr; }
>;
void f ( )
C c l, c2, c3;
>
www.MathSchoolinternational.com
3.4 SAM PLE APPLIC A TIO N : A Z IP CODE CLASS 103
class C {
char* p tr;
p u b lic:
void ~ C ();
>;
20. Declare a class C that uses dynamically allocated storage and define the
destructor C: : ~C.
class C {
in t x;
const flo a t y;
p u b lic:
C( in t a l, flo a t a2 ) { x = a l; y = a2; >
>;
#include <stdio.h>
#include <iostream.h>
#include <string.h>
www.MathSchoolinternational.com
CH APTER 3 CLASSES
class ZipC {
char* code; // representation
p u b lic :
// constructors-destructor
ZipCO; // default
ZipC( const char* ) ; // from char*
ZipC( const unsigned long ) ; // from in teger
"ZipCO ; // destructor
void w r ite ( ) { cout « code « endl; }
void expand( const char* ) ;
>;
// d efau lt constructor
ZipC: :ZipCO
{
code = new char[ MinZip + 1 ] ; // +1 fo r terminator
fo r ( in t i = 0; i < MinZip; i++ )
code[ i ] = InitC har;
code[ i ] = ’ \0’ ;
}
in t len =
( s tr le n ( zip s tr ) < MaxZip ) ? s trle n ( z ip s tr ) :
MaxZip;
code = new char[ len + 1 ] ;
strncpy( code, z ip s tr, len ) ;
code[ len ] = ’ \0 ’ ;
>
www.MathSchoolinternational.com
3.4 SAM PLE A PPLIC A TIO N : A Z IP CODE CLASS 105
ZipC: : "ZipCO
d e le te [ ] code;
>
The class ZipC has code, a pointer to chairj as its single data member. The
three constructors set code to storage dynamically allocated with the new
operator. How much storage is allocated depends on the constructor. For
instance, the default constructor
// default constructor
ZipC: :ZipCO
www.MathSchoolinternational.com
CHAPTER 3 CLASSES
void f ( )
{
ZipC z l ; // default constructor
}
because z l ’s definition does not include an initializing value. Accordingly,
zl.c o d e points to MinZip + 1 chars, each holding InitChar, except for
the last, which holds a ’ \0 ’ . The constructor adds a null terminator to the
sequence of chaxs so that, for example, the user can invoke library functions
such as strlen or strcpy on the sequence. The user need not worry about
a null terminator because the constructor ensures that one is present.
The constructor ^ ^ O’1
ZipC::ZipC( const char* z ip s tr )
in t len =
( s tr le n ( z ip s tr ) < MaxZip ) ? s tr le n ( z ip s tr ) :
MaxZip;
code = new char[ len + 1 ] ;
strncpy( code, z ip s tr , len ) ;
code[ len ] = ’ \0’ ;
>
converts a traditional C string to a ZipC object. The compiler would have
this constructor invoked in a code sequence such as
void g ()
■C
ZipC z2( "60607" ) ; // convert constructor
}
because z2’s definition includes the initializing value 60607 given as a char
acter string constant. In this case, the constructor would allocate six char
cells: five for the characters in “60607” and one for the null terminator.
This constructor ensures that the initializing value does not exceed MaxZip
characters in length. The constructor’s single parameter, zip s tr, has a
type qualifier of const to ensure that the constructor does not change the
characters to which z ip s tr points.
The last of the three constructors
ZipC::ZipC( const unsigned long zipnum )
•C
char b u ffe r [ BigZip + 1 ] ;
s p r in tf( b u ffer, "*/,0*ld", MinZip, zipnum ) ;
b u ffe r [ MinZip ] = ’ \0’ ;
code = new char[ s trle n ( bu ffer ) + 1 ] ;
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A Z IP CODE CLASS 107
>
The constructor uses sp rin tf to convert the integer into a null-terminated
array of char with length MinZip. For this purpose, the constructor uses an
array of BigZip + 1 char cells to ensure sufficient storage for the conver
sion. The constructor then allocates sufficient char cells to hold the string
that represents the ZipC object, including a cell for the ’\0’.
Class ZipC has three constructors, each named ZipC: :ZipC. Yet there
is never any question about which of the three is invoked in a particular
situation. If an object of type ZipC is defined without an initializing value,
then the default constructor is invoked. If such an object is defined with an
initializing string value, then the char* constructor is invoked. If such an
object is defined with an initializing integer value, then the long constructor
is invoked. In general, the compiler uses the number and type of initial values
to determine which constructor should be invoked. It is an error to have two
constructors that expect identical arguments. In our example, there can be
only one constructor that expects a single long argument.
The destructor for class ZipC
ZipC: : "ZipCO
{
d e le te [ ] code;
>
deallocates whatever storage a constructor allocates before such storage can
become garbage. For example, in the code slice
void f ( )
-C
ZipC z ip ( "60607-1312" ) ; // 11 bytes allocated
www.MathSchoolinternational.com
108 CHAPTER 3 CLASSES
first place. The destructor uses the operator d elete [ ] to free whatever
storage the constructor has allocated, which in this code slice is 11 bytes.
The compiler, not the programmer, takes responsibility for invoking the de
structor.
Class ZipC also has a method, defined within the class declaration and
therefore implicitly in lin e, to print the zip code. This method could be
invoked as follows:
void f ( )
ZipC z ip ( "60607-1312” ) ;
z ip .w r ite O ; // prints 60606-1312
>
As ZipC presently stands, the only way to print z ip . code inside function f
is to use method zip .w rite because
• z i p . code is p riva te and therefore accessible only to ZipC methods or
frie n d functions (see Section 3.7).
• f is neither a method nor a frien d function of ZipC.
By contrast, method zip .w rite is accessible in f because all of ZipC’s meth
ods are public.
Finally, method expand takes a zip code suffix, such as 1234, and ap
pends it to a standard zip code such as 60607, inserting a hyphen between
the code and the suffix. Of course, many other methods may be appropri
ate to support zip code operations. All such methods should provide users
with desired functionality without requiring users to know the underlying
representation of a ZipC. In short, ZipC is an abstract data type.
Exercises
1. Write a method shorten that shortens a 9-digit zip code such as 60607-
1234 to a 5-digit zip code. The 5-digit zip code then becomes the official
zip code.
2. Write a method sameZip that checks whether two ZipCs are identical.
www.MathSchoolinternational.com
A F IR S T LO O K A T CLASS O PERATOR OVERLOADING 109
>;
in which strin g points to dynamically allocated storage that can hold null-
terminated chars. Now suppose that we store “bob” in String object s i
and “carol” in String object s2. We would like the expression
s i + s2 // String concatenation
to represent String concatenation. We therefore overload the + operator,
the built-in version of which expects numeric rather than String operands.
Here is a sketch:
class String {
char* strin g;
p u b lic:
Stringfe operator+( const String ) const;
>;
www.MathSchoolinternational.com
CHAPTER 3 CLASSES
Exam ple 3.5.2. We expand Example 3.5.1 by overloading the > operator
so that it can be used to compare two String objects on the basis of their
lexicographical order.
class String {
char* strin g;
p u b lic :
in t operator>( const String s ) const; // declaration
>;
// d e fin itio n
in t S tr in g ::operator>( const String s ) const
{
return strcmp( strin g , s .s trin g ) > 0;
}
Suppose that s i.s t r in g points to “lettuce” and that s2 .strin g points to
“lattice” , where s i and s2 are String objects. The expression
s i > s2
would evaluate to 1 because “lettuce” is lexicographically greater than “lat
tice.” The overloaded > operator could be used in code slices such as
if ( s i > s2 )
e ls e
www.MathSchoolinternational.com
3.5 A F IR S T L O O K A T CLASS O PERATOR OVERLOADING 111
Exercises
class Diet {
char word[ 100 ] ;
char d e fin it io n [ 1000 ] ;
public:
void w r ite ( ) ;
in t operator>( const Diet ) const; // declaration
};
// d e fin itio n
in t D ic t ::> ( const Diet d ) const
{
return strcmp( word, d.word ) ;
}
3. For the overloaded operator in Exercise 1, give code slices in which the
operator is invoked using method syntax. ;i- /' , , ■!& '/
4. For the overloaded operator in Exercise 1, give code slices in which the
operator is invoked using operator syntax. , ( ( /j J J I s
6. Explain the difference between operator and method syntax for an over
loaded class operator. Give an example of each.
www.MathSchoolinternational.com
112 CHAPTER 3 CLASSES
class Diet {
chair word[ 100 ] ;
char d e fin it io n [ 1000 ] ;
p u b lic:
void w r ite ( ) ;
in t o p era to r.( const Diet ) const; // declaration
// d e fin itio n
in t D ie t ::o p era to r.( const Diet d ) const
{
>
v ■ •r
10. Which C + + operators, if any, may not be overloaded? - - •'
s '
S o lu tio n ______________________________________________________________________
We create class Complex with two double data members to represent the real
and imaginary components of a complex number. We extend the standard
arithmetic operators such as + and * to Complex objects. We practice infor
mation hiding by making a Complex’s data members private. We practice
encapsulation by including methods, including constructors and overloaded
operators, in Complex.
#include <iostream.h>
class Complex {
double re a l;
double imag;
p u b lic :
// constructors
Complex( ) ; // default
Complex( double ) ; // re a l given
Complex( double, double ) ; // both given
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A C O M PLEX NUM BER CLASS
// other methods
void w r ite ()
{
cout « "re a l == " « re a l «
"imaginary == " « imag « endl
>
// operator methods
Complex operator+( const Complex ) const;
Complex op erator-( const Complex ) const;
Complex operator*( const Complex ) const;
Complex operator/( const Complex ) const;
>;
// default constructor
Complex::Complex()
{
re a l = imag = 0.0;
}
re a l = r; imag = i ;
>
return Complex( re a l - c .r e a l,
imag - c . imag ) ;
www.MathSchoolinternational.com
114 CHAPTER 3 CLASSES
return Complex(
( re a l * c .r e a l + imag * c.imag ) / abs_sq,
( imag * c .re a l - re a l * c . imag ) / abs_sq ) ;
>
The class Complex has three constructors but no destructor because it does
not use dynamically allocated storage. The default constructorinitializes
datamembers re a l and imag to 0.0. The one-argument constructor ini
tializes re a l to the double parameter and imag to 0.0. The two-argument
constructor initializes the data members to the respective parameter values.
The three constructors could be combined into one as:
Complex: : Complex( double r = 0.0, double i = 0.0 )
re a l = r; imag = i ;
>
Our main interest lies in the arithmetic operators overloaded for the
class. The purpose of the overloading is to extend the standard arithmetic
operators to Complex numbers, thus allowing code such as
int mainO
{
Complex c l ( 7.7, 5.5 ) ;
Complex c2( 4.4, 3.3 ) ;
Complex c3;
>
In the declarations and definitions for the overloaded arithmetic opera
tors, the keyword const occurs twice, once in the formal parameter list and
then at the end:
www.MathSchoolinternational.com
3.6 SAM PLE A PPLIC A TIO N : A C O M PLEX NUM BER CLASS 115
The const in the parameter list ensures that the argument’s value will not
be altered during the addition, and the const at the end ensures that the
method’s invoker— the Complex object whose operator+ is invoked on the
argument— will not be altered during the addition. The operator returns
the Complex result of the addition but does alter the objects involved in the
addition.
Exercises
1. Overload the += operator for class Complex and show a code slice that
uses the overloaded operator.
2. Overload the -= operator for class Complex and show a code slice that
uses the overloaded operator.
3. Overload the /= operator for class Complex and show a code slice that
uses the overloaded operator.
4. Overload the *= operator for class Complex and show a code slice that
uses the overloaded operator.
5. In the declaration
int mainO
>
www.MathSchoolinternational.com
116 CHAPTER 3 CLASSES
>;
Except for being able to access one or more class’s private members, a frien d
function is no different from any other function.
There are three main reasons to use frien d functions:
• To allow a library function access to the private members of a class.
• To allow a function to access the private members of two or more classes.
(If a function needs access to the private members of only one class, it
should be a method.)
• To allow more flexible operator overloading.
Because a frien d function is not a method and still has access to p rivate
class members, a frien d function violates a strict interpretation of object-
oriented principles. Accordingly, frien d functions are controversial and
open to misuse. We recommend using frien d functions only when abso
lutely necessary. We illustrate each use of frien d functions.
Consider the class C that has a p rivate data member of type char*:
class C {
char* strin g;
p u b lic :
C( char* s )
in t mainO
{
C c l ( "tcp/ip" );
www.MathSchoolinternational.com
3.7 FR IEN D FUNCTIONS 117
int mainO
C c l ( "tcp/ip" ) ;
in t len = s tr le n ( c l.s t r in g ) ; // ok
>
frien d s o f T w o or M o re Classes
Example 3.7.1. Consider a version of the Stack class (see Section 3.2)
designed for Complex objects rather than chars:
class Complex; // makes class Complex
// v is ib le to ComplexStack
class ComplexStack {
class Complex {
double re a l;
www.MathSchoolinternational.com
118 CHAPTER 3 CLASSES
double imag;
p u b lic :
cout « endl;
>
In the original Stack class, dump_stack is a method. Here dump_stack is
a frie n d of ComplexStack and a frien d of Complex because dump_stack
needs access to ComplexStack’s private member items and to Complex’s
p riv a te members re a l and imag. In the original Stack class, dump_stack
needs access only to p rivate member items in Stack itself and so is best
implemented as a method.
Note that we must declare Complex
class Complex; // makes class Complex
// v is ib le to ComplexStack
class ComplexStack {
Exam ple 3.7.2. Operator functions in class Complex could have been im
plemented as friends rather than as methods. For example,
class Complex {
double re a l;
double imag;
p u b lic :
// constructors
ComplexO; // default
www.MathSchoolinternational.com
3.7 FRIEN D FUNCTIO NS 119
// friends
frien d Complex operator+( const Complex, const Complex ) ;
};
The declaration of operator+ contains the keyword friend, but the op
erator’s definition does not. Note, too, that the operator’s name is sim
ply operator+ rather than Complex: : operator+. Whether operator+ is a
method or a friend, its invocation looks exactly like the method’s invocation
when operator syntax is in use:
in t mainO
>
If operator+ is a frien d rather than a method, however, then method
syntax cannot be used. This code is illegal for the frie n d version
c3 = c l . operator+( c2 ) ; // * * * * * ILLEGAL fo r frien d
because operator+ is not a c l method. However, the code
c3 = operator+( c l, c2 ) ; // le g a l fo r frien d
is legal. □
>
www.MathSchoolinternational.com
120 CHAPTER 3 CLASSES
One class’s method may be another class’s friend, or classes may share a
function as a friend. Yet these and related uses of frien d functions strain
the style of object-oriented programming in C + + . Some object-oriented
languages allow only methods to access data members as a way of enforc
ing information hiding. C + + gives the programmer flexibility by allowing
frie n d functions as well as methods to access a class’s p riva te members,
but we recommend that frien d functions be used sparingly. The normal
access to a class’s p riva te members should be through its methods.
Exercises
1. Create a class and test whether you can make main a frie n d function of
this class.
2. Overload all the operators for class Complex as frie n d functions rather
than as methods.
3. Explain why the extensive use of frien d functions may compromise the
spirit of object-oriented programming.
4. On your system, find the header file complex.h. (On UNIX systems, it is
likely in the directory /usr/include and in Borland C + + it is likely in the
IN CLUD E subdirectory.) Check whether the arithmetic operators have
been overloaded as frien d functions or as methods.
www.MathSchoolinternational.com
.8 ASSERTIONS A N D P R O G R A M CORRECTNESS 121
in t mainO
{
Complex c l ( 111.0, 999.0 ) ;
Complex c2;
c2 = c l + 777.0;
c2 = 888.0 + c l;
c2 = 777.0 + 888.0;
>
in t mainO
{
Complex c l ( 1.0, 1.0 ) ;
Complex c2( 3.0, 3.0 ) ;
Complex c3;
c3 = c l + c2;
c3 = c l .operator+( c2 ) ;
c3 = + ( c2, c l ) ;
c3 = operator+( c l, c2 ) ;
>
www.MathSchoolinternational.com
122 CHAPTER 3 CLASSES
class Stack {
enum { FullStack = MaxStack, EmptyStack = -1 } ;
char items[ MaxStack ] ;
in t top;
p u b lic :
StackO ;
void push( char ) ;
char p o p ();
in t empty( ) ;
in t f u llO ;
>;
Stack::Stack()
■C
top = EmptyStack;
>
item s[ ++top ] = c;
>
char Stack::pop()
{
in t va l;
va l = items [ top— ] ;
return va l;
>
in t S t a c k ::fu ll()
www.MathSchoolinternational.com
ASSERTIONS AN D P R O G R A M CORRECTNESS 123
in t Stack::empty()
{
return top == EmptyStack;
>
In this version of the stack class, the user is responsible for checking for a
full stack before pushing an item on the stack and for checking for an empty
stack before popping an item off the stack.
Consider the method push. Because it is an error to push an item onto
a full stack, we assert that, when push is entered, the stack is not full. A
precondition for push is that the stack is not full. When push is exited, the
stack is not empty. A postcondition for push is that the stack is not empty.
Formally, we write
void Stack: :push( chair c )
item s[ ++top ] = c;
www.MathSchoolinternational.com
CH APTER 3 CLASSES
#include <iostream.h>
#include <assert.h>
#include <stdlib.h>
const in t MaxStack = 3;
class Stack {
enum { FullStack = MaxStack, EmptyStack = -1 } ;
char item s[ MaxStack ] ;
in t top;
p u b lic :
Stack( ) ;
void push( char ) ;
char popO ;
in t empty( ) ;
in t f u l l O ;
>;
Stack::Stack()
top = EmptyStack;
>
item s[ ++top ] = c;
chair S ta c k : :p o p ( )
{
in t v a l;
va l = item s[ top— ] ;
www.MathSchoolinternational.com
ASSERTIONS AN D P R O G R A M CORRECTNESS
return va l;
>
in t S t a c k ::fu ll()
{
return top + 1 == FullStack;
>
in t S tack::empty()
in t mainO
char resp , v a l;
Stack s;
fo r ( ; ; ) {
cout « "Push (2 ), Pop (1 ), Quit (0 ): 11;
cin » resp;
switch ( resp ) {
case ’ 2’ :
cout « "Push what value? ";
cin » v a l;
s.push( va l ) ;
break;
case ’ 1 ’ :
cout « "Pop va l = " « s.popO « endl;
break;
case ’ O’ :
return EXIT.SUCCESS;
>
}
>
www.MathSchoolinternational.com
CHAPTER 3 CLASSES
www.MathSchoolinternational.com
ASSERTIONS AND P R O G R A M CORRECTNESS 127
public method. For example, in the stack class, top must always be greater
than or equal to EmptyStack, and top must always be less than FullStack.
Thus the condition
top >= EmptyStack && top < FullStack
is a class invariant for the class Stack.
The following example shows the stack class with preconditions, post
conditions, and a class invariant.
class Stack {
enum { FullStack = MaxStack, EmptyStack = -1 } ;
char item s[ MaxStack ] ;
in t top;
p u b lic:
StackO ;
void push( char ) ;
char popO ;
in t empty( ) ;
in t f u l l O ;
>;
Stack: :StackO
{
top = EmptyStack;
a ssert( Stack_inv ) ;
>
www.MathSchoolinternational.com
128 CHAPTER 3 CLASSES
char Stack::pop()
in t v a l;
in t S tack::f u l l ()
a s s e rt( Stack_inv ) ;
return top + 1 == FullStack;
>
in t S tack::empty()
a s s e rt( Stack_inv ) ;
return top == EmptyStack;
>
top— ;
a s s e rt( Stack_inv ) ;
in the constructor and run the program with the main function of Example
3.8.1 added, the output is
Exercises
1. Supply preconditions, postconditions, and class invariants for the zip code
class of Section 3.4.
www.MathSchoolinternational.com
3.9 GENERIC CLASSES USING TEM PLATES 129
www.MathSchoolinternational.com
CHAPTER 3 CLASSES
item s[ ++top ] = c ;
>
www.MathSchoolinternational.com
GENERIC CLASSES USING TEM PLATES 131
Templates are similar to parameterized macros and serve the same gen
eral purpose. Indeed, early versions of C + + did not support templates and
so generic classes had to be constructed using parameterized macros. Tem
plates are far superior to parameterized macros because templates are part
www.MathSchoolinternational.com
132 CH APTER 3 CLASSES
of the language and are not handled by the preprocessor, as are parameter
ized macros. Templates are easier to write than parameterized macros, and
they are also easier to debug.
Generic classes provide yet another level of abstraction for the program
mer. Just as a class is an abstraction of an object, so a generic class is an
abstraction of a class (see Figure 3.9.1).
Exercises
public:
CO;
>;
>
2. Write a line that constructs a stack class using the generic class of Ex
ample 3.9.1 for a maximum stack size of 500 elements of type char.
3. Write a line that constructs a class stack class using the generic class of
Example 3.9.1 for a maximum stack size of 2000 elements of type String*.
4. Show the changes to the stack class of Example 3.9.1 if we add a method
top that returns, but does not remove, the item at the top of the stack.
www.MathSchoolinternational.com
CO M M O N PR O G R A M M IN G ERRORS 133
5. Revise the stack class of Example 3.9.1 so that it has one type parameter
Typ. Provide a constructor with an in t parameter size that dynami
cally allocates an array of size elements. Provide a default constructor
that dynamically allocates an array of 100 elements. Also provide an
appropriate destructor.
6. Write a line that constructs a stack class using the generic class of Exercise
5 to a maximum stack size of 100 elements of type flo a t.
7. Write a line that constructs a stack class using the generic class of Exercise
5 to a maximum stack size of 1000 elements of type Complex*.
2. The keyword class is not needed to create class objects. For example,
we write
class C {
>;
instead of
class C {
in t x ;
p u b lic :
C() { x = -999; }
>;
void f ( )
{
C c;
cout « c.x ; // * * * * * ERROR
>
www.MathSchoolinternational.com
134 CH APTER 3 CLASSES
>
is illegal.
>
7. It is illegal to have two constructors for the same class with exactly the
same argument types because there is then no way for the compiler to
determine which version of the constructor should be invoked.
class C {
// * * * * * ERROR: i l l e g a l in it ia liz a t io n
in t x = 1;
>;
class C {
in t x;
www.MathSchoolinternational.com
COM M ON PRO G RAM M IN G ERRORS 135
p u b lic:
// correct in it ia liz a t io n
CO { x = 1; >
>;
class C {
const in t x;
p u b lic:
// * * * * * ERROR: const in it ia liz e d in body
C( in t a ) { x = a; }
>;
class Z {
const in t x;
pu b lic:
// ok
Z( in t a ) : x ( a ) { }
>;
class N {
in t x;
p u b lic:
N( in t a ) { x = a; }
>;
class C {
in t y;
// * * * * * ERROR: i l l e g a l in it ia liz a t io n
N n( 0 ) ;
p u b lic:
CO { y = 0; >
>;
class C {
in t y;
N n;
p u b lic:
www.MathSchoolinternational.com
136 CHAPTER 3 CLASSES
// correct
CO : n( 0 ) { y = 0; >
>;
rather than
c l + c2 // OK
operator+( c l, c2 ) // OK
rather than as
// class member
.* // class member dereference
:: // scope resolu tion
?: // conditional
s iz e o f // s iz e in bytes
in t f ( char ) ;
>;
is a parameterized function and therefore requires a template. For this
reason,
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 137
is an error.
Also, the class is C< Typ > rather than C. Accordingly, the following is
an error:
>
// correct
template< class Typ >
in t C< Typ > : : f ( chax c )
{
www.MathSchoolinternational.com
CH APTER 3 CLASSES
3.3. Implement a Deck class that represents a deck of 52 cards. The public
interface should include methods to shuffle, deal, display hands, do pair
wise comparisons of cards (e.g., a Queen beats a Jack), and the like. To
simulate shuffling, you can use a random number generator such as the
library function rand.
25 / 5 + 4
and then evaluates the expression, printing the value. In this example,
the output would be
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 139
25 / 5 +
• Create a Set.
• Add a new element to a Set.
• Remove an element from a Set.
• Enumerate the elements in the Set.
• Compute the intersection of two Sets SI and S2, that is, the set
of elements that belong both to SI and to S2.
• Compute the union of two Sets SI and S2, that is, the set of ele
ments that belong to SI or to S2 or to both.
• Compute the difference of two Sets SI and S2, that is, the set of
elements that belong to SI but not to S2.
3.11. Implement a Bag class. A bag is like a set except that a bag may have
duplicates. For this exercise, the bag’s elements should be ints. The
public interface should support the counterpart operations given in Pro
gramming Exercise 3.9.
3.13. Create a Spaceship class suitable for simulation. One of the construc
tors should allow us to specify the Spaceship’s initial position in 3-
dimensional space, its trajectory, its velocity, its rate of acceleration, and
its target, which is another Spaceship. The simulation should track a
Spaceship’s movement every clock tick (e.g., every second), printing such
relevant data as the Spaceship’s identity, its trajectory, and so forth. If
you have access to a graphics package such as UNIX curses or Borland
C + + Graphics, you can add graphics to the simulation.
www.MathSchoolinternational.com
140 CH APTER 3 CLASSES
has numbered records, each of which has four fields (Social Security Num
ber, Last Name, Department, and Boss). The public interface should
allow a user to
• Create a table.
• Change a table’s structure by adding or removing fields.
• Delete a table.
• Add records to a table.
• Remove records from a table.
• Retrieve information from one or more tables at a time using a suit
able query language.
3.15. This exercise requires access to a basic graphics package such as UNIX
curses or the Borland C + + graphics library. Implement a GeoFig class
with methods that allow the user to draw on the screen geometric fig
ures such as lines, squares, circles, and the like. The public interface
also should include methods for creating, moving, enlarging, shrinking,
and destroying such objects. The idea behind this exercise is to take
operations already available in a package such as UNIX curses and to en
capsulate them with a class so that they enjoy the ease-of-use associated
with object-oriented programming.
www.MathSchoolinternational.com
Chapter 4
More On Classes
141
www.MathSchoolinternational.com
142 CHAPTER 4 M O RE O N CLASSES
This chapter begins with a sample application, a String class, that intro
duces important and subtle issues with respect to constructors, destructors,
and assignment operators. We use the sample application to clarify these
issues in subsequent sections and to introduce related material.
S o lu tio n _______________________________________________________________________
class String {
enum SortOrder { Asc, Desc } ;
enum ErrorsIO { ReadFail, W riteFail } ;
char* s tr; // data member — p rivate
in t len; // actual
p u b lic:
// constructors-destructor
S trin g ( ) ; // defau lt constructor
S trin g ( const Stringfe ) ; // copy constructor
S trin g( const in t ) ; // strin g in it ia liz e d to blanks
StringC const char* ) ; // from a C strin g, chair*
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A STRING CLASS 143
"Strin gO ; // destructor
// other methods as functions
in t w r ite ( ) ;
in t w r ite ( FILE* ) ;
in t r e a d ();
in t read( FILE* ) ;
// operators
String operator+( const Stringfe ) const;
in t operator<( const String ) const;
in t operator>( const String ) const;
Stringfe operator=( const Stringfe ) ;
// friends
frien d void s o r t( S trin g*, in t, in t ) ; // selection sort
>;
#endif // StringHeaderLoaded_Version_l.0
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "strin gs.h "
// convert constructor
S t r in g ::S trin g ( const char* cstr )
{
// +1 to ensure room fo r n u ll terminator
s tr = new char[ s tr le n ( cstr ) + 1 ] ;
strcp y( s tr, cstr ) ;
len = s tr le n ( s tr ) ;
}
www.MathSchoolinternational.com
CHAPTER 4 M O RE ON
d e le t e [ ] s tr;
>
www.MathSchoolinternational.com
SAM PLE APPLIC A TIO N : A STRING CLASS 145
return len = s tr le n ( s tr ) ;
>
// assignment operator
Stringfe S tr in g ::operator=( const Stringfe strarg )
{
// check whether String assigned to i t s e l f
i f ( th is != festrarg ) {
d e le te [ ] s tr; // fre e current storage
len = stra rg .le n ;
s tr = new char[ len + 1 ] ; // a llo c a te new storage
strcpy( s tr , s tra rg .s tr ) ; // copy contents
>
return *th is ;
}
www.MathSchoolinternational.com
CHAPTER 4 M O RE O N CLASSES
// + operator fo r concatenations
S tring S trin g::op era tor+ ( const Stringfe strarg ) const
return re tv a l;
>
in t next;
www.MathSchoolinternational.com
4.1 SAM PLE A PPLIC A TIO N : A STRING CLASS 147
a [ i ] = a [ next ] ;
a [ next ] = temp;
>
>
>
D iscussion .------------------------------------------------------------------------------------------------
The class String has two data members: an in t variable len that stores the
S tring’s length and a pointer s tr to the char cells that hold the S trin g’s
value. The char cells include a cell for a ’ \0 ’ , which means that the total
number of cells is the S trin g’s length + 1. The data members are p riva te
by default and so accessible only to a Strin g’s four constructors, its destruc
tor, the other four member functions, the four member operators, and the
frien d function sort, which does a selection sort on an array of Strings.
The sort may be done in either ascending or descending order. The data
member len is included as a convenience for defining the constructors. The
class String could be created without the len member, as we request in an
exercise. We now examine how the methods and frien d function work.
The default constructor
// default constructor — create empty strin g
String: :StringO
{
str = new char[ 1 ] ; // a llo ca te
* s tr = ’ \0’ ; // i n i t i a l i z e to empty
len = 0;
>
expects no argument and so is invoked whenever a variable of type S tring
is defined without any initializing value. For example, in a definition such
as
String s tr in g l;
the default constructor is invoked. This constructor dynamically allocates a
single char cell, sets its value to the null terminator, and sets its length to
0. Because class member s tr now points to a null-terminated array of char,
s t r in g l. s tr is an ordinary C string and so can be passed as an argument
to library functions such as strlen, strcmp, s tr cat, and the like.
The convert constructor
// convert constructor
S tr in g ::S trin g ( const char* cstr )
{
// +1 to ensure room fo r n u ll terminator
s tr = new chart s tr le n ( cstr ) + 1 ] ;
strcpy( s tr, cstr ) ;
www.MathSchoolinternational.com
CHAPTER 4 M O RE O N CLASSES
len = s tr le n ( s tr ) ;
>
is invoked whenever a String object is defined with an ordinary C string as
its initializing value. For example, in the definition
S trin g strin g2 ( "mercy!" ) ;
this constructor is invoked. The constructor allocates s tr le n ( cs tr ) +
1 char cells so that there are enough cells to hold the C string and the
’ \0 ’ . The constructor then copies the argument into the cells and sets data
member len to s tr le n ( cstr ). The argument to this constructor is const
to ensure that the constructor does not alter the value of the C string while
initializing str.
The copy constructor
// copy constructor — String ==> String
S t r in g ::S trin g ( const Stringfe strarg )
www.MathSchoolinternational.com
4.1 SAM PLE APPLIC A TIO N : A STRING CLASS
st r i n gs
strin g 2
f 0 0 \0
strin g3
f 0 0 \0
www.MathSchoolinternational.com
150 CHAPTER 4 M O RE O N CLASSES
the same chars in these cells. Our copy constructor achieves this goal, but
the compiler’s does not. Our copy constructor first allocates separate storage
for string3 and then uses strcpy to copy strin g2 . s tr into s trin g 3 . str.
The constructor finishes its work by setting strin g3 . len to s trin g 2 . len.
Whenever we create a class with a pointer as a data member, we typically
provide our own copy constructor. If we create a class without any pointers
as data members, we typically let the compiler generate the copy constructor
for us. Our copy constructor’s single argument is const because the copy
constructor does not alter it.
The convert constructor
Figure 4.1.3 summarizes the different types of constructor, using the String
constructors as examples.
The destructor
d e le te [ ] s tr;
>
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A STRING CLASS 151
www.MathSchoolinternational.com
CHAPTER 4 M O RE ON CLASSES
String s t r in g l( "bonnie" ) ;
String strin g2 ( "clyde" ) ;
i f ( s trin g l < string2 )
cout « "bonnie" « " < " « "clyde" « endl;
else
cout « "clyde" « " <= " « "bonnie" « endl;
>
illustrates how the operator might be used. The output is
bonnie < clyde
The single argument to the overloaded operator is const because the com
parison does not alter the argument.
The overloaded operator +
// + operator fo r concatenations
S trin g S trin g::op era tor+ ( const Stringfe strarg ) const
return re tv a l;
>
is more complex. Here is a code slice to illustrate its use:
www.MathSchoolinternational.com
4.1 SAM PLE A PPLIC A TIO N : A STRING CLASS 153
int mainO
{
String s l ( "Get a l i f e , George" ) ;
String s2( " and Martha!" ) ;
String s3;
s3 = s i + s2; // Get a l i f e , George and Martha!
s 3 .w r ite (); // prin ts s3 .s tr to standard output
}
The overloaded + is used for string concatentation. Because the operator
returns a value of type String, the line
String r e t v a l( temp ) ;
is needed to convert the C string temp into a String. When r e tv a l is
defined, temp (which points to the concatenation of s i. s t r and s 2 .s tr)
provides the initializing value stored at r e t v a l. str. The constructor
// C strin g to String constructor
S tr in g ::S trin g ( const char* cstr )
www.MathSchoolinternational.com
154 CHAPTER 4 M O RE O N CLASSES
si
f r e d \0
this
r i
>
th is points to String s i (see Figure 4.1.4). The pointer variable th is has
type qualifier const so that it would be an error to use th is as the target
of an assignment expression. Any statement of the form
th is = . . . ; // *** * * ERROR
is wrong. Also, th is is a C + + keyword, which rules out a user-defined
variable or parameter of the same name.
In the case of the = operator,
// assignment operator
Stringfe S tr in g ::operator=( const Stringft strarg )
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A STRING CLASS 155
}
the body of the i f statement is not executed because the test
i f ( th is != &str ) {
fails. (Exercise 6 asks you to investigate the result of removing the i f test
from the operator.) If the String object is not being assigned to itself,
the body of the i f statement frees the current storage to which s tr points,
allocates new storage to hold stra rg .le n + 1 bytes, and copies the string
into this new storage. The operator uses the statement
return *th is ;
to return the current object, that is, the object to which th is points. It
is important that String: :operator= return a S tring reference to enable
constructs such as
in t main()
{
String s l ( "h e llo , world" ) ;
String s2;
String s3;
s3 = ( s2 = s i ) ; // parentheses optional
>
Recall that the assignment operator is, technically, an operator function,
that is, a function that permits operator syntax. So String: :operator=
may be used with the syntax of a binary operator
s2 = s i; // operator syntax
or the syntax of a method
s2.operator=( s i ) ; // method syntax
The point is that String: :operator= expects a String reference as an
argument. Therefore, the statement
s3 = ( s2 = s i ) ; // parentheses optional
should be understood as
s3.operator=( s2.operator=( s i ) ) ; // method syntax
For this to work, the expression
www.MathSchoolinternational.com
156 CHAPTER 4 M O RE O N CLASSES
s2 = s i
must evaluate to a String reference— the argument to s3’s operators
The frie n d function sort uses one of the overloaded comparison oper
ators (either > or <), the overloaded assignment operator =, and the copy
constructor. The code slice
in t ( S tr in g :: *compare_op ) ( const String ) ;
compare_op =
( order == Asc ) ? compare_op = S tr in g :: operator< :
compare_op = S tr in g ::operator>;
defines the variable compare_op as a pointer to a String method that ex
pects a const argument of type String and returns an in t (see Section
2.3). The assignment statement sets compare_op to either operator< or
operator>, depending on the value of parameter order. Once compare_op
has been set, we can use it to compare values during the sort:
if ( ( a [ j ] . *compare_op ) ( a [ next ] ) )
next = j ;
For example, if compare_op is operator>, the i f condition tests whether
a [ j ] .s tr is lexicographically greater than a [ next ] .str.
The code
// put sm allest-biggest at p osition i
i f ( i != next ) {
String temp = a [ i ] ;
a [ i ] = a [ next ] ;
a [ next ] = temp;
>
swaps two Strings so that they are in the correct lexicographical order. In
the next section, we illustrate how the assignment operator and the copy
constructor are both at work in this code.
Exercises
in t mainO
String s i;
String s2( 1000 ) ;
String s3( "fred " ) ;
String s4( s3 ) ;
>
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A STRING CLASS 157
5. Rewrite the read and w rite methods so that they use functions such as
puts, gets, fputs, and fgets.
i f ( th is != &str ) {
from String: : operator=? If you do not see any danger, remove the test
and do a sample run.
7. Write a method substitute that substitutes len chars for the blanks
used in the constructor
10. The method String: :w r ite ( FILE* ) does not make its FILE* argu
ment a const. Explain why not. If the reason is not clear, make the
argument const and do a sample run that invokes the method.
11. Express in words the data type of compare_op in frien d function sort.
13. Change the String class so that enum ErrorsIO has file rather than class
scope.
14. The String method operator+ uses local variable r e tv a l of type String
to hold the operator’s return value. Is this local variable necessary? That
is, could you rewrite the operator so that it uses no local variable of type
String?
( a [ j ] . *compare_op ) ( a [ next ] )
www.MathSchoolinternational.com
158 CHAPTER 4 M O RE O N CLASSES
16. Would the sort still work if sort were a method rather than a friend?
Explain your answer.
17. Why does the String destructor use the d elete [ ] operator rather than
the d elete operator?
18. Illustrate how th is behaves by rewriting the read and w rite methods so
they all explicitly use this.
th is = . . . ;
22. Write a String method that replaces, in the internal representation, one
specified character by another. For example, this method would replace
every blank character by, say, the character ’ !’ in the S trin g’s internal
representation.
www.MathSchoolinternational.com
M O RE O N THE C O P Y CONSTRUCTOR 159
int mainO
{
// code s lic e 1
String s l ( "RISC versus CISC" ) ; // convert constructor
String s2( s i ) ; // copy constructor
String s3 = s i; // copy, not assignment!
}
s2 is initialized through the copy constructor because s i is a String. Object
s3 also is initialized through the copy constructor, even though the assign
ment operator seems to be at work. In C + + , the assignment operator is
never at work when a variable is initialized in its definition. The reason can
be seen by reviewing the String assignment operator:
// assignment operator
Stringft S trin g : : operator=( const Stringft strarg )
{
// te s t whether object assigned to i t s e l f
i f ( th is != ftstrarg ) {
d e le te [ ] s tr;
len = stra rg .le n ;
s tr = new char[ len + 1 ] ;
strcpy( s tr , s tr a r g .s tr ) ;
>
return *th is ;
}
Note that the assignment operator uses the d elete [ ] operator to free the
previously allocated storage to which s tr points. However, when a S trin g
such as s3 is initialized in its definition, s3. s tr does not yet point to dy
namically allocated storage. Instead, s 3 .s tr contains some random value
that, as luck usually has it, constitutes an illegal address. The d e le te [ ]
operator within the assigns lent operator thus could cause an access violation
on the spot or even more si btle mischief later on. (The prudent programmer
assumes that an uninitialis ed pointer points to an illegal address.) A copy
constructor, which is designed precisely for variable initialization, usually
does not contain a d elete [ ] operator because there is no previously allo
cated storage to delete. Accordingly, the copy constructor is the appropriate
way to initialize s3.
The code slice
int mainO
{
// code s lic e 2
String s l ( "RISC versus CISC" ) ; // convert
String s2; // default
www.MathSchoolinternational.com
CHAPTER 4 M O RE O N CLASSES
s2 = s i; // assignment
>
neither the copy constructor nor the assignment operator is at work. The
two statements are equivalent. They are syntactic variants of
String s l ( "judy" ) ; // convert constructor
□
www.MathSchoolinternational.com
4.2 M O R E O N THE C O P Y CONSTRUCTOR 161
Strin gO , // defau lt
s, // copy
C strs[ 2 ] >; // convert
illustrates how an array of String might be initialized. Array Sstrs has five
members because the compiler allocates one String for every initial value.
The initializations include an explicit call to the default constructor to signal
that the third element, Sstrs [ 2 ], should be initialized with the default
constructor. If we left out the default constructor, the compiler would have
allocated only four String cells for Sstrs because, in that case, only four
initial values would have been provided. However, we could specify an array
size and provide fewer initial values:
String s t r s [ 5 ] = { C strs[ 0 ] , // convert
C strs[ 1 ] } ; // convert
Because there are only two initial values, strs [ 2 ], strs [ 3 ], and
strs [ 4 ] are all initialized with the default constructor. □
Class storage allocated with the new statement is always initialized with
the default constructor. It is an error to try to provide initial values for such
storage.
>
www.MathSchoolinternational.com
162 CHAPTER 4 M O RE ON CLASSES
si
f 0 0 \0
in m ain
f 0 0 \0
in fu n c
in t mainO
>
passes String variable s i by value to function func. The copy constructor is
invoked to initialize the storage cells that hold the copy of s i that is passed
to func (see Figure 4.2.1). □
www.MathSchoolinternational.com
4.2 M O R E O N THE C O P Y CONSTRUCTOR 163
si
s2
temp
>
The concatenation changes neither s i nor s2, as the calls s i.w r it e ( ) and
s 2 .w rite () illustrate. The concatentation operator does return a String
value, which is stored in a temporary String cell initialized with the copy
constructor (see Figure 4.2.2).
In a code slice such as
www.MathSchoolinternational.com
164 CHAPTER 4 M O RE O N CLASSES
in t main()
{
String s l ( "G alileo was lucky." ) ;
String s2( " Bruno was n o t." ) ;
String s3;
s3 = s i + s2; // s3: G alileo was lucky. Bruno was not.
>
the contents of the temporary String cell that holds s i + s2 are assigned
to s3. The assignment operator returns a String reference rather than a
S trin g value, which explains why the copy constructor is not invoked in the
assignment operation. For example, the copy constructor is not invoked in
this code slice:
in t main()
>
If the user does not overload the assignment operator when creating a class,
then the compiler does so. The compiler’s assignment operator, which does
a member by member copy, is likely to cause problems if the class contains
a pointer as a data member.
C ::C ()
{
p tr = new char[ 1 ] ;
*ptr = ’ \0’ ;
www.MathSchoolinternational.com
4.2 M O R E O N THE C O P Y CONSTRUCTOR 165
Cl
in t mainO
c2 = c l; // c2.ptr == c l.p t r
setValue( c2, "Ada, software" ) ;
www.MathSchoolinternational.com
166 CHAPTER 4 M O RE O N CLASSES
cl
c h a r 1 e s h a r d w a r e \0
\o
\0
c2
Ada, software
However, c l.p t r also points to this string because it points to the same
cell to which c2.ptr points (see Figure 4.2.5)! This is not what we want.
We want c l.p t r and c2.ptr to point to different cells that hold different
strings. We can achieve this goal by overloading the assignment operator:
C& C ::operator=( const C& c )
www.MathSchoolinternational.com
4.2 M O RE O N THE C O P Y CONSTRUCTOR 167
c h a r 1 e s h a r d w a r e \0
c h a r 1 e s h a r d w a r e \0
Figure 4.2.6 After the assignment statement with the assignment operator over
loaded.
C a r 1 e s > h a r d w a r e \0
c2
ptr A d a s 0 f t w a r e \0 a r e \0
It makes sense to overload the equality (==) and inequality (!= ) operators
whenever it makes sense to overload the assignment operator. The equality
and inequality operators are overloaded so they test for equality as defined
by the assignment operator.
Example 4.2.7. For the class of Example 4.2.6 with the assignment op
erator overloaded, we could overload the equality and inequality operators
as
in t C : :operator==( const C& c )
{
return strcmp( p tr, c .p tr ) == 0;
>
www.MathSchoolinternational.com
168 CHAPTER 4 M O RE O N CLASSES
We conclude this section with a program slice that defines Strings, passes
them by value and by reference to functions, returns them by value and by
reference, assigns them to other Strings, and so on. We add print statements
to the constructors, destructor, and String assignment operator to trace
the program’s run. We also have print statements at function entry and exit
points. The sample run’s output illustrates how the constructors, destructor,
and assignment operator behave for Strings.
// * * * * * * * * * * * * code
in t mainO
void f ( String ) ;
String s i;
String s tr in g s [ ] =
{ "moe", "cu rly ", "la rry " } ;
S tring s2( strings [ 0 ] ) ;
S tring s3;
s3 = ( String ) "natasha";
f ( s3 ) ;
return EXIT_SUCCESS;
>
void f ( String s )
void g ( String ) ;
S tring lo c a l;
g( s );
g ( lo c a l ) ;
void g ( String s )
{
cout « "\n\tInto g ( String ) . . . " « endl;
www.MathSchoolinternational.com
4.2 M O R E O N THE C O P Y CONSTRUCTOR 169
String h( String ) ;
String lo c a l;
lo c a l = h( s ) ;
String h( String s )
{
cout « "\n\Into h( String ) . . . " « endl;
String k( Stringfe ) ;
String lo c a l;
lo c a l = k( s ) ;
return s;
}
Stringfe k( String s )
{
cout « "\n\tInto k ( String ) . . . " « endl;
cout « "\n\tOut of k ( String ) . . . 11 « endl;
return s;
}
// * * * * * * * * * * * * sample run
Into mainO . . .
Default — S tr in g ::S trin g ( ) ***
Convert — S tr in g ::S trin g( const char* ) *** moe
Convert — S tr in g ::S trin g ( const char* ) *** curly
Convert — S tr in g ::S trin g ( const char* ) *** la rry
Copy — S tr in g ::S trin g ( const Stringfe ) *** moe
Default — S tr in g ::S trin g ( ) ***
Convert — S tr in g ::S trin g ( in t ) ***
Convert — S tr in g ::S trin g ( const char* ) *** natasha
Assignment — S trin g::o p era to r= ( const Stringfe ) *** natasha
Destructor — S tr in g :: "S trin g () *** natasha
Copy — S tr in g ::S trin g ( const Stringfe ) *** natasha
Into f ( String ) . . .
Default — S tr in g ::S trin g ( ) ***
www.MathSchoolinternational.com
CHAPTER 4 M O RE O N CLASSES
Into k( Stringfe ) . . .
Out of k( Stringfe ) . . .
Assignment — S trin g::op erator= ( const Stringfe ) *** natasha
Out of h( String ) . . .
Copy — S tr in g ::S trin g ( const Stringfe s tr ) *** natasha
Destructor — S tr in g :: "S trin gO *** natasha
Destructor — S tr in g :: "S trin gO *** natasha
Assignment — S tr in g ::operator=( const Stringfe ) ** * natasha
Destructor — String::"StringO *** natasha
Out of g ( String ) . . .
Destructor — S tr in g :: "S trin gO *** natasha
Destructor — S tr in g :: "S trin gO *** natasha
Copy — S tr in g ::S trin g( const Stringfe ) ***
Into h( String ) . . .
Default — String: :StringO ***
Into k( Stringfe ) . . .
Out of k( Stringfe ) . . .
Assignment — String::operator=( const Stringfe ) ***
Out of h( String ) . . .
Copy — String::String( const Stringfe ) ***
Destructor — S tr in g :: "S trin gO ***
Destructor — String::"StringO ***
Assignment — String::operator=( const Stringfe ) ***
Destructor — String::"StringO ***
www.MathSchoolinternational.com
4.2 M O R E O N THE C O PY CONSTRUCTOR 171
Out of g ( String )
Destructor — String: ~String() ***
Destructor — String: ~String() ***
Out of f ( String ) . . .
Destructor — String: ~String() ***
Destructor — String: ~String() *** natasha
Out of mainO . . .
Destructor — String: ~String() ***
Destructor — String: ~String() *** natasha
Destructor — String: ~String() *** moe
Destructor — String: ~String() *** la rry
Destructor — String: ~String() *** curly
Destructor — String: ~String() ♦♦♦ moe
Destructor — String: “ S trin g () ***
E xercises
int mainO
{
String si;
String s2 = si;
String s3;
s3 = si;
String s4( "glory days by bs" );
String s5;
s5 = s4;
String s6 = s5;
String s7 = String( "judy blue eyes" );
www.MathSchoolinternational.com
172 CHAPTER 4 M O RE O N CLASSES
5. If the programmer does not write his or her own copy constructor, is the
compiler’s copy constructor still at work during call by value?
6. Illustrate with pictures how the copy constructor works during a call by
value with a String object.
7. Why should you not rely on the compiler to overload the assignment
operator for class String?
8. Illustrate with pictures how the copy constructor works during return by
value with a String object.
10. Illustrate with pictures a problem that could arise if we did not provide
String: :operator= for class String.
11. Can you imagine a situation in which it would be a good idea to write
your own copy constructor but not your own assignment operator?
14. Explain why the == operator should be overloaded for class String.
15. Explain why the != operator should be overloaded for class String.
www.MathSchoolinternational.com
FRIEND CLASSES 173
class C {
in t cdm; // data member
p u b lic:
in t m (); // method
frien d in t t ( ) ; // to p le v e l frien d
frien d in t F : : f ( ) ; // method frien d
>;
has two frien d functions, t and F: :f. As the scope resolution operator
makes clear, F : : f is a method in class F. By contrast, t is a toplevel function.
The two frien d functions have the same access to C’s p rivate members,
however. Either frien d can access C: : cdm. □
class F -(
in t adm; // data member
p u b lic:
in t f ( ) ;
... // other methods
>;
class C {
frien d F ; // class F a frien d
in t cdm; // data member
p u b lic:
in t m (); // method
frien d in t t ( ) ; // to p le v e l frien d
>;
makes F a frien d class of C. As a result, any method in F has full access to
all members of C, even p riva te ones. For instance, F : : f can access p riva te
data member C: : cdm. □
www.MathSchoolinternational.com
174 CHAPTER 4 M O RE O N CLASSES
are to any other functions. Two classes can befriend each other so that the
relationship is symmetrical.
class F {
frien d C; // C a frien d to F
in t adm; // data member
public:
// other methods
>;
class C {
frie n d F; / / F a frien d to C
in t cdm; // data member
p u b lic :
>;
makes F a frien d to C, and C a frien d to F. Note that class C is declared in
abbreviated form above F’s declaration so that its name is visible in F when
C is designated a friend. □
Exercises
1. Write class declarations for Cl, C2, and C3 so that Cl is a frie n d to C2,
which in turn is frien d to C3.
www.MathSchoolinternational.com
4.4 SAM PLE A PPLIC A TIO N : A B IN A R Y SEARCH TREE CLASS 175
S o lu tio n _______________________________________________________________________
We use two classes, Node and BST, with BST a frie n d to Node. The class BST
consists of Nodes ordered as described previously. We practice information
hiding by having only priva te data members in BST and Node. Making BST
a frien d to Node eases the programming but does compromise information
hiding. We practice encapsulation by including methods in both classes.
C + + Im plem entation_______________________________________________________
#include <iostream.h>
class Node {
frien d BST; // frie n d class
char v a l; // value == contents
Node* lc ; // l e f t ch ild
Node* rc; // rig h t ch ild
p u b lic:
Node(); // default constructor
in t emptyO; // va l == None
void w r ite ( ) ;
>;
www.MathSchoolinternational.com
CHAPTER 4 M O RE O N CLASSES
class BST {
Node* root;
Node* tre e ;
void addNodeAux( const char ) ;
void inorderAux( Node* ) ;
p u b lic :
BSTO;
void addNode( const char ) ;
void in order( ) ;
>;
Node::Node()
lc = rc = 0;
v a l = None;
>
in t Node: : empty()
return va l == None;
>
BST::BST()
www.MathSchoolinternational.com
4.4 SAM PLE A PPLIC A TIO N : A B IN A R Y SEARCH TREE CLASS 177
// — return
i f ( tree -> empty() ) {
tree -> va l = v;
tree -> lc = new Node;
tree -> rc = new Node;
return;
>
addNodeAux( v ) ;
>
D iscussion____________________________________________________________________
Classes Node and BST are interdependent: Node has BST as a friend, whereas
BST has two data members of type Node*. To make BST visible to Node’s
declaration, we place the forward declaration
class BST; // forward declaration
above Node’s declaration, which in turn occurs above the declaration for BST.
We make BST a frien d of Node so that BST methods such as addNodeAux
www.MathSchoolinternational.com
CHAPTER 4 M O RE O N CLASSES
and inorderAux can access Node’s p riva te data members lc and rc. As we
add other BST methods, they too will have access to p riva te data members
in Node objects. Making individual BST methods into friends of Node would
be less convenient, especially as we add to these methods.
The default BST constructor
BST::BST()
lc = rc = 0;
v a l = None;
>
sets pointers lc and rc to null address 0 before setting v a l to value None,
which is used to identify an “empty” Node. Pointer root always points to
the root of the entire binary search tree, whereas tre e points to the current
subtree. Initially, the entire tree is the current subtree. This approach lets
us write BST methods addNode and addNodeAux with only one argument,
the v a l to be stored in a Node:
void BST::addNode( const char v )
■C
tre e = root; // sta rt at root
addNodeAux( v ) ;
>
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A B IN A R Y SEARCH TREE CLASS 179
addNodeAux( v ) ;
}
The BST method addNode sets tre e to root to ensure that the search
always starts at the root of the entire tree. Method addNodeAux does the
work. If the current Node (i.e., the root of the current subtree) is empty,
then addNodeAux stores the value there and creates a left and a right child
before returning. Otherwise, the method sets tre e to the current Node’s left
or right subtree before invoking itself. Note that addNodeAux is p riva te in
BST but that addNode is public. There is a similar relationship between
inorderAux, which is private, and inorder, which is public. The two
public methods are the BST’s public interface, whereas the p rivate methods
represent a functional decomposition of the public methods. A user adds
a Node to a BST by invoking the public method only, which then turns the
task over to a p riva te method.
Once a BST has been built, method inorder is invoked to perform an
inorder traversal of the tree. The method traverses Node’s left subtree, prints
Node’s val, and then traverses Node’s right subtree. The recursive method
starts at the tree’s root so that the traversal visits every Node.
The BST methods addNodeAux and inorderAux illustrate two styles of
recursion. Before each recursive call, addNodeAux sets tre e to its left subtree
(lc ) or its right subtree (rc), thereby determining the direction of the search
for an empty Node. The only argument passed is v, the data item to be
stored in the appropriate empty Node. By contrast, inorderAux changes its
parameter to either the left or the right subtree of the current Node. Each
recursive method is p rivate so that the user can remain oblivious to this
dreaded programming technique while benefiting from its power.
Finally, here is a code slice that illustrates the BST methods:
in t main()
{
BST bst; // create binary search tree
bst.addNode( ’ K’ ) ; // add K node
bst.addNode( ’ G’ ) ; // etc.
bst.addNode( >F’ ) ;
bst.addNode( ’ I ’ ) ;
bst.addNode( ’ H’ ) ;
bst.addNode( );
www.MathSchoolinternational.com
180 CH APTER 4 M O RE O N CLASSES
bst.addNode( );
bst.addNode( ’ X’ );
b s t. addNode( ’ S’ );
bst.addNode( ’ A’ );
b s t . in order( ) ; // p rin ts: AFGHIKPRSX
return EXIT.SUCCESS;
>
Exercises
4. Rewrite BST using root as the only data member of type Node*.
6. Write BST:: ~BST() so that it systematically deletes all Nodes in the bi
nary tree. Hint: The destructor should d elete the left and right subtrees
before deleting the root.
7. Explain why
class BST {
const Node* root; // changed from Node* root
>;
8. Do a hand trace of
bst.addNode( ’ T ’ ) ;
Assume the statement occurs at the end of the code slice immediately
preceding these exercises.
www.MathSchoolinternational.com
4.5 SAM PLE A PPLIC A TIO N : A N ITE R A TO R CLASS 181
S o lu tio n _______________________________________________________________________
C + + Im plem entation________
#include <iostream.h>
class BST;
class IterBST;
class Node {
frien d BST; // frien d class
frien d IterBST; // frien d class
char v a l; // value == contents
Node* lc ; // l e f t child
Node* rc; // righ t child
p u b lic:
N o d e(); // constructor
in t empty( ) ; // va . == None
void w rite O ;
>;
class IterBST {
Node** nodeStack; // l i s t of Nodes in BST
in t nextNode; // index into l i s t
in t nodeCount; // to ta l Nodes in BST
www.MathSchoolinternational.com
CHAPTER 4 M O RE ON CLASSES
class BST {
frien d IterBST;
in t count;
Node* root;
Node* tree;
void addNodeAux( const char ) ;
void inorderAux( Node* ) ;
p u b lic :
BSTO;
void addNode( const char ) ;
void inorder( ) ;
>;
// inorder traversal
void IterB ST:: stackNodesAux( Node* n )
{
i f ( n -> empty( ) )
return;
stackNodesAux( n -> lc ) ;
nodeStack[ nextNode++ ] = n;
stackNodesAux( n -> rc ) ;
www.MathSchoolinternational.com
4.5 SAM PLE APPLIC A TIO N : A N ITE R A TO R CLASS 183
Node* IterBST::getNextNode()
Node: :Node()
{
lc = rc = 0;
val = None;
}
cout « val;
>
BST::BST()
{
root = tree = new Node;
count = 0; //n o nodes yet
>
www.MathSchoolinternational.com
184 CHAPTER 4 M O RE ON CLASSES
www.MathSchoolinternational.com
4.5 SAM PLE A PPLIC A TIO N : A N ITE R A TO R CLASS 185
Exercises
www.MathSchoolinternational.com
186 CHAPTER 4 M O RE ON CLASSES
in t mainO
{
Node* n;
BST bst; // create a BST
b s t.addNode( ’K’ // add a Node. . .
b s t.addNode( ’ G’ // and another..
b s t.addNode( >F > // and another
Our IterBST would not see a Node such as Z that is added to the BST
after the BST is created and initialized. Change IterBST so that it would
see Nodes added to the BST after the IterBST is created. Hint: Data
member BST: : count counts every Node added to a BST.
Static D a ta M em bers
www.MathSchoolinternational.com
STATIC DATA MEMBERS AND METHODS 187
class C. Except for its definition, a p riva te s ta tic data member cannot be
accessed outside the class.
>;
includes a declaration for s ta tic data member sdm. The declaration does
not allocate storage. Accordingly, C: : sdm must be defined elsewhere as, for
example:
in t C::sdm = -999; // define s ta tic C::sdm and i n i t i a l i z e
// keyword s ta tic NOT used!
in t mainO
{
}
Note that C: : sdm’s definition includes the scope resolution operator. If
the scope resolution operator were omitted
in t sdm = -999; // define an extern va riab le named sdm
// that is NOT the same as C: : sdm
then we would be defining an extern variable named sdm (i.e., : : sdm) rather
than C: : sdm.
A s ta tic data member must be defined outside all blocks. It would be
an error, for example, to try to define C: : sdm inside main:
in t mainO
{
// * * * * * ERROR: s ta tic data member can’ t be
// defined inside a block
in t C :: sdm = -999;
>
□
www.MathSchoolinternational.com
188 CHAPTER 4 M O RE ON CLASSES
class C {
char* name;
in t id;
s ta tic in t sdm;
>
>
void f ( )
>
www.MathSchoolinternational.com
4.6 STATIC DATA MEMBERS AND METHODS 189
C::Sdm
the s ta tic data member C :: sdm is defined before the first class object s is
defined. Objects s and r have their own copies of data members name and
id, but the two share the s ta tic data member sdm (see Figure 4.6.1). If a
s ta tic data member is defined without an initial value, then the compiler
initializes it to zero. So, for example, given this definition of C:: sdm
class String {
char* s tr; // data member — p rivate
in t len; // actual
s ta tic in t count; // s ta tic data member
p u b lic :
void print_count()
<
cout « "Total strin gs ==> " « S trin g : : count « endl;
}
www.MathSchoolinternational.com
190 CHAPTER 4 M O RE O N CLASSES
Data member count is s ta tic and tracks the total number of String objects
created in the program. Function print_count is a frie n d that can access
this data member in order to print its value. We make count a s ta tic data
member rather than, say, an extern variable in order to associate count with
class String. For count to reflect the current number of S tring objects,
the String constructors should be amended to include the statement
count++;
and the String destructor should be amended to include the statement
count— ;
□
Exam ple 4.6.5. Data member sdm is a s ta tic yet public data member
in class C
class C {
p u b lic :
s ta tic in t sdm; // declare
>
>
>
Of course, class C must be visible to f . □
Static M ethods
www.MathSchoolinternational.com
4.6 STATIC DATA MEMBERS AND METHODS 191
Example 4.6.7. We amend the String class so that it has a s ta tic method
to increment the s ta tic data member count:
class String {
char* s tr; // data member — p rivate
in t len; // actual
s ta tic in t count; // count declared here
p u b lic :
// s ta tic functions
s ta tic void count_up() { count++ } ;
>;
www.MathSchoolinternational.com
192 CHAPTER 4 M O RE ON CLASSES
void print_count()
Exercises
1. Can a sta tic data member be defined as well as declared within a class
declaration?
www.MathSchoolinternational.com
STATIC DATA MEMBERS A N D METHODS
class X {
in t x;
s ta tic in t sX;
>;
in t mainO
{
X: :sX = -999;
class X {
in t x;
s ta tic in t sX;
>;
sX = -999; // d e fin itio n of X::sX
class X {
in t x;
s ta tic in t sX;
>;
s ta tic in t X::sX = -999;
class Z {
in t z ;
p u b lic:
s ta tic in t sZ;
>;
in t Z: : sZ = 10;
in t main()
{
www.MathSchoolinternational.com
194 CHAPTER 4 M ORE O N CLASSES
class C {
in t c;
s ta tic in t sC;
p u b lic :
s ta tic void fC () { count « c; >
>;
class C {
in t c;
s ta tic in t sC;
p u b lic:
s ta tic void fC ()
{ cout « th is -> sC; }
>;
13. Explain the advantage of using a s ta tic data member instead of a global
variable.
because th is is a constant.
www.MathSchoolinternational.com
CO M M O N PRO G RAM M IN G ERRORS 195
class C {
>;
C::C(Cc) // * * * * * ERROR
{
C::C( C& c ) // ok
{
>
However, it is legal to provide fewer initializing values than there are cells
in an array:
//ok
String s tr in g s [ 12 ] =
{ "good", "bad", "ugly" } ; // only 3 values
class C {
s ta tic in t sdm = 6 ; // * * * * * ERROR
>;
www.MathSchoolinternational.com
196 CHAPTER 4 M O RE O N CLASSES
class D {
sta tic int sdm; // ok — declaration
>;
class D {
sta tic int sdm; // ok — declaration
>;
void f ( )
{
// * * * * * ERROR: d efin itio n in a block!
D: : sdm = 6;
>
9. It is an error to define a sta tic data member with the keyword static.
However, the data member must be declared with the keyword static:
class D {
sta tic int sdm; // ok — declaration
>;
10. It is illegal to attempt to reference a public sta tic data member with
out the scope resolution operator:
class C {
p u b lic :
sta tic int sdm; // declaration
>;
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 197
void f ( )
{
i f ( sdm > 0 ) // * * *** ERROR: name is C::sdm
>
13. It is an error for a s ta tic method to reference a data member that is not
static.
• Open an account.
• Close an account.
• Add funds to an already open account.
• Remove funds from an already open account.
• Transfer funds from one open account to another.
• Request a report on one or more open accounts.
www.MathSchoolinternational.com
198 CHAPTER 4 M O RE O N CLASSES
4.5. Implement a list as an abstract data type L ist, where a list is an ordered
collection of none or more elements. In a traditional programming lan
guage such as C, a list typically is implemented either as an array or as
a linked-list, with shortcomings in either implementation: an array’s size
must be fixed at definition time, and a linked-list usually requires that the
user manipulate pointers. By contrast, the user of a L is t should need to
know only the public interface, which supports the following operations:
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 199
e Schedule would be
www.MathSchoolinternational.com
CHAPTER 4 M O RE ON CLASSES
c e l l (11,44) * cell(1 4 ,2 3 )
4.9. Implement a Graph class, where a graph is a set of vertices V and a set
of edges E such that each edge in E is associated with an unordered pair
of distinct vertices in V. The following figure
M i s s o u l a ----------M i n n e a p o l i s Detroit
shows a graph in which the vertices represent cities and the edges repre
sent airline routes between pairs of cities. A graph search is the coun
terpart of a tree traversal (see Section 4.3) in that the search visits every
vertex in the graph. Two general-purpose graph searches are depth-first
search and breadth-first search, which can be sketched as follows:
// d ep th -first search
1. Designate a vertex as the START. Let V = START.
2. V is it V and mark i t as v is ite d .
3. Choose an unvisited vertex W that is adjacent to V.
Do a d ep th -first search from W.
4. When you reach a vertex U that has no u nvisited
adjacent v e rtic e s , back up to the most recen tly
v is ite d vertex W that does have an unvisited vertex X.
I f there is no such vertex W, terminate the search;
otherwise, do a d e p th -firs t search from X.
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 201
For the graph in the preceding figure, one depth-first search with Chicago
as START is
where a**b means ab. Also, there should be a method that allows the
user to encode a polynomial as a bit-string. For example, the bit-string
1101
4.11. Implement a SymbolTable class. A symbol table lists all identifiers (i.e.,
function and variable names) in a program’s source code together with
pertinent information such as the identifier’s data type, its role within the
program (e.g., whether the identifier is a function name, variable name,
or a label), and its position in a source code file (e.g., a line number
designating the source code line in which the identifier occurs). The
public interface should allow the user to specify one or more source files
www.MathSchoolinternational.com
202 CHAPTER 4 M O RE O N CLASSES
aRgT
matches only other strings with exactly these four characters in this order.
Use the following special characters:
www.MathSchoolinternational.com
Chapter 5
Inheritance
203
www.MathSchoolinternational.com
204 CHAPTER 5 INHERITANCE
Example 5.1.1. Classes Car and Vehicle are related such that every Car
is a Vehicle as well (see Figure 5.1.1). Car is thus a subclass or derived class
of Vehicle, and Vehicle is a superclass or base class of Car. Our figures use
an arrow to point from a derived class back to a base class.
Inheritance relationships are either direct or indirect. Suppose that
Coupe is a subclass of Car (see Figure 5.1.2). Because there is no intermedi
ate superclass between Coupe and Car, Car is a direct superclass or a direct
base class of Coupe. Conversely, Coupe is a direct subclass or direct derived
class of Car. By contrast, Vehicle is an indirect superclass or indirect base
class of Coupe, and Coupe is an indirect subclass or indirect derived class of
Vehicle. Note that Car is a derived class with respect to Vehicle but a base
class with respect to Coupe.
The terms direct and indirect also apply to inheritance links. For ex
ample, Coupe inherits directly from Car but only indirectly from Vehicle.
There is a direct inheritance link from Vehicle to Car but only an indirect
inheritance link from Vehicle to Coupe.
C + + supports multiple inheritance in which a subclass has multiple
superclasses. For example, Car also might be a subclass of ExpensiveToy (see
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYNTAX 205
M e m b er Accessibility
www.MathSchoolinternational.com
CH APTER 5 INHERITANCE
class Pen {
p u b lic :
move_pen( a, b ) { x = x + a ; y = y + b ; }
set_pen( a, b ) ( x = a ; y = b ; }
PenO { in it ia l_ p e n (); }
protected:
void in it ia l_ p e n ();
p r iv a te :
in t x;
in t y;
>;
in t main()
{
Pen p;
p.set_pen( 0, 0 ) ; //OK — set_pen is public
p .in it ia l_ p e n (); // *** ERROR: in itia l_ p e n is protected
p.x = 0; // *** ERROR: x is p riva te
>
move_pen and set_pen can access x and y because x and y are members
of the class Pen. Because x and y are p riva te members, they cannot be
accessed outside Pen; thus,
p.x = 0; // * * * * * ERROR: x is p rivate
is an error.
Similarly, the constructor can access in itia l_ p e n because in itia l_ p e n
is a member of the class pen. Because in itia l_ p e n is a protected member,
it cannot be accessed outside pen or classes directly or indirectly derived from
pen; thus,
p . in it ia l_ p e n (); // * * * * * ERROR: in itia l_ p e n is protected
is an error.
Because set_pen is a public member, it can be accessed globally. Ac
cordingly,
p.set_pen( 0, 0 ) ; //OK — set_pen is public
is legal. □
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYNTAX 207
In C + + , all data members and methods of the base class, except for
constructors, the destructor, and the overloaded assignment operator, are
always automatically included in the derived class. In this sense, the derived
class inherits from the base class. Although the derived class inherits mem
bers from the base class, the accessibility of an inherited member can change.
For example, a public member in the base class can become p rivate in the
derived class. The C + + programmer has considerable flexibility, not only
in constructing new classes from old through inheritance, but also in con
trolling the accessibility of the inherited members. In the remainder of this
section, we explain the syntax and semantics of inheritance and accessibility
of members.
>;
>;
where optional access-specifier is one of private, protected, or public.
The access-specifier controls the type of access provided to the data mem
bers and methods inherited by the derived class from the base class. (We use
the phrase inheritance link interchangeably with access-specifier.) If access-
specifier is omitted, it defaults to private. (If class is replaced by struct
and access-specifier is omitted, access-specifier defaults to public.)
Although a derived class cannot prohibit any of its base class’s data
members or methods from being inherited, the derived class may specify
additional data members or methods.
www.MathSchoolinternational.com
208 CH APTER 5 INHERITANCE
V eh icle
mph
cpmph
w e ig h t
Car
mph
w e ig h t
brand_nam e J- local to G a r
class Celt is derived from the base class Vehicle. The access-specifier is
public. Derived class Car inherits the members mph, cpmph, and weight
from superclass Vehicle and adds a fourth member brand_name (see Figure
5.1.5). □
public Inheritance
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYNTAX 209
in t z;
>;
In the code
in t mainO
{
D d l;
d l.x = 33; / / ok — x is public
d l.y = 99; / / ok — y is public
dl.w = 77; // * * * * * ERROR: w is protected
d l.z = 88; // * * * * * ERROR: z is accessible only within B
>
we may access the public members x and y of D but not the protected
member w, which is visible only within the class hierarchy. Within class D,
it is legal to access w:
void set_w( in t a ) { w = a; } // ok
It is an error to try to access z outside of B. In particular, z cannot be
accessed even in D:
class D : public B {
>;
□
www.MathSchoolinternational.com
210 CHAPTER 5 INHERITANCE
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYNTAX 211
A class may be derived from more than one base class. In this case, its
base classes are separated by commas in the derived class’s declaration.
www.MathSchoolinternational.com
212 CHAPTER 5 INHERITANCE
class D is derived directly from two independent base classes, Bl and B2.
D inherits x l from Bl and x2 from B2. Because both access-specifiers are
public, the members x l and x2 are protected. (The added member d is
p rivate.). □
protected Inheritance
In a protected derivation
• Each p riva te member in the base class remains p riva te in the base
class and so is visible only in the base class.
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS A N D SYNTAX 213
In a p rivate derivation
• Each public member in the base class is p riva te in the derived class.
• Each protected member in the base class is p riva te in the derived
class.
• Each p riva te member in the base class remains p riva te in the base
class and so is visible only in the base class.
class D is derived from the base class B. The access-specifier is private. The
members of the derived class D are
Exam ple 5.1.10. Because priva te is the default value for access-specifier,
the declaration of class D in Example 5.1.9 is equivalent to
www.MathSchoolinternational.com
214 CHAPTER 5 INHERITANCE
Indirect Inheritance
Data members and methods may traverse several inheritance links as they
are included from a base to a derived class. For example, suppose that B is
D’s base class and that D is X’s base class (see Figure 5.1.6). In this case, X
inherits D’s data members and methods— including whatever data members
or methods D inherits from B. Inheritance thus may be either direct (to a
derived class from a direct base class) or indirect (to a derived class from an
indirect base class).
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYNTAX 215
Access Declarations
www.MathSchoolinternational.com
216 CHAPTER 5 INHERITANCE
BC:: z ;
adjusts z to its public status in the base class BC by declaring it in the
public section of the derived class DC. Inherited member y is p riva te in DC
because DC is obtained by p rivate inheritance from BC and y’s status was
not adjusted. Added member w is public. □
N am e H idin g
If a derived class adds a data member with the same name as a data member
in the base class, the local data member hides the inherited data member.
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYNTAX 217
in t mainO
D d l;
>
class D inherits x from B. However, D also has a local data member named x,
which means that the local data member hides the inherited data member
in the sense that B: : x is not in class D’s scope. Theonly way toaccess B: : x
in D is by using the scope resolution operator, as inthe second assignment
statement. □
Similarly, if a derived class adds a method with the same name in the
base class, the added method hides the base class’s method.
in t mainO
D d l;
>
www.MathSchoolinternational.com
218 CHAPTER 5 INHERITANCE
Exercises
4. Draw a class hierarchy that illustrates the distinction between direct and
indirect inheritance.
5. Explain the relationship among the terms superclass, subclass, base class,
and derived class.
7. Draw a class hierarchy that is at least five deep. List the directly and
indirectly derived classes of the top class in the hierarchy.
class A {
in t x;
class B : A {
in t y;
B b l;
class A {
in t x;
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYN TAX 219
class B : A {
in t y;
void f ( ) { y = x; >
>;
class A {
>;
class B : A ■[
};
class A {
protected:
flo a t f l , f2 ;
p r iv a te :
in t x;
in t main()
A a l;
A* p tr = &al;
p tr -> f l = 3.14;
>
12. Explain the difference between p riva te and protected with respect to
a class’s data members and methods.
13. Write the code for a class hierarchy in which there is public inheritance
from base class B to derived class D.
class A {
www.MathSchoolinternational.com
220 CHAPTER 5 INHERITANCE
class B : A {
>;
16. Explain the advantage of protected over p rivate data members or meth
ods.
17. Explain the advantage of protected over public data members or meth
ods.
18. Suppose that data member B: :x is public. Use an inheritance link from
B to D to deny public access to D: :x.
class A {
protected:
flo a t f l , f2;
p u b lic :
in t x;
>;
class B : p riva te A {
p u b lic:
void p flO { cout « fl « endl; }
>;
in t mainO
B b l;
b l . f l = 3.14;
b l.p flO ;
b l.x = ( in t ) b l . f l ;
>
class A {
protected:
in t x;
>;
www.MathSchoolinternational.com
5.1 BASIC CONCEPTS AN D SYNTAX 221
class B : public A {
in t y;
void f ( A a ) { y = a . x ; >
>;
class A {
protected:
in t x;
>;
class B : public A {
p u b lic:
in t y;
>;
in t main()
{
B b l;
b l .x = 8;
b l.y = 9;
www.MathSchoolinternational.com
222 CHAPTER 5 INHERITANCE
24. Explain the difference between inheritance and access. Write rules that
summarize the difference.
class A {
protected:
in t x;
>;
class B : public A {
p u b lic :
void f l ( ) { x = 6; }
void f 2 ( A a ) { a . x = l ; }
>;
www.MathSchoolinternational.com
CONSTRUCTORS UNDER INHERITANCE 223
int mainO
{
D d l; // B ::B () invoked
d l.w r it e O ; // 1 w ritten to standard output
>
B’s default constructor is invoked when dl is defined because D is derived
from B. The constructor initializes d l.x and d l.y to -1. Note that d l in
herits its only data members from B. □
Base class constructors are often sufficient for the derived class. Some
times, however, it makes sense for a derived class to have its own construc
tors. A constructor specific to a derived class may invoke a base class con
structor, if one exists.
class Animal {
protected:
char species [ MaxName + 1 ] ;
p u b lic :
Animal() { strcpy( species, "Animal" ) ; >
Animal( char* s ) { strcpy( species, s ) ; }
>;
www.MathSchoolinternational.com
224 CH APTER 5 INHERITANCE
class Animal {
protected:
char species [ MaxName + 1 ] ;
p u b lic :
AnimalO { strcpy( species, "Animal" ) ; }
Animal( chair* s ) { strcpy( species, s ) ; }
www.MathSchoolinternational.com
5.2 CONSTRUCTORS UNDER INHERITANCE 225
I
P r im a t e ::P r im a t e ( ... ) executes second
1
H u m a n ::H u m a n ( ... ) executes third
Human j i l l ( ) ; // HumanO
Human fr e d ( 4 ) ; // Human( int )
the inheritance hierarchy is now three deep. Human inherits heart_cham di
rectly from Primate and species indirectly from Animal by way of Primate.
Each of the Human constructors invokes the direct base class constructor
Primate before executing an empty body. The Primate constructor, in turn,
invokes the Animal constructor before executing its own body. The effect is
that the constructors are executed in a top-down order, where Animal is at
the top, Primate in the middle, and Human at the bottom of the inheritance
hierarchy (see Figure 5.2.2). □
www.MathSchoolinternational.com
C H A PTE R S INHERITANCE
is in error because B does not have a default constructor and D’s constructor
does not explicitly invoke a B constructor. We can avoid the error in two
ways: by having D’s constructor explicitly invoke, in its header, one of B’s
constructors or by giving B a default constructor. We amend the code slice
to illustrate the two approaches:
www.MathSchoolinternational.com
CONSTRUCTORS UNDER INHERITANCE 227
Suppose that a base class has a default constructor and that a derived
class has constructors, none of which explicitly invokes a base class construc
tor. In this case, the base class default constructor is invoked automatically
whenever a derived class object is created.
int main()
{
D d;
>
is
B::B() fires.
www.MathSchoolinternational.com
CHAPTER 5 INHERITANCE
D ::D () f i r e s . ..
It is legal but unnecessary for D’s constructor to invoke B’s default constructor
explicitly:
// le g a l but unnecessary
DO : B () { . . . }
□
www.MathSchoolinternational.com
5.2 CONSTRUCTORS UNDER INHERITANCE 229
I
D ::D ( c h a r * ) executes second
D fo o ( "fo o " ) ;
D’s constructor is called when foo is defined with the initializing value “foo” ,
which is copied into the dynamically allocated storage to which name points.
The copy occurs in D’s body. The dynamically allocated storage consists
of maxlen char cells. It is B’s default constructor, not D’s parameterized
constructor, that initializes maxlen and dynamically allocates the storage.
Therefore, B’s default constructor must be invoked before the body of D’s
parameterized constructor executes. D’s parameterized constructor does in
voke B: :B () and, as a result, fo o ’s creation and initialization work properly
(see Figure 5.2.3). □
Exercises
class B {
in t x;
p u b lic:
B( in t a ) { x = a; }
>;
class D : public B {
p u b lic:
DO { . . . }
>;
www.MathSchoolinternational.com
CHAPTER 5 INHERITANCE
2. In Example 5.2.3, the default constructor for Human explicitly invokes the
default constructor for Primate but does not explicitly invoke the default
constructor for Animal. Why not?
3. Create a class hierarchy at least three deep and write constructors for
each class. The constructors should contain print statements so that you
can trace their firing. Create objects that belong to each class and trace
the constructor firings.
class B {
p u b lic:
B () { cout « "B" « endl; }
>;
class Dl : public B {
p u b lic:
D l() : BO { cout « "Dl" « endl; >;
>;
class D2 : public Dl {
p u b lic:
D2() : DIO { cout « "D2" « endl; } ;
>;
D2 d2;
7. Is it possible for a derived class to have a constructor but its base class
not to have a constructor? Write and compile sample code to confirm
your answer.
8. Suppose that base class B has two constructors, the default constructor
B: :B( ) and the constructor B: :B( in t ). D is derived from B and has a
single constructor, D: :D( in t ). Must D invoke both of B’s constructors
before executing its own body?
www.MathSchoolinternational.com
5.3 SAM PLE APPLIC A TIO N : MEASURING CO M PUTER PERFO RM AN C E 231
10. Extend the class hierarchy of Example 5.2.3 at least two more levels,
writing constructors for each of the additional classes.
S o lu tio n _______________________________________________________________________
#include <iostream.h>
#include <string.h>
#include <math.h>
class Test;
www.MathSchoolinternational.com
232 CH APTER 5 INHERITANCE
in it () ;
strcpy( name, "???" ) ;
>
BMark( char* n )
in it O ;
i f ( s tr le n ( n ) < MaxName )
strcpy( name, n ) ;
else
strncpy( name, n , MaxName ) ;
>
void re p o rt()
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : M EASURING C O M PU TER PER FO R M A N C E 233
private:
// I n it ia liz e percentages to 0.0.
void in it O
{
alP = cP = mP = ioP = ic = 0.0;
>
>;
if ( !ok() )
in it _ e r r o r ( ) ;
>
>;
www.MathSchoolinternational.com
CHAPTER 5 INHERITANCE
// no i/o.
class DryRock : public BMark {
public:
DryRockO : BMark( "DryRock" ) // DryRock constructor
alP = 77.0;
cP = 16.6;
ioP = 0.0;
mP = 1.0 - alP - cP - ioP;
ic = ( flo a t ) 6700909;
if ( !ok() )
i n i t _ e r r o r () ;
>
>;
alP = 12.2;
mP = 57.7;
ioP = 23.9;
cP = 1.0 - mP - ioP - alP;
ic = ( flo a t ) 10400500;
i f ( !ok () )
i n i t _ e r r o r () ;
>
>;
class Computer {
frien d Test;
protected:
// cpi = cycles per instruction
flo a t a lc p i; // arithm etic-logic cpi
flo a t ccpi; // control cpi
flo a t iocpi; // input-output cpi
flo a t mcpi; // memory cpi
flo a t ct; // cycle time (nanoseconds)
char name[ MaxName + 1 ] ;
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : MEASURING CO M PUTER PERFO RM AN C E 235
protected:
Computer( flo a t a l, flo a t c, flo a t io,
flo a t m, flo a t t ,
char* n, flo a t 1, flo a t u )
{
alcp i = a l;
ccpi = c;
iocpi = io;
mcpi = m;
ct = t;
i f ( s tr le n ( n ) < MaxName )
strcpy( name, n ) ;
else
strncpy( name, n, MaxName ) ;
costU = u;
costL = 1;
}
void re p o rt()
{
cout « "Computer " << name
« " at cost ranging from $" « costL
« " to $" « costU « « endl;
cout « " Clock cycle (nanoseconds): "
« ct « endl;
cout « " CPIs: " « endl;
cout « " A rith-Logic: " « alcp i « endl;
cout « " Control: " « ccpi « endl;
cout « " Memory: " « mcpi « endl;
cout << " I/O: " « iocpi « endl;
>
>;
www.MathSchoolinternational.com
CHAPTER 5 INHERITANCE
flo a t io , // io
flo a t t, // ct
char* n, // name
flo a t 1, // lower bound
flo a t u ) // upper bound
Computer( a l, c, m, io, t , n,
>;
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : M EASURING C O M PU TER PER FO R M A N C E 237
class Test {
flo a t r t ; // response time in nanoseconds
void r e s u lt s ( Computer c, BMark b ) ;
p u b lic :
Test( Computer c, BMark b ) ;
>;
www.MathSchoolinternational.com
238 CH APTER 5 INHERITANCE
D iscussion____________________________________________________________________
R T = IC * C P I * CT
where
Metric Definition
RT Response time
IC Instruction count, the number of instructions executed
CPI Average clock cycles per instruction
CT Clock cycle time, usually in nanoseconds
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : MEASURING C O M PU TER PER FO R M A N C E 239
if ( !o k () )
in it _ e r r o r ( ) ;
>
>;
www.MathSchoolinternational.com
CH APTER 5 INHERITANCE
www.MathSchoolinternational.com
5.3 SAM PLE A PPLIC A TIO N : M EASURING CO M PUTER PERFO RM AN C E 241
J
D e s k to p ::D e s k to p ( ... ) executes second
I
PC::PC( ... ) executes third
}
generates the report
Benchmark r e s u l t s :
Benchmark WetRock
Total instructions executed == 4500301
A rith m etic-logic == 0.5
Memory == 0.2
Control == 0.2
www.MathSchoolinternational.com
242 CHAPTER 5 INHERITANCE
Input/Output = = 0 . 1
Computer PC at cost ranging from $800 to $14500.
Clock cycle (nanoseconds): 230
CPIs:
A rith -L o gic: 2.5
Control: 2.3
Memory: 9.2
1/0: 5.6
Exercises
3. Add data member superscalar to Desktop. The data member has value
true (1) if the machine is superscalar and false (0) otherwise. A computer
is superscalar if
5. Computer technology changes so fast that the default clock cycle time
and C PI values listed in a constructor such as PC: :PC may already be
out of date and, in any case, soon will be. Determine accurate values for
an actual machine and change the default values.
www.MathSchoolinternational.com
5.4 PO LYM O RPH ISM AND VIRTUAL METHODS 243
8. Add a method balanced to BMark. Its value is true (1) if the percentages
of the four instruction categories are approximately equal and false (0)
otherwise. For example, balanced would be true if
alP = 25.0;
cP = 25.0;
mP = 26.0;
ioP = 24.0;
WS workstation;
trace the order in which the relevant constructors are invoked and the
order in which they complete.
10. Computer vendors often are selective in making public how their machines
run different benchmarks. Explain why a given machine might fare far
better running, say, PetRock than WetRock.
www.MathSchoolinternational.com
244 CH APTER 5 INHERITANCE
>
illustrates. By contrast, a pointer to a derived class object(e.g., a pointer of
type C irc le *) may not point to a base class object withoutexplicit casting.
The code slice
www.MathSchoolinternational.com
5.4 PO LYM O RPH ISM AN D VIRTUAL METHODS 245
in t mainO
{
Figure f i g ;
C ircle* p tr;
ptr = & fig; // * * * * * ERROR: derived class pointer can’ t
// point to base class object
>
is illegal. It would be legal if a cast were included:
ptr = ( C irc le * ) & fig;
We review these points with another example.
};
class D : public B {
>;
B b;
D d;
B* ptr;
each of these assignment statements
ptr = &b;
ptr = &d;
is legal.
Given
class B {
>;
class D : public B {
>;
B b;
D d;
D* p tr;
the assignment
www.MathSchoolinternational.com
246 CHAPTER 5 INHERITANCE
p tr = fed; // OK
class D : public B {
p u b lic :
void g ( ) ;
in t h ( ) ;
>;
in t mainO
D d;
B* p tr = &d;
>
the base class B contains a v irtu a l method g, which derived class D then
redefines, and a nonvirtual method h. Since h is nonvirtual, compile-time
binding is in effect in the statement
p tr -> h () ;
Because p tr is of type B*, B’s h is invoked. On the other hand, because g is
v irtu a l, run-time binding is in effect in the statement
p tr -> g ( ) ;
www.MathSchoolinternational.com
PO LYM O RPH ISM AN D VIRTU AL METHODS 247
class D : public B {
p u b lic:
int f ( char ) ;
>;
int mainO
{
D d;
d .g O ; // D: :g (in h erited from B) is invoked
}
method g in class B is inherited by D in the usual way. □
www.MathSchoolinternational.com
CH APTER 5 INHERITANCE
class D : public B {
p u b lic :
void f ( flo a t ) ; // hides B’ s f
>;
in t mainO
{
D d;
B* p tr = fed;
p tr -> f ( 3.3 ) ; // B ::f invoked
the parameter types of B: : f and D: : f differ; hence, D does not redefine f , but
rather defines a new f that hides B’s f . Furthermore, compile-time binding
is used. Because p tr is of type B*, B: : f is invoked in the statement
p tr -> f ( 3.3 ) ;
Because B: : f expects an in t argument, 3.3 is converted to the in t value 3
by dropping the fractional part and 3 becomes the argument to B: :f. □
class D : public B {
p u b lic :
// * * * * * ERROR: Can’ t change the return type
in t f ( in t ) ;
>;
D’s attempt to change the return type of f from void to in t results in an
error. □
www.MathSchoolinternational.com
5.4 PO LYM O RPH ISM AN D VIRTUAL METHODS 249
One
Two
Three
// in it i a liz e array
arra y [ 0 ] = Stone;
arra y [ 1 ] = &two;
arra y [ 2 ] = ftthree;
return EXIT_SUCCESS;
>
the output is
www.MathSchoolinternational.com
CHAPTER 5 INHERITANCE
One
One
One
It would be nice if the output were
One
Two
Three
instead. However, the system determines at compile-time which of the
whoami methods to invoke. Because the array elements are of type pointer
to One (One*), the system invokes One: :whoami in each loop iteration de
spite the fact that array [ 1 ] points to a Two and array [ 2 ] points to a
Three. □
Exam ple 5.4.7. We slightly amend the code of Example 5.4.6 to get sig
nificantly different behavior:
// This time, make whoami a v irtu a l method,
class One {
p u b lic :
v ir tu a l void whoami( ) { cout « "One" « endl; }
>;
in t mainO
{
// define three objects
One one;
Two two;
Three three;
// i n i t i a l i z e array
www.MathSchoolinternational.com
5.4 POLYM O RPH ISM AN D VIRTUAL METHODS 251
array[ 0 ] = &one;
array[ 1 ] = &two;
array[ 2 ] = fethree;
return EXIT_SUCCESS;
>
This time the output is
One
Two
Three
The only difference is that whoami is now a v ir tu a l method, which means
that the system determines at run-time—not at compile-time— which of the
three whoami to invoke. Because array [ 0 ] points to a One, the system
invokes One:: whoami for it. Because array [ 1 ] points to a Two, the system
invokes Two: :whoami for it. Because a rra y[ 2 ] points to a Three, the
system invokes Three: :whoami for it.
The output in this example would be the same if the keyword v ir tu a l
were omitted in the definitions of Two: :whoami and Three: :whoami. C+-1-
adheres to the principle
• Once virtual, always virtual!
for v irtu a l methods. □
>;
>;
www.MathSchoolinternational.com
252 CHAPTER 5 INHERITANCE
>;
Each class derived from Book specializes v irtu a l method p rin t for its class.
For example, Textbook’s prin t prints information about the book as well
as courses for which the book is appropriate, the level of the book (e.g.,
elementary, high school, college), and so on. Similarly, Referencebook’s
p rin t prints information about the book as well as subject areas to which
it is relevant, type of reference book (e.g., dictionary, journal), and so on.
Periodically, output is produced that lists all of the books in order to
gether with information about each, which is supplied through the print
methods. To facilitate the sort, the array
Book* l i s t [ NoBooks ] ;
is defined and initialized to the various objects from the classes Textbook
and Referencebook representing the books. After sorting, the output is
produced by the loop
fo r ( in t i = 0; i < NoBooks; i++ )
l i s t [ i ] -> p r in t( ) ;
Because method prin t is virtu a l, if l i s t [ i ] points to a Textbook ob
ject, Textbook’s prin t is invoked. If l i s t [ i ] points to a Referencebook
object, Referencebook’s prin t is invoked.
If the kinds of books are expanded by deriving additional classes from
Book, the code for producing the output need not be changed. An added
class would require only code for its version of print.
Sorting also could be supported through polymorphism. For example, if
each class contained a v irtu a l method key that returned the key on which
to sort, the array l i s t could be sorted by accessing the sort key as
l i s t [ i ] -> keyO
Now if the kinds of books are expanded by deriving additional classes from
Book, the code for sorting would not have to be changed. An added class
would require only code for its version of key. □
www.MathSchoolinternational.com
PO LYM O RPH ISM AN D VIRTU AL METHODS 253
p u b lic:
v irtu a l void f ( in t ) = 0 ; // pure v ir tu a l method
>;
declares AC to be an abstract class, namely, a base class that must have a
derived class. AC is made abstract by declaring f as a pure virtual method.
This is done through the assignment statement
v irtu a l void f ( in t ) = 0 ; // f == 0
As a pure v ir tu a l method, f must be defined in a class derived from AC.
For example, the code slice
class D : public AC {
public:
v irtu a l void f ( in t i ) { . . . }
>;
satisfies the requirement that f be defined in a class derived from AC. □
>;
class D : public AC {
p u b lic:
v irtu a l void f ( ) // f defined
>;
www.MathSchoolinternational.com
254 CHAPTER 5 INHERITANCE
>;
class D : public AC {
p u b lic :
v ir tu a l void f ( ) { . . . } // define f
>;
>
is legal.
Miscellany
www.MathSchoolinternational.com
5.4 PO LYM O RPH ISM AND VIRTU AL METHODS 255
f and g are both v irtu a l. Technically, g is declared and defined inside X’s
declaration; but the keyword v ir tu a l is part of g ’s declaration, not its inline
definition. In the case of f , the declaration and definition are separated: the
keyword v irtu a l occurs in the declaration but not in the definition, which
occurs outside X’s declaration. It would be an error for the keyword v ir tu a l
to occur in X : :f ’s definition. □
Exercises
class A {
p u b lic :
void f ( ) { cout « "A!" « endl; >
>;
class Z : public A {
p u b lic :
void f ( ) { cout « "Z!" « endl; }
>;
int mainO
{
A* ptr;
Z z;
ptr = &z;
ptr -> f ( ) ;
return EXIT_SUCCESS;
}
class A {
p u b lic :
void f ( int ) { cout « "A!" « endl; }
>;
www.MathSchoolinternational.com
256 CHAPTER 5 INHERITANCE
class Z : public A {
p u b lic :
void f ( double ) { cout « "Z!" « endl; }
>;
int mainO
A* p tr;
Z z;
ptr = &z;
ptr -> f ( 9999999.9999 ) ;
return EXIT_SUCCESS;
>
class A {
p u b lic :
v irtu a l void f ( ) { cout « "A!" « endl; }
>;
class Z : public A {
p u b lic :
v irtu a l void f ( ) { cout « "Z!" « endl; }
>;
int m a i n O
A* p tr;
Z z;
p tr = &z;
p tr -> f ( ) ;
return EXIT_SUCCESS;
>
class A {
p u b lic :
v irtu a l void f ( int ) { cout « "A!" « endl; >
>;
class Z : public A {
p u b lic :
v irtu a l void f ( double ) { cout « "Z!" « endl; }
>;
www.MathSchoolinternational.com
5.4 PO LYM O RPH ISM AN D VIRTUAL METHODS 257
int main()
{
A* p tr;
Z z;
p tr = &z;
p tr -> f ( 27 ) ;
return EXIT_SUCCESS;
>
class A {
p u b lic :
void f ( ) -[ cout « "A!" « endl; }
};
class Z : public A {
p u b lic :
void f ( ) { cout « "Z!" « endl; }
>;
int m a i n O
A* p tr;
Z z;
p tr = &z;
p tr -> f ( ) ;
ptr -> Z : : f ( ) ;
return EXIT_SUCCESS;
}
class B {
p u b lic :
int f ( int ) ;
>;
class D : public B {
p u b lic :
int f( float );
>;
www.MathSchoolinternational.com
258 CHAPTER 5 INHERITANCE
in t mainO
{
D d l;
B* ptr = &dl;
>
8. Explain why it does not make sense for a v ir tu a l method to be sta tic.
void g ( in t, in t, double ) ;
v ir tu a l in t f ( double ) ;
class A {
p u b lic :
s ta tic v irtu a l void f ( ) { . . . }
>;
class A {
p u b lic :
v irtu a l void f ( ) = 0;
>;
A a l , a2, a3;
class A {
... //no v irtu a l methods here
>;
class B : public A {
p u b lic :
v irtu a l void f ( ) ;
>;
www.MathSchoolinternational.com
5.4 PO LYM O RPH ISM AN D VIRTUAL METHODS 259
class C : public B {
p u b lic:
v irtu a l void f ( ) ;
>;
16. Is Z: : f a v ir tu a l method?
class A {
p u b lic:
v ir tu a l void f ( ) ;
};
class Z : public A {
p u b lic:
void f ( ) ;
>;
class A {
p u b lic:
v ir tu a l void g ( ) ;
>;
v irtu a l void A : : g ( )
{
class A {
p u b lic:
void v ir tu a l h ( ) ;
>;
void A: :h ()
>
www.MathSchoolinternational.com
260 CHAPTER 5 INHERITANCE
Implement the standard binary tree traversals (inorder, preorder, and pos
torder) as v irtu a l functions.
S o lu tio n _______________________________________________________________________
We revise the binary search tree of Section 4.4 so that class BST is now an
abstract or partial class that declares traverse as a pure v ir tu a l function.
There are three derived classes that then define traverse: InBST, PreBST,
and PostBST. The BST methods that create a binary search tree and add
Nodes to it remain unchanged.
#include <iostream.h>
class BST;
class Node {
frie n d BST; // abstract class
frie n d InBST; // derived from BST
frie n d PreBST; // derived from BST
frie n d PostBST; // derived from BST
char v a l; // value == contents
Node* lc ; // l e f t ch ild
Node* rc; // righ t child
p u b lic :
Node(); // constructor
in t empty( ) ; // va l == None
void w r i t e ( ) ;
>;
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : VIRTUAL TREE TRAVERSAL
void InBST::traverseO
inorder( ) ;
>
tree = root;
inorderAux( root ) ;
>
www.MathSchoolinternational.com
CHAPTER 5 INHERITANCE
preorder( ) ;
>
void PreBST::preorder()
tree = root;
preorderAux( root ) ;
>
// stub function
}
BST::BST()
{
root = tree = new Node;
count = 0;
}
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : VIRTUAL TREE TRAVERSAL
Node::Node()
{
lc = rc = 0;
val = None;
>
www.MathSchoolinternational.com
264 CHAPTER 5 INHERITANCE
D iscussion____________________________________________________________________
There are moderate changes to the original code (see Section 4.4). The
most significant is that BST is now an abstract class with traverse as its
pure v ir tu a l method. BST has InBST, PreBST, and PostBST as three de
rived classes, each of which defines traverse. For example, InBST defines
tra verse to perform an inorder traversal of the BST
void InBST: :traverseO
in order( ) ;
>
by invoking local method inorder. PreBST has a comparable local method
preorder that produces a preorder traversal of the BST.
BST now has a copy constructor in addition to the default constructor.
The code for copy constructor is straightforward:
BST::BST( BST& bst )
root = b s t.ro o t;
tre e = b s t.tre e ;
count = b s t.count;
>
Each derived class also has a default and a copy constructor with empty
bodies. The constructors merely invoke their BST counterpart. Here is the
InBST copy constructor:
InBST( BST& bst ) : BST( bst ) { }
The copy constructors have been added to allow code slices such as this:
int mainO
>
www.MathSchoolinternational.com
5.5 SAM PLE A PPLIC A TIO N : VIRTU AL TREE TRAVERSAL 265
The new program is more “object driven” than the original. In the
original program, we build a BST and then explicitly invoke method inorder
to perform an inorder traversal. If we want a preorder traversal instead, then
we must explicitly invoke preorder. In the new program, we can invoke the
v irtu a l function traverse through a pointer, as in the code slice
in t mainO
{
BST* p tr; // pointer to BST
// build a BST of one fla v o r
// or another, e . g . , PostBST
ptr -> tr av er se O ; // object determines what sort
// of tra versa l is performed
}
The object to which p tr points determines what sort of traversal is per
formed. The programmer simply invokes traverse and lets the system
determine at run-time the appropriate v ir tu a l function to call.
Exercises
1. The new code makes BST, InBST, PreBST, and PostBST all friends of
Node. Why must BST still be a friend?
8. Why does the new code have a copy constructor for BST?
9. Explain why the default and the copy constructor for PreBST have empty
bodies.
10. How many definitions of traverse are required so that the pure v ir tu a l
function requirement is met?
11. Summarize the difference in approach between the original BST program
and the new one. Which strikes you as more object-oriented in design?
Justify your answer.
www.MathSchoolinternational.com
CH APTER 5 INHERITANCE
c l a s s B : p u b lic A {
p u b lic :
B () : A () { cout « "B ’ s c o n s t r u c t o r " ; }
~B () { cout « "B ’ s d e s t r u c t o r " ; }
};
i n t mainO
vo id f ( ) ;
f();
r e t u r n EXIT_SUCCESS;
}
vo id f ( )
{
B b;
}
is
A’ s c o n s tru c to r
B’ s c o n s tr u c t o r
B’ s d estru ctor
A’ s d estru ctor
www.MathSchoolinternational.com
5.6 DESTRUCTORS UNDER INHERITANCE 267
"BO
{
d e le te [ ] sB;
cout « "B frees 3 bytes" « endl;
}
>;
sD = new char[ 5 ] ;
cout « "D allocates 5 bytes" « endl;
>
~D()
{
d e le te [ ] sD;
cout << "D frees 5 bytes" « endl;
>
>;
int mainO
D d l;
return EXIT_SUCCESS;
>
is
www.MathSchoolinternational.com
268 CHAPTER 5 INHERITANCE
V irtu a l Destructors
Constructors may not be v irtu a l but destructors may be. The need for
v ir tu a l destructors is best explained through an example.
www.MathSchoolinternational.com
DESTRUCTORS UNDER INHERITANCE 269
int mainO
{
const in t Forever = 1;
void f ( ) ;
// generate lo ts of garbage
while ( Forever ) {
f();
>
return EXIT_SUCCESS;
>
void f ( )
{
B* p = new D; // p points to a D object
d elete p;
>
is
www.MathSchoolinternational.com
270 CHAPTER 5 INHERITANCE
BO
{
ptrB = new char[ 5 ] ;
cout « "B a lloca tes 5 bytes" « endl;
>
d e le te [ ] ptrB;
cout « "B frees 5 bytes" « endl;
>
>;
In this case, p is bound at run-time to the data members and methods of the
object to which it currently points. So if p points to a D object, as in f , then
D: : ~D fires when control exits. B: : ~B also still fires when f exits because
the D object to which p points is, by virtue of inheritance, a B object as well.
With B: : ~B as a v irtu a l destructor, our output becomes
B a llo ca tes 5 bytes
D a llo ca tes 1000 bytes
D fre e s 1000 bytes
B fre e s 5 bytes
□
Exercises
class X {
p u b lic :
XO { cout « "X: :X" « endl; }
~X() { cout « " X: : ~X" « endl; >
>;
www.MathSchoolinternational.com
5.7 M U LT IP LE INHERITANCE 271
class Y : public X {
p u b lic:
Y( ) : X () { cout « "Y ::Y " « endl; >
~Y() { cout « "Y : : ~Y" « endl; }
>;
class Z : public Y {
pu b lic:
Z () : Y ( ) { cout « "Z ::Z " « endl; >
~Z() { cout « "Z::~Z" « endl; }
>;
int mainO
{
Y y;
Z z;
return EXIT_SUCCESS;
}
2. In Exercise 1, make all the destructors virtu a l. Does the code run any
differently than before?
5. Must a derived class destructor invoke a base class destructor if one exists?
www.MathSchoolinternational.com
272 CHAPTER 5 INHERITANCE
single multiple
inheritance inheritance
>;
>;
a ScrollWin is a specialization of a Win. In particular, a ScrollWin has a
horizontal and a vertical scrollbar, which are not present in a Win. □
>;
www.MathSchoolinternational.com
5.7 M U LTIPLE INHERITANCE 273
>;
>;
>;
class iostream :
public istream, public ostream { // input-output
>;
an iostream is a class that supports input and output operations. It com
bines istream, which supports only input operations, and ostream, which
supports only output operations. These classes and others are declared in
the C + + header file iostream. h. Chapter 7 looks closely at the multiple in
heritance hierarchy that C + + provides for input/output. □
The rules of inheritance and access do not change from a single to a multiple
inheritance hierarchy. A derived class inherits data members and methods
from all its bases classes, regardless of whether the inheritance links are
private, protected, or public.
www.MathSchoolinternational.com
274 CHAPTER 5 INH ERITANCE
// a l l public
class Bl { // base class 1
>;
>;
>;
class D :
public B l, public B2, public B3 { // derived class
>;
// a l l private
class BB1 { // base class 1
>;
>;
class DD :
private BB1, private BB2, private BB3 { // derived class
>;
// mixed
class BBB1 { // base class 1
>;
>;
www.MathSchoolinternational.com
5.7 M U LTIPLE INHERITANCE 275
>;
class DD :
private BBB1, public BBB2, public BBB3 { // derived class
>;
void testerO
{
D dl;
d l.x = 999; // lo c a l x
d l. B l: :x = 111; // inherited from Bl
d l.B 2 ::x = 222; // inherited from B2
>
www.MathSchoolinternational.com
276 CHAPTER 5 INHERITANCE
the local x hides the inherited Bl: :x and B2: :x. Further, Bl and B2 each
has a data member named x. The only way to resolve these conflicts is to
use the scope resolution operator in referencing either of the inherited x’s. □
>;
>;
>;
>;
Z inherits x twice from B: once through Dl and again through D2 (see Figure
5.7.2). This is wasteful and confusing. We correct the problem by changing
Dl and D2 into v irtu a l base classes for Z:
c la s s B { // base c la s s
p r o te c t e d :
in t x;
>;
www.MathSchoolinternational.com
5.7 M U LT IP LE INHERITANCE 277
>;
There is now a single copy of x in Z. By making Dl and D2 into v ir tu a l base
classes for Z, we tell them in effect to send to Z only one copy of whatever
they inherit from their own common ancestor B. □
Exercises
class A -[
>;
class B : public A {
www.MathSchoolinternational.com
278 CHAPTER 5 INH ERITANCE
class P {
protected:
in t x;
in t y;
>;
class Q {
protected:
flo a t a;
flo a t b;
>;
class P {
protected:
in t x;
in t y;
>;
class Q {
protected:
flo a t a;
flo a t b;
>;
class R : public P, public Q {
p u b lic :
void f ( ) { . . . }
>;
class B {
protected:
in t x;
>;
www.MathSchoolinternational.com
CO M M O N PR O G R A M M IN G ERRORS 279
class Bl : public B {
protected:
flo a t y;
>;
class B2 : public B {
flo a t z;
>;
};
class B {
protected:
in t x;
class B2 : v ir tu a l public B {
protected:
flo a t z;
>;
>;
class C {
in t x;
www.MathSchoolinternational.com
280 C H A PTE R S INHERITANCE
in t mainO
{
C c l;
c l.x = 6; // * * * * * ERROR: x is p riva te in C
>
>;
in t mainO
C c l;
c l.x = 9; // * * * * * ERROR: x is protected in C
>
>;
>;
www.MathSchoolinternational.com
COM M ON PR O G R A M M IN G ERRORS 281
>;
// ok
class DC : protected BC1, public BC2 {
>;
class B {
in t x;
in t z;
p u b lic:
// constructors — but no defau lt constructor
B( in t a ) { x = a ; z = -1; >
B( in t a l , in t a2 ) ■[ x = a l ; z = a2; }
>;
class Dl : public B {
in t y;
p u b lic:
// * * * * * ERROR: D( in t ) must e x p lic it ly invoke
// one of B’ s constructors
D l( in t a ) { y = a; }
>;
class D2 : public B {
in t y;
p u b lic:
// ok — D2 e x p lic it ly invokes a B
// constructor in it s header
D2( in t a ) : B ( a ) { y = a ; >
};
www.MathSchoolinternational.com
282 CH APTER 5 INHERITANCE
5. If a derived class has more than one base class, then it is an error to omit
a comma that separates the access-specifiers for the base classes. Here
are two examples:
>;
>;
// correct
class DC2 : public BC1, public BC2 {
>;
p u b lic :
void f ( double ) ; // method f
>;
www.MathSchoolinternational.com
COM M ON PR O G R A M M IN G ERRORS 283
p u b lic:
void f ( char* ) ; // CAUTION — hides BC::f
>;
in t mainO
{
DC d;
>
BC:: f is not in the scope of class DC. BC: : f can only be accessed within
class DC by using the scope resolution operator. Furthermore, compile
time binding will be used.
www.MathSchoolinternational.com
284 CH APTER 5 INHERITANCE
10. It is an error to declare a method in a derived class with the same pa
rameter types as a v ir tu a l method in the base class but with a different
return type:
class C {
p u b lic :
v irtu a l in t f ( ) ; // declaration — ok
v irtu a l in t g ( ) in lin e d e fin itio n — ok
>;
>
14. It is an error for an abstract or partial class not to have a derived class.
>;
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 285
>;
DC d e l; // ok — DC derived from AC
5.1. Implement a Library hierarchy with at least a dozen classes. For pur
poses of the exercise, consider a library to be a collection of literary or
artistic materials that are not for sale. In addition to the constructors
and destructors, classes should include methods that describe the class
much in the way that a human librarian might describe a class or subclass
of materials among library’s holdings.
5.2. Implement a LAN (local area network) hierarchy by using the LAN class
of Programming Exercise 4.3 as a base class. Subclasses may be derived
to represent different topologies such as star, ring, bus, and hub. Data
members should represent properties such as transmission medium, access
control method, data frame format, standards, data rate, and the like. For
at least one subclass, simulate the activity of nodes in such a LAN.
5.3. Implement an Employee hierarchy for any type of business with which you
are familiar. The hierarchy should have at least four levels, with inheri
tance of data members and methods. There should be methods for hiring,
firing, promoting, demoting, transferring, and retiring Employees. Also,
there should be methods for calculating raises and bonuses for Employees
in keeping with both their category (e.g., hourly-wage versus salaried)
and their performance. The inheritance hierarchy also should be used to
provide different types of access to Employees. For example, the type of
access granted the general public presumably would differ from the type
of access provided to an Employee’s supervisor, to the payroll depart
ment, or to the FBI. Use inheritance to distinguish among at least four
different types of access to Employee information.
www.MathSchoolinternational.com
CH APTER 5 INHERITANCE
fo r ( i = 0; i < n; i++ ) {
>
fo r ( in t i = 0; i < n; i++ ) {
>
5.6. Implement a Graph hierarchy with Graph as the base class (see Program
ming Exercise 4.9). Sample derived classes are
The hierarchy should have methods appropriate to all graphs (e.g., search
methods) as well as methods particular to a specific type of graph (e.g.,
methods to compute the cost of a path in a WeightedGraph).
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 287
5.7. Implement a hierarchy of numeric data types that extends the fundamen
tal data types such as in t and flo a t available in C + + . You could begin
with classes such as B iglnt (see Programming Exercise 4.1) and Complex
(see Section 3.6). Other candidate classes include Fraction, Vector, and
Matrix. Each class in the hierarchy should have methods that extend,
where appropriate, the built-in arithmetic operators to the class.
5.9. Implement a Task hierarchy that provides classes suitable for simulation.
A Task has basic temporal properties such as
A Task also requires one or more resources. For example, the Task of
mowing the lawn requires a lawn mower, trimming shears, and so on. So a
Task should have data members to reflect resource requirements. A Task
also has temporal constraints with respect to other Tasks. For example,
in steel making, the Task of casting the steel into a bar cannot begin until
the Task of heating the steel has finished. Temporal constraints on Tasks
can be implemented as relations such as
Provide at least half a dozen temporal relations by which the user can
constrain Tasks. Document the methods that define a Task’s public in
terface and include a graphical depiction of the class hierarchy.
www.MathSchoolinternational.com
CH APTER 5 INHERITANCE
5.12. Implement an ErrorCode hierarchy. Error codes are used in data com
munications to detect and to correct errors that occur when digital in
formation is transmitted over a channel from a sender to a receiver. Two
broad classes are ForwardErr and BackwardErr codes: the former codes
include sufficient information so that the receiver can fix a detected error
in place, whereas the latter codes provide only enough information so that
the receiver can detect an error and “fix” it by requesting retransmission
of the data. Subclasses of ErrorCode include parity, block sum, Hamming,
and cyclic redundancy codes. For further details, consult a text in data
communications such as Fred Halsall, Data Communications, Computer
Networks, and Open Systems (New York: Addison-Wesley, 1993).
www.MathSchoolinternational.com
Chapter 6
Operator Overloading
289
www.MathSchoolinternational.com
290 CH APTER 6 OPERATOR OVERLOADING
www.MathSchoolinternational.com
6.1 BASIC OPERATOR OVERLOADING 291
the system could not distinguish between the built-in */, and some user-
defined If */. is overloaded either as a method or as an operator function
that takes a class object as an argument, then the system can determine
which "/, operator to invoke in a particular context.
}
has a class object— a String— as an argument, it does not contain an error
even though operator+ is overloaded as a toplevel function rather than a
method. One String argument would be sufficient to meet the requirement.
□
www.MathSchoolinternational.com
292 CH APTER 6 OPERATOR OVERLOADING
in t mainO
Complex c l ( 1, 1.1 ) ;
Complex c2( 2, 2.2 ) ;
Complex c3( 3, 3.3 ) ;
Complex ans;
ans = c l + c2 * c3;
>
the expression
ans = c l + c2 * c3;
is equivalent to
ans = c l + ( c2 * c3 ) ;
There is no way to change the precedence of the built-in operators + and *
so that, for example, Complex: :+ had higher precedence than Complex::*.
Also, the binary operator + always occurs between its two arguments. There
is no way to overload the binary + so that it occurred either before or after
its two arguments. In similar fashion, the unary + in C + + always occurs
before its argument, even if the operator is overloaded. □
O perator A rity
>
overloads operator+ as a method in class Complex. The code contains an
error because the built-in addition operator + is binary, not ternary. There
fore, the overloaded Complex: : operator+ also must be binary, which means
that it must take one rather than two arguments. Recall that an expression
such as
c3 = c2 + c l; // operator syntax
www.MathSchoolinternational.com
BASIC O PERATOR OVERLOADING 293
is a convenient alternative to
c3 = c2.operator+( c l ) ; // method syntax
In order to be a binary operator, the overloaded Complex: :operator+ thus
needs a single argument because the other operand is a class object such as
c2.
If we overloaded operator+ as a frien d to Complex rather than as a
Complex method, then the operator would take two arguments:
class Complex {
frien d:
void operator+( Complex c l, Complex c2 )
{
};
Note that the + operator is binary as either a method or a toplevel friend.
The issue is one of syntax only. □
}
contains an error because the built-in modulus operator */, is binary, not
unary. Therefore, the overloaded Complex: : operator'/, must be binary as
well, which means that Complex: : operator'/,— a method—needs exactly one
argument. We can correct the error as follows
void Complex: :operator'/,( Complex c )
{
>
□
www.MathSchoolinternational.com
294 CHAPTER 6 OPERATOR OVERLOADING
Exam ple 6.1.8. Here is an overload of the binary operator && as a class
method:
>
>;
in t mainO
{
C c l;
C c2;
>
The operator function takes a single argument, as the other argument is the
class object itself—in this case, cl. Here is the same operator overloaded as
a frie n d to C, but implemented as a toplevel function:
class C {
frie n d :
// not a method — 2 arguments
in t operator&&( C compl, C comp2 )
>
in t mainO
C c l, c2;
i f ( c l && c2 ) // same as: i f ( operator&&( c l, c2 ) )
>
www.MathSchoolinternational.com
6.1 BASIC OPERATOR OVERLOADING 295
Now the operator function takes two arguments, as it is not a method but a
toplevel function. □
The increment ++ and decrement operators — are among those that can
be overloaded in C + + . Recall that each operator comes in a prefix and a
postfix flavor:
int x = 6;
// p re fix ++
// p o stfix ++
Accordingly, we can overload the prefix ++, the postfix ++, the prefix — ,
and the postfix — . Such overloads can be used to ensure, for example, that
pointers to array cells always point to a cell within the array’s bounds. We
begin with an example that overloads the prefix increment operator. We
give the code and then explain it:
#include <iostream.h>
#include <string.h>
#include <stdlib.h >
S a fe S t r::SafeStr()
-C
str = ptr = new char[ 1 ] ;
*s t r = ’ \0’ ;
www.MathSchoolinternational.com
CHAPTER 6 OPERATOR OVERLOADING
s ize = 0;
>
d e le t e [ ] s tr;
>
SafeStr has two variables of type char*: s tr is a p riva te data member
that always points to the first char in a character string, whereas p tr is a
public data member that may point to any char in the string. The code
slice
in t mainO
{
SafeStr s l ( "foo" ) ; // length is 3
>
produces the output
foo
oo
o
. . . // empty strings with lin e feeds
After the loop’s third iteration, s i .p tr points to the cell that holds the null
terminator. The i f test in the overloaded ++ operator
char* S a fe S tr::operator++()
{
i f ( *ptr != ’ NO’ ) // bounds check
return ++ptr; // ok to increment
else
www.MathSchoolinternational.com
BASIC O PERATOR OVERLOADING 297
We now give an example that overloads both prefix and postfix versions
of the increment operator ++. The declaration
op erator+ + ();
with no parameters describes the prefix operator and the declaration
operator++( in t ) ;
with a single in t parameter describes the postfix operator. (Similar com
ments apply to the decrement operator.) The in t parameter in the postfix
form serves to distinguish this form from the prefix form. The parameter
itself may be but need not be used.
If class C overloads the prefix increment operator and obj is an object in
class C, the expression
++obj
is equivalent to
o b j.operator++()
Either expression may be used.
If class C overloads the postfix increment operator and obj is an object
in class C, the expression
obj++
is equivalent to
o b j.operator++( 0 )
Either expression may be used. The method may also be invoked with an
arbitrary argument n:
o b j.operator++( n )
Example 6.1.9. Class Clock overloads both the prefix and postfix ++
operator:
class Clock {
in t hour;
in t min;
in t ap; // 0 is AM, 1 is PM
p u b lic:
Clock( in t, in t, in t ) ;
www.MathSchoolinternational.com
298 CHAPTER 6 OPERATOR OVERLOADING
Clock tic k O ;
void p rin t_tim e ();
Clock o p e rato r+ + (); // ++c
Clock operator++( int ); // C++
>;
hour = h;
min = m;
ap = ap _flag;
>
Clock C lo c k ::tic k ()
{
++min;
i f ( min == 60 ) {
hour++;
min = 0;
>
i f ( hour == 13 )
hour = 1;
return t ic k O ;
>
www.MathSchoolinternational.com
BASIC O PERATOR OVERLOADING 299
Clock c, d;
c = d++;
cout « "Clock c: 11;
c .p r in t_ tim e ();
cout « "Clock d: ";
d .p r in t_ tim e ();
>
is
Clock c: 12:00 AM
Clock d: 12:01 AM
www.MathSchoolinternational.com
300 CHAPTER 6 OPERATOR OVERLOADING
Clock c, d;
c = ++d;
cout « "Clock c: ";
c .p rin t_ tim e ();
cout « "Clock d:
d .p rin t_ tim e ();
>
is
Clock c: 12:01 AM
Clock d: 12:01 AM
□
Exercises
class C {
void op era to r.( C c l, C c2 ) ;
>;
in t op era to r,( in t i l , in t i2 , in t i3 )
>
class C {
in t operator I|( C c l, C c2, C c3 ) ;
>;
www.MathSchoolinternational.com
6.2 SAM PLE A PPLIC A TIO N : BOUNDS CHECKING 301
class C {
p u b lic:
void operator->*( const char* a ) { . . . }
>;
contain an error?
12. Define a class Odd that consists of odd integers. Overload the ++ operator
so that it increments the integer by two.
13. Take a stand for or against the C + + policy that the s ize o f operator
cannot be overloaded.
15. For class C, write code that overloads the comma operator.
www.MathSchoolinternational.com
302 CHAPTER 6 OPERATOR OVERLOADING
C + + Implementation___________________________________
#include <iostream.h>
#include <stdlib.h>
class Matrix {
in t* c e lls ;
int side;
void toobig( int ) ;
void overflow( in t, int ) ;
p u b lic :
M atrix( int ) ; // constructor
"M atrixO ; // destructor
void dumpO; // print contents
intfe operator( ) ( in t, int ) ; // row-col access
>;
// allowable size?
i f ( s > MaxSide ) {
toobig( s ) ;
return;
>
Matrix: : "MatrixO
{
// deallocate storage from constructor
d e le te [ ] c e lls ;
>
www.MathSchoolinternational.com
6.2 SAM PLE A PPLIC A TIO N : BOUNDS CHECKING 303
www.MathSchoolinternational.com
304 CHAPTER 6 OPERATOR OVERLOADING
www.MathSchoolinternational.com
6.2 SAM PLE A PPLIC A TIO N : BOUNDS CHECKING 305
cell’s value. The p riva te method toobig ensures that a Matrix’s side
does not exceed MaxSide, and p riva te method overflow produces the error
message for out-of-bounds references.
Exercises
ml( 3, 9 ) = 88;
\
should single out 9 as the offending index. The index 3 is within bounds.
3. Write the Matrix method copy that copies one Matrix’s cells to the
other’s. The method must ensure that the two Matrixes are of the same
size.
ml.change_dim( 12 ) ; // 12-by-12
It is understood that data may be lost when a Matrix changes its dimen
sions.
www.MathSchoolinternational.com
306 CHAPTER 6 OPERATOR OVERLOADING
10. Modify the Matrix class so that the user can specify, as optional in t
arguments to the constructor, the range of legal indexes. For example,
code such as
Matrix ml( 8, 1, 8 ) ;
S o lu tio n _______________________________________________________________________
#include <iostream.h>
#include <string.h>
class Entry {
char word[ MaxWord + 1 ] ;
chax def [ MaxDef + 1 ] ;
p u b lic :
www.MathSchoolinternational.com
6.3 SAM PLE A PPLIC A TIO N : A N ASSOCIATIVE A R R A Y 307
EntryO
{
strcpy( word, 11" ) ;
strcpy( def, "" ) ;
}
strcpy( word, w ) ;
strcpy( def, d ) ;
>
class D ic tlte r;
class Diet {
friend class D ic tlte r;
Entry e n trie s [ MaxEntries + 1 ] ;
int count; // how many entries
p u b lic :
D ictO -[ count = 0; }
void dumpO ;
void add( const char*, const char* ) ;
void operator[ ] ( const char* ) const;
>;
www.MathSchoolinternational.com
CHAPTER 6 OPERATOR OVERLOADING
void D ie t: : dump()
{
fo r ( int i = 0; i < count; i++ )
e n trie s [ i ] . w r i t e ( ) ;
>
int i = 0;
class D ic tlte r {
int current;
Diet* diet;
p u b lic :
D ic t lt e r ( Dictfe d )
diet = &d;
current = 0;
>
Entry* operator( ) ( ) ;
>;
www.MathSchoolinternational.com
6.3 SAM PLE A PPLIC A TIO N : A N ASSOCIATIVE A R R A Y 309
Entry* D i c t l t e r : :operator( ) ( )
Class Diet contains as data members an array of Entry objects, where Entry
is itself a class, and an in t variable count that tracks how many entries (up
to a maximum of MaxEntries) are currently in the dictionary. An Entry
consists of a word and its definition, each implemented as a character string.
Diet and Entry have identically named methods called add, each expecting
a word and its def. A typical code sequence for adding pairs and then
printing them is:
in t mainO
■C
// Create a diction ary of MaxEntry w ord-definition pairs
Diet d;
>
Method D iet: :add simply invokes Entry: :add on the first open slot in the
dictionary. This slot is indexed by D iet: : count, which is incremented after
each add operation:
void D ict::a d d ( const char* w, const char* d )
{
i f ( count < MaxEntries )
en tries [ count++ ] .add( w, d ) ;
else
cout « count « " exceeds MaxEntries." «
endl;
>
www.MathSchoolinternational.com
310 CHAPTER 6 OPERATOR OVERLOADING
>
shows how D ic tlte r : : operator( ) may be used to iterate through the dic
tionary entries. The loop condition works because D ic t lt e r : : operator ()
returns 0 when it reaches the end of entries.
The syntax
Entry* D ic t lt e r ::o p e r a t o r ()()
>
may look peculiar in that there are two pairs of parentheses right next to
each other. The first pair represents the operator that we are overloading,
which is the function call operator (). The second pair of parentheses is the
argument list for our overloaded function call operator. The list is empty
because our overload of () does not expect any arguments.
Overloading the [ ] and () operators provides the applications program
mer with convenient, intuitive tools for manipulating a dictionary. Such
overloading coats the C + + language with a layer of syntactic sugar so as to
make the language more palatable to its programmers.
Exercises
1. Change class Entry so that its data members are of type String (see
Section 4.1 ) rather than char*.
www.MathSchoolinternational.com
6.4 T Y P E CONVERSIONS 311
2. Change the appropriate methods so that each new Entry preserves sorted
order among the Diet entries.
>
8. Implement
9. Implement
10. Implement
www.MathSchoolinternational.com
312 CHAPTER 6 OPERATOR OVERLOADING
Of course, we could write String methods that mimic s trle n and the
other library functions, but this would be tedious and wasteful. Library
functions are meant to be used, not reinvented. A solution is to overload a
typ e conversion operator so that a String behaves as if it were char*
in contexts that require char*.
Exam ple 6.4.2. We amend the String class to include a type conversion
operator so that a String may be passed to a library function such as
strlen:
class String {
enum SortOrder { Asc, Desc } ;
enum ErrorsIO { ReadFail, W riteFail } ;
char* s tr; // data member — p rivate
in t len; // actual
p u b lic :
>;
return s tr;
>;
Note that neither the declaration nor the definition of the overloaded oper
ator shows a return value, not even void, although the function operator’s
body contains the return statement
return s tr;
It is illegal to give a return value, even void, in either the declaration or the
definition of a type conversion operator.
The first const in the type conversion operator signals that code outside
the String class should not modify the storage to which data member s tr
points. The second const signals that the type conversion operator itself
does not change this storage. The operator returns str, which points to a
null-terminated vector of char. In short, s tr is of type char*. This means
that s tr is a suitable argument to library functions such as strlen. Code
such as
www.MathSchoolinternational.com
T Y P E CONVERSIONS 313
>
Type conversion operators occur in built-in and user-defined classes.
We take an example from the iostream class (see the system header file
iostream.h and Chapter 7).
www.MathSchoolinternational.com
314 CHAPTER 6 OPERATOR OVERLOADING
Exercises
i f ( si ) { // i f ( s tr le n ( s i . s t r ) )
>
>
www.MathSchoolinternational.com
6.5 SAM PLE A PPLIC A TIO N : F IL E SUBSCRIPTS 315
String s l ( "agnes" ) ;
int len = s tr le n ( s i ) ;
would cause the compiler to issue a type violation warning. With the
type conversion operator in place, the compiler is silent. Explain the
disadvantages of silencing such compiler warnings.
Extend array syntax to files so that the user can access a file for reading and
writing as if the file were an indeterminately large, one-dimensional array of
char. In other words, implement a file subscript that behaves as if it were
an array subscript.
S o lu tio n _______________________________________________________________________
C + + Im plem entation_______________________________________________________
#include <stdio.h>
#include <iostream.h>
class F ile ;
class FileRef {
Fileft f i l e ;
char b u ffer;
unsigned long index;
p u b lic :
F ile R e f( File& f , unsigned long i ) :
f i l e ( f ) , index( i ) { }
F ileR ef& operator=( char c ) ;
operator c h a r();
>;
www.MathSchoolinternational.com
316 CHAPTER 6 OPERATOR OVERLOADING
class F ile {
frien d class FileR ef;
p riv a te :
FILE* fp tr;
p u b lic :
F i le ( const char* name ) { fp tr = fopen( name, "wb+" ) ; }
~ F ile () { fc lo s e ( fp tr ) ; }
FileRef operator[ ] ( unsigned long ) ;
Discussion
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : FILE SUBSCRIPTS 317
>
At the syntax level, a F ile now looks like an array of indeterminate
size. A F ile is written or read as if it were an array of char. The C + +
implementation is compact and contains some subtle features.We begin with
a straightforward feature.
The F ile constructor opens the named file in mode wb+, which means
that the file is created if it does not already exist and may be read as well
as written. The F ile destructor closes the file. Once created, a F ile may
be treated as if it were an indeterminately long one-dimensional array. The
file’s actual size is system-dependent, of course. In any case, the file may be
read or written using array syntax. The index must be an integer expression,
however, as the overload of the subscript operator makes no provision for,
say, Strings as indexes. Expressions such as
in t x = 10;
in t y = 20;
char c;
f 1[ 6 ] = ’ A’ ;
f 1C x + y ] = ’ Z>;
c = f l [ y - x ] ;
are all legal.
The overloaded subscript and assignment operators together with the
type conversion operator serve one purpose: to handle situations in which
a subscripted F ile occurs as the source and as the target in an assignment
expression. As a source, a subscripted F ile occurs on the left side of an
assignment; as a target, a subscripted F ile occurs on the right side of an
assignment:
c = fl[ 23 ] ; I I F ile as source
f 1 [ 23 ] = c; // F ile as target
We begin with a subscripted F ile as a target.
In the expression
f 1 [ 10 ] = ’ Q’ ; // F ile as target
the subscript operator
F ileR ef F i l e : : operator[ ] ( unsigned long index )
{
return F ile R e f( *th is , index ) ;
>
returns the value o f the constructor call
www.MathSchoolinternational.com
318 CHAPTER 6 OPERATOR OVERLOADING
Exercises
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : FILE SUBSCRIPTS 319
return *th is ;
instead of with
return th is ;
f 1 [ 2 ] = f 2 [ 3 ] = ’ A’ ;
6. Does the type conversion operator come into play when a subscripted
F ile occurs as the target or right side of an assignment expression? Ex
plain.
7. Does the overloaded assignment operator come into play during F ile
reads and writes? Explain.
www.MathSchoolinternational.com
320 CHAPTER 6 OPERATOR OVERLOADING
>
and
// overloaded as to p le v e l operator function
void* operator new( s ize _ t size )
■C
>
illustrate two overloads of the operator new. The overloaded new operators
both return a void*, just as the built-in new operator does. In this example,
each overloaded operator function expects a single argument of type size_t.
A typical invocation of C: : new would be
C* c l = new C; // a llo ca te a C object
The system uses the overloaded C: :new operator. If such an operator were
not defined, then the system would use the built-in new operator. □
>
contains an error because the first parameter is not of type size_t.
www.MathSchoolinternational.com
M E M O R Y M A N A G E M E N T OPERATORS 321
// overloaded as method
void C::operator d e le te ( void* objPtr )
{
>
and
// overloaded as to p le v e l function operator
void operator d e le te ( void* objPtr )
{
}
illustrate two overloads of the d elete operator. The operator returns void
and expects an argument of type void*, which points to the storage to be
freed. A typical invocation of C: : d elete would be
C* c l = new C; // a llo c a te
d elete c l; // fre e
The system again uses the overloaded d elete if one is present and the built-
in d elete otherwise. □
class Frame {
s ta tic Frame* allFrames;
Frame* nextFrame;
char name[ NameSize ] ;
char data[ DataSize ] ;
p u b lic :
www.MathSchoolinternational.com
322 CHAPTER 6 OPERATOR OVERLOADING
Frame( ) ;
Frame( const char* ) ;
Frame( const char*, const char* ) ;
void p rin t( ) ;
void* operator new( size_t ) ;
>;
Frame::Frame()
■C
name[ 0 ] = d ata[ 0 ] = ’ \0’ ;
>
strcpy( name, n ) ;
d ata[ 0 ] = ’ \0’ ;
p r in t ( ) ;
>
strcpy( name, n ) ;
strcpy( data, d ) ;
p r in t ( ) ;
>
void Frame::p r in t ()
{
cout « name « " created." « endl;
>
www.MathSchoolinternational.com
M E M O R Y M A N A G E M E N T OPERATORS 323
// any storage le f t ?
i f ( allFrames == ( Frame* ) poolEnd ) {
cout « "No more storage fo r Frames."
« endl;
return 0;
>
www.MathSchoolinternational.com
324 CHAPTER 6 OPERATOR OVERLOADING
Frame:: a l l F r a m e s
framePool
framePool
s i z e o f ( F r a me ) bytes
(each chunk with s iz e o f ( Frame ) bytes) so that the chunks then can be
allocated one per Frame (see Figure 6.6.2):
// storage a llocated yet?
i f ( ! allFrames ) {
allFrames = ( Frame* ) framePool;
fo r ( in t i = 0; i < MaxFrames - 1; i++ )
allFrames[ i ] .nextFrame = &allFrames[ i + 1 ] ;
allFrames [ i ] .nextFrame = ( Frame* ) poolEnd;
>
Data member nextFrame points to the next available storage, if any,
in framePool. After MaxFrames have been allocated, nextFrame points to
poolEnd, which means that no more Frames can be allocated. The allocation
itself occurs at the end of new:
Frame* temp = allFrames; // current chunk
allFrames = allFrames -> nextFrame; // next chunk
return temp;
The code slice
in t mainO
{
Frame* f l = new Frame( " f l " ) ;
Frame* f2 = new Frame( "f2 " ) ;
www.MathSchoolinternational.com
CO M M O N PRO G RAM M IN G ERRORS 325
f48 created.
No more storage fo r Frames,
because MaxFrames is currently set to 48.
Exercises
1. Assume that the new operator is overloaded for class Cl but not for class
C2. Explain which new operator, Cl: :new or built-in new, is invoked in
each case:
>
void d e le te ( char* p tr )
{
>
6. Overload the d elete operator for class Frame in Example 6.6.3. A delete
operation should recover the storage so that it can be used to allocate yet
another Frame.
www.MathSchoolinternational.com
CHAPTER 6 OPERATOR OVERLOADING
>
has an error because the overloaded operator is not a method and does
not have a class object among its arguments.
>
is shorthand for
c3 = c2.operator+( c l ) ;
www.MathSchoolinternational.com
PRO G RAM M IN G EXERCISES 327
// ok — + remains binary
Complex Complex::operator+( const c )
{
>
7. It is an error to have the overloaded new operator return any value except
void*.
6.1. Overload a unary operator for the Deck class (see Programming Exercise
3.3) whose invocation results in a Deck’s being shuffled. For example, if
the bitwise complement operator ~ is overloaded, then the code slice
Deck d;
~d; // sh u ffle the Deck
shuffles d.
www.MathSchoolinternational.com
CHAPTER 6 OPERATOR OVERLOADING
6.3. Overload the binary operators +, and * as Set methods (see Program
ming Exercise 3.9). The following code slice illustrates how the operators
work:
6.4. Overload the negation operator ! for the String class (see Section 4.1).
A code slice such as
tISH hINOJOSA
An expression such as
String s ( "Kim" ) ;
// convert to uppercase: KIM
+s;
www.MathSchoolinternational.com
PRO G RAM M IN G EXERCISES 329
String s ( "Kim" ) ;
// convert to lowercase: kirn
-s;
6.6. The BST (binary search tree) class of Section 4.4 has a method addNode
to add nodes to a BST. To add three nodes to a BST requires a code slice
such as
6.7. Provide a type conversion operator for BSTs (see Section 4.4) so that they
can be passed to a string library function such as strlen. For example,
in the code slice
www.MathSchoolinternational.com
330 CHAPTER 6 OPERATOR OVERLOADING
7 is printed to the standard output because bst has seven nodes. The
second statement uses the overloaded function call operator as described
in Programming Exercise 6.6.
6.8. Overload the relational operators <, <=, ==, >=, and > for the Graph class
of Programming Exercise 4.9. If g l and g2 are two Graphs, then the
expression
g l < g2
// create a Spreadsheet
Spreadsheet taxes; // current c e ll is 1st
++taxes; // current c e ll is 2nd
++taxes; // current c e ll is 3rd
— ta xes; // current c e ll is 2nd
!taxes
6.10. Create a class hierarchy with Int as an abstract base class that has In ti,
Int2, and Int4 as derived types. In t i represents a signed integer in one
byte, Int2 represents a signed integer in two bytes, and Int4 represents
an unsigned integer in four bytes:
/-N /■—
s ize o f ( In ti
II II
II II
s ize o f ( Int 2
CN
s
s ize o f ( Int4 ) == 4
www.MathSchoolinternational.com
PR O G R A M M IN G EXERCISES 331
Assume further that your application must do its own memory manage
ment because, for example, it is part of an embedded system with very
limited memory resources. When your application begins to run, it re
ceives m bytes of memory (e.g., 64K bytes). The application then must do
its own memory management. In particular, storage for integers must be
dynamically allocated and freed. Overload the new, the delete, and the
delete [ ] operators as v ir tu a l operator functions that manage alloca
tion and release of storage for In ti, Int2, and Int4. The new operator
should ensure that no more than m bytes of memory have been allocated.
www.MathSchoolinternational.com
www.MathSchoolinternational.com
Chapter 7
7.1 O verview
7.2 The Class ios
7.3 The H igh-Level Input/O utput Classes
7.4 M anipulators
7.5 The File Input/O utput Classes
7.6 Sample Application: A R andom Access File Class
7.7 The Character A rra y Input/O utput Classes
7.8 Sample Application: A H igh-Level C opy Function
7.9 The Buffer Classes
Com m on Program m ing Errors
Program m in g Exercises
333
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS H IERARCHY
Input and output facilities are not part of the C + + language but instead
are furnished through a class library. In this chapter, we explore this class
library in detail.
The class hierarchy for C + + ’s input/output library is complex. We
examine the hierarchy in detail for three reasons. First, this hierarchy il
lustrates the power available by combining polymorphism and multiple in
heritance. Even programmers with no particular interest in the details of
C + + ’s input/output hierarchy can learn important object-oriented design
and coding lessons by attending to these details. Second, most C + + envi
ronments extend the language by providing class libraries (e.g., Microsoft
Visual C + + ’s Foundation Classes, Borland C + + ’s ObjectWindows). Part
of learning C + + is learning how to use class libraries so that time and en
ergy are not wasted in recreating what is already available. Because the
input/output class library is standard within C + + , it is an excellent case
study for the use of class libraries in general. Third, through inheritance
a programmer can extend the input/output classes (see Section 7.6). Such
extensions require a clear understanding of the details of the classes.
Overview
www.MathSchoolinternational.com
7.1 OVERVIEW 335
t
cm \ Stream
y Plan 9 From Outer Space
Input
Stream
Plan 9 From Outer Space )
Output
istream ostream
iostream
www.MathSchoolinternational.com
336 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
Write a Write 1
character buffer
istream_withassign
ostream_withassign
iostream_withassign
Exam ple 7.1.1. Figure 7.1.3 depicts buffered output. When a request is
received to write a character, the character is not written directly to the
output but rather to the buffer. Periodically the buffer is written to the
output. Writing the buffer is called flushing the buffer. In C + + a newline
typically flushes the output buffer. □
www.MathSchoolinternational.com
7.1 OVERVIEW 337
ios
■— ► stream bu f
f il e b u f s trs trea m b u f
the methods in the classes istream and ostream are called high-level in
put/output methods because they access the stream indirectly— by making
calls to the low-level methods in streambuf.
Class streambuf also contains the v ir tu a l methods underflow, which
is responsible for dealing with an attempted read from an empty buffer, and
overflow, which is responsible for dealing with an attempted write to a full
buffer. A class derived from streambuf typically overrides underflow and
overflow so that action appropriate to the specific source or destination
is taken. For example, when the buffer is full, overflow might ignore new
writes or return an error flag, or, if the destination is a file, it might flush
the buffer.
The class file b u f contains constructors and methods for associating a
file b u f object with a file, and the class strstreambuf contains constructors
and methods for associating a strstreambuf object with a character array.
Each overrides underflow and overflow.
One reason that the buffer class hierarchy (Figure 7.1.4) is distinct from
the stream class hierarchy (Figure 7.1.5) is to separate the high-level and
low-level input/output methods. If these hierarchies were combined into a
single hierarchy, some class would necessarily contain both high-level and
low-level input/output methods.
Two additional classes are derived from ios:
fstreambase strstreambase
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
(see Figure 7.1.5). These classes serve as base classes for derived classes that
provide a high-level interface to file and character array input and output.
The class fstreambase contains a buffer member (a member of type
file b u f). The base class ios is connected to this buffer object through a
pointer (see Figure 7.1.4); in this way, fstreambase establishes a connection
to a physical stream— a file. The class fstreambase provides constructors
and methods for opening, attaching, and closing a file.
Class ifstream is derived from both fstreambase and istream; thus,
it contains a file buffer object and methods for reading and moving around
within the stream. Therefore ifstream provides high-level, indirect access
to the file. Class ifstream also inherits from fstreambase methods for
attaching and closing a file. It redefines the method open to assure that the
file is opened in read mode.
Similarly, class of stream is derived from both fstreambase and ostream;
thus, it contains a file buffer object and methods for writing and moving
around within the stream. Class of stream also inherits from fstreambase
methods for attaching and closing a file. It redefines the method open to
assure that the file is opened in write mode.
Class fstream is derived from both fstreambase and iostream; thus, it
contains a file buffer object and methods for reading, writing, and moving
around within the stream. Class fstream also inherits from fstreambase
methods for attaching and closing a file. It redefines the method open to
remove any default protection.
The strstream classes (strstreambase, ostrstream, istrstream , and
strstream), which read and write arrays of characters, are designed similarly
to their f stream counterparts, which read and write files.
The class strstreambase contains a buffer member (a member of type
strstreambuf). The base class ios is connected to this buffer object through
a pointer (see Figure 7.1.4); in this way, strstreambase establishes a connec
tion to a physical stream— an array of characters. The class strstreambase
provides a constructor for establishing a connection with a character array.
Class istrstream is derived from both strstreambase and istream;
thus, it contains an strstreambuf object and methods for reading and mov
ing around within the buffer. Therefore istrstream provides high-level,
indirect access to the character array.
Class ostrstream is derived from both strstreambase and ostream;
thus, it contains an strstreambuf object and methods for writing and mov
ing around within the buffer.
Class strstream is derived from both strstreambase and iostream;
thus, it contains an strstreambuf object and methods for reading, writing,
and moving around within the buffer.
The header file iostream. h declares the classes
www.MathSchoolinternational.com
7.1 OVERVIEW 339
ios
streambuf
istream
ostream
iostream
istream_withassign
ostream_withassign
iostream_withassign
the objects cin, cout, and cerr; and the manipulators endl, ends, flush,
dec, hex, oct, and ws. The header file fstream.h #includes the file iostream.h,
if it was not already included, and declares the classes
file b u f
fstreambase
ifstream
ofstream
fstream
The header file strstream.h #includes the file iostream.h, if it was not already
included, and declares the classes
strstreambuf
strstreambase
istrstream
ostrstream
strstream
Figure 7.1.6 summarizes the classes and functionality given in this sec
tion. In the remainder of this chapter, we look at these classes in detail.
Exercises
1. Print the header files iostream.h, fstream.h, and strstream.h, and identify
the data members and methods referred to in this section.
5. Why not replace class of stream with a class derived from ostream and
file b u f?
www.MathSchoolinternational.com
340 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
Buffer classes
stream buf
fileb u f
strstrea m bu f
In this section we look closely at the base input/output class ios (see Figure
7.1.5). The names used in this section are fairly standard across C + + sys
tems, but the implementation is less standardized. Thus the reader should
be able to use the flags and methods as described herein; the implementation
should be considered merely as an example.
Class ios defines several protected integer members whose bits are used
as flags. For example, the integer member state could be used to indicate
the status of the stream: the first bit is set to indicate end-of-file; the second
bit is set to indicate that the last input/output operation failed; and so on.
The bits are named by using a public enum:
class ios {
p u b lic :
enum io_state {
goodbit = 0x00, // ok — no b it is set
eo fbit = 0x01, // set = eof
fa ilb it = 0x02, // set = la s t i/o operation fa ile d
badbit = 0x04, // set = in valid operation
h a rd fa il = 0x80 // set = unrecoverable error
>;
>;
www.MathSchoolinternational.com
7.2 THE CLASS ios 341
Method Returns
rd stateO the stream state (state)
goodO nonzero if state is zero; otherwise, returns zero
eof () nonzero if e o fb it is set; otherwise, returns zero
fa ilO nonzero if f a i l b i t is set; otherwise, returns zero
badO nonzero if badbit is set; otherwise, returns zero
Because the names names are public, they can be used by the programmer.
However, the programmer cannot directly access the integer member state
containing the flags because this member is protected. Instead, ios fur
nishes public methods to access the status of the stream (see Figure 7.2.1).
do {
cin » i ;
i f ( Ic in .e o fO )
cout « i « endl;
} while ( Ic in .e o fO ) ;
echoes integers in the standard input to the standard output, one per line.
An attempted read beyond the end of the stream is required to set e o fb it;
thus, the following code that attempts to echo integers in the standard input
to the standard output is not correct; an extra line is printed:
in t i ;
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS H IERARCH Y
The member clea r replaces the stream state with the value passed or 0
if no argument is passed.
clears all of the standard input status flags, including the end-of-file flag. □
Class ios overloads the not operator ! and provides a conversion from
ios to void*. The declarations are
class ios {
p u b lic :
operator v o id * ();
in t o p era to r!( ) ;
>;
The operator void* converts ios to the pointer value zero if state is
nonzero, and it converts ios to a nonzero pointer value if state is zero.
Similarly, the overloaded not operator returns nonzero if state is nonzero,
and it returns zero if state is zero.
Class ios declares an enum to give names to flag bits to indicate modes
as shown in Figure 7.2.2. These flags are typically used in classes derived
from ios.
Exam ple 7.2.5. The class of stream has a constructor whose first argument
is a file name (see Section 7.5), and whose second argument is ored with
i o s : : out (to open the file for output) after which it becomes the initial
mode. Thus
ofstream fo u t( "ou t.d at", ios::app ) ;
www.MathSchoolinternational.com
7.2 THE CLASS ios 343
Name Purpose
in Open for reading
out Open for writing
ate Open and move to end-of-stream
app Open for appending
trunc Discard stream if it already exists
nocreate If stream does not exist, open fails
noreplace If stream exists, open for output fails unless ate or app is set
binary Open as a binary stream
Name Purpose
beg Seek from the beginning
cur Seek from the current position
end Seek from the end
creates an of stream object associated with the file out.dat, which is opened
for appending (writing at the end of the file). □
Class ios declares an enum to give names to flag bits to indicate how
to seek (move) in the stream as shown in Figure 7.2.3. These flags are also
typically used in classes derived from ios (see Section 7.3).
Example 7.2.6. The method seekp is defined in the output class ostream
(see Section 7.3). One form of seekp has two arguments: the first is an
offset, and the second is the direction. If out is an object in class ostream,
the expression
out.seekp( 10, io s ::c u r )
moves the current position in the stream 10 bytes forward. □
Class ios declares an enum to give names to flag bits to indicate how to
format the stream as shown in Figure 7.2.4. Also, ios furnishes methods to
read, set, and clear the format flags (see Figure 7.2.5) and methods to read
and change the field width, the fill character, and the number of digits of
floating-point precision (see Figure 7.2.6).
www.MathSchoolinternational.com
344 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS H IERARCH Y
Name Purpose
skipws Skip white space
le ft Left-justify
rig h t Right-justify
in tern al Padding after sign or base flag
dec Decimal
oct Octal
hex Hexadecimal
showbase Use base indicator on output
showpoint Print trailing zeros in floating-point numbers
uppercase Use uppercase letters on hex output
showpos Use + with positive integers
s c ie n t ific Use scientific notation for floating-point numbers: d.dddEdd
fix e d Use fixed notation for floating-point numbers: d.ddd
unitbuf Flush any stream after write
stdio Flush standard output and standard error after write
I ios::showpoint
I ios::uppercase
I ios::fixed );
saves the old flags in o ld _fla gs and formats the standard output as left-
justify output, print integers in hexadecimal, print trailing zeros, print hex
adecimal output using uppercase letters, and print floating-point output as
dd.dddddd. □
o l d _ f i l l = c o u t . f i l l ( ’ 0’ ) ;
// w rite to standard output
c o u t .fill( o ld _ fill );
changes the fill character to zero and saves the old fill character in o ld _f i l l .
After writing to the standard output, it restores the original fill character.
The same effect could be obtained more easily by using manipulators (see
Section 7.4). □
Exam ple 7.2.9. The method setf, with one argument, sets the specified
format flags without changing the other flags. For example, the statement
cout.setf( ios::showbase );
www.MathSchoolinternational.com
7.2 THE CLASS ios 345
Method Purpose
f l a g s () Return a long that shows the
format flags
f l a g s ( long ) Set the format flags to the
long passed and return the
old flags
s e t f ( long ) Set specified flags and return
the old flags
s e t f ( ios: :dec, i o s : : basefield ) Set integer base to decimal
and return the old flags
s e t f ( i o s : :o ct , i o s : : basefield ) Set integer base to octal and
return the old flags
s e t f ( ios::hex, i o s : : b a s e f i e l d ) Set integer base to hex and re
turn the old flags
s e t f ( i o s : : l e f t , i o s : : ad ju s tf i el d ) Set left justification and re
turn the old flags
s e t f ( i o s : : r i g h t , i o s : : ad ju s tf i el d ) Set right justification and re
turn the old flags
s e t f ( i o s : : i n ter nal , i o s : :ad ju s tf i el d ) Put fill character between sign
and value and return the old
flags
setf( io s :sc ie n t ific , ios::floatfield ) Set scientific notation and re
turn the old flags
s etf( ios::fixed, io s : :fl o a t fi e l d ) Set fixed notation and return
the old flags
s e t f ( 0, i o s : : f l o a t f i e l d ) Set default notation and re
turn the old flags
unsetf( long ) Clear specified flags and re
turn the old flags
Figure 7.2.5 Methods to read, set, and clear the format flags.
Method Purpose
width ( ) Return the field width
width( int ) Change the field width and return the old width (the width
reverts to 0 after the next number or string is written)
fillO Return the fill character
f i l l ( char ) Change the fill character and return the old fill character
precisionQ Return the precision (number of digits of floating-point
precision)
p recisio n ( in t ) Change the precision and return the old precision
Figure 7.2.6 Methods to read and change the field width, the fill character, and the
precision.
www.MathSchoolinternational.com
346 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
causes subsequent output to show the integer base; that is, octal integers
will be printed with a leading zero, hexadecimal integers will be printed
with a leading Ox, and decimal integers will be printed in the usual way.
The preceding statement is equivalent to
c o u t.fla g s ( c o u t.fla gs() I i o s : : showbase ) ;
□
Exam ple 7.2.10. Example 7.2.9 shows how s e tf can be used to change
the format when only a single flag is involved. The situation is more complex
when several flags are involved. For example, to format integer output as
hexadecimal, the hex bit must be set and the dec and oct bits cleared.
To simplify changing the format when several flags are involved, s e tf can
take a second argument. For example, output can be formatted as decimal,
hexadecimal, or octal by using b a sefield as the second argument to setf.
The output from the following code
c o u t.s e tf( io s::h ex , io s : : b a sefield ) ;
cout « "Hex: 11 « 168 « endl;
c o u t.s e tf( io s ::o c t , io s : :b a sefield ) ;
cout « "Octal: " « 168 « endl;
is
Hex: a8
Octal: 250
□
Exam ple 7.2.11. We can modify the code of Example 7.2.10 so that the
output shows the base, and uppercase letters are used on hexadecimal out
put:
c o u t.s e tf( io s : : showbase | i o s : :uppercase ) ;
c o u t.s e tf( io s::h ex , i o s : :b a sefield ) ;
cout « "Hex: " « 168 « endl;
c o u t.s e tf( io s ::o c t , io s ::b a s e fie ld ) ;
cout « "Octal: " « 168 « endl;
The output is now
Hex: 0XA8
Octal: 0250
□
Exam ple 7.2.12. We can left- or right-justify output by using adju stf ie ld
as the second argument to setf. The output from the following code
www.MathSchoolinternational.com
THE CLASS ios 347
cout.width( 6 ) ;
cout « -100 « endl; // d efau lt is r ig h t - ju s t ify
cout.width( 6 ) ;
c o u t.s e tf( i o s : : l e f t , io s ::a d ju s t fie ld ) ;
cout « -100 « endl;
cout.width( 6 ) ;
c o u t.s e tf( io s ::r ig h t , io s : : a d ju s tfie ld ) ;
cout « -100 « endl;
-100
-100
-100
-100
In C ++, if the output is larger than the width, the output is written anyway
in a field whose width is equal to the width of the item to write. Thus, in
the last line, the output is right-justified in a field of width four.
Another option that can be used with a d ju s tfie ld is internal, which
uses the fill character to pad between the sign and the value. For example,
the output from the following code
cout.width( 6 );
cout.fill( ’ 0 ’ );
c o u t.s e tf( i o s : : in te rn a l, i o s : : a d ju s tfie ld ) ;
cout « -100 « endl;
is
-00100
□
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
on our system is
4 .971499e-01
0.49715
On our system, the default precision (which can be changed using the
method precision ) is six. Thus, in the first line of output, six digits are
printed to the right of the decimal point. Notice that the value is rounded.
In the second line of output, the sixth digit to the right of the decimal point
is zero and, by default, is not printed. (Trailing zeros can be printed by
setting the showpoint flag.) Again, the value is rounded. □
Exam ple 7.2.14. The method unsetf always takes only one argument. It
clears the specified flags. For example, the statement
c in .u n s e tf( ios::skipw s ) ;
clears the skipws flag so that white space is not skipped. (The default is to
skip white space.) □
www.MathSchoolinternational.com
7.2 THE CLASS ios 349
Exercises
2. Write a statement that clears io _ o b j’s e o fb it and does not change any
other status bit.
i f ( !cin ) {
5. Write a statement that moves the current position in the file associated
with the object f out in class ostream 10 bytes from the end of the file.
6. Write a statement that formats the standard output as follows: skip white
space, right justify, use decimal conversion, use + with positive integers,
and use fixed notation for floating-point numbers.
7. Use the method s e tf to set the showpoint flag on the standard output.
8. Using only the method fla g s, set the showpoint flag on the standard
output. Do not change any other format flag.
9. Use the method unsetf to clear the showpoint flag on the standard
output.
10. Using only the method fla g s, clear the showpoint flag on the standard
output. Do not change any other format flags.
11. Use the method s e tf to set the integer base to octal on the standard
output.
12. Using only the method fla g s, set the oct flag, and clear the dec and hex
flags on the standard output.
13. Use the method s e tf to restore the default notation for floating-point
output on the standard output.
www.MathSchoolinternational.com
350 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
cout. s e t f ( i o s : : showpos ) ;
c o u t.s e tf( i o s : : l e f t , i o s : : a d ju s tfie ld ) ;
c o u t . f i l l ( ’ X’ ) ;
cout.width( 6 ) ;
cout « 66;
cout.width( 6 ) ;
cout « 66 « 66 « 66 « endl;
istream
www.MathSchoolinternational.com
7.3 THE HIGH-LEVEL IN P U T / O U T P U T CLASSES 351
>;
and provides high-level methods for input streams.
The method get is overloaded and so can be invoked in various ways.
When the version of get whose declaration is
istreamft g e t ( signed char* a, in t m, char c = ’ \n’ ) ;
is invoked, characters are read from the stream into the array a until the
character c (whose default value is ’ \n’ ) is encountered, until end-of-stream,
or until m - 1 characters have been read into a, whichever happens first.
The character c is not placed in the array a, nor is it removed from the
stream. The method get adds a null terminator ’ \0\ Notice that get
never stores more than m characters in a. This version of get resembles the
C function fgets. It is different from f gets in that f gets stores the newline
terminator and removes it from the stream. The method get returns the
(updated) stream that invoked it.
>
The stream return value is converted to type void*, which is zero on an
error condition such as end-of-file, and nonzero, otherwise. □
Exam ple 7.3.2. The following code reads a line (defined as ending with a
newline) and then checks to see whether the line read was too long to store:
const in t lin e _ le n = 81;
char a [ lin e _ le n ] , c;
c in .g e t( a, lin e _ le n ) ;
c in .g e t( c ) ;
www.MathSchoolinternational.com
352 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
if ( c != ’ \nJ )
cout « "Line too lon g." « endl;
□
www.MathSchoolinternational.com
THE HIGH-LEVEL IN P U T / O U T P U T CLASSES 353
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
When » is used for input, the default action is to skip white space, even
for type char (unlike scanf in C).
Exam ple 7.3.4. The type charfe is used to read one character. For the
input
x y z
the code
char c;
while ( cin » c )
cout « c;
cout « endl;
prints
xyz
since white space is skipped. □
The type char* is used with » to read a string. If the field width is
zero (the default), white space is skipped, after which all non-white space
characters up to the next white space character are read and stored. If
the width is set to n, white space is skipped, after which all non-white
space characters up to the next white space character, or n - 1 characters,
whichever occurs first, are read and stored. In either case, a null terminator
is added.
The skip white space option can be disabled by clearing the skipws flag.
Exam ple 7.3.6. The following code echoes the standard input to the stan
dard output:
www.MathSchoolinternational.com
THE HIGH-LEVEL IN P U T / O U T P U T CLASSES 355
char c;
while ( cin » c )
cout « c;
cout « endl;
□
For integer types, if the first non-white space character is not a digit or a
sign, f a i l b i t is set and no further data can be read until f a ilb it is cleared.
Similarly, for floating-point types, if the first non-white space character is
not a digit, a sign, or a decimal point, f a i l b i t is also set and no further
data can be read until f a i l b i t is cleared.
Example 7.3.7. The following program accepts integer input and echoes
it in hexadecimal. If the input is not an integer, a message is printed and
the user is prompted to reenter the item:
#include <iostream.h>
#include <std lib.h >
enum { fa ls e , true } ;
in t mainO
{
int v a l , ok;
char l i n e [ 80 ] , c ;
cout « hex;
fo r ( ; ; ) {
cout « "Enter an integer (negative to q u i t ) : "
« flush ;
ok = true;
cin » v a l; // i f val is i l l e g a l , state != 0
i f ( cin .rd sta te O ) {
cout « "Bad input. Redo." « endl;
c in .c le a r ( ) ; // clear state so input can be read
c in .g e t( lin e , 80 ) ; // read and dump bad input
c in .g e t( c ) ; // read and dump ’ \n’
ok = fa ls e ;
}
www.MathSchoolinternational.com
356 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
if ( ok )
i f ( va l < 0 )
break;
else
cout « va l « endl;
}
return EXIT_SUCCESS;
}
□
ostream
www.MathSchoolinternational.com
THE HIGH-LEVEL IN P U T / O U T P U T CLASSES 357
www.MathSchoolinternational.com
358 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
flushes the buffer. The method flush returns the stream which invoked it.
It resembles the C function fflush.
The class ostream overloads the left-shift operator for formatted output.
A typical declaration is
ostreamfe o p e r a t o r « ( short ) ;
Here a short is written, after which the stream is returned.
Among the types handled by « are
Either version
ostreamft o p e r a t o r « ( const signed char* ) ;
ostreamft o p e r a t o r « ( const unsigned char* ) ;
writes a null-terminated string to the output stream.
The version
ostreamft o p e r a t o r « ( void* ) ;
writes the value of a pointer to the output stream.
www.MathSchoolinternational.com
7.3 THE HIGH-LEVEL IN P U T / O U T P U T CLASSES 359
iostream
Class iostream is publicly inherited from both istream and ostream. Its
entire declaration is
class iostream : public istream, public ostream {
p u b lic:
iostream( streambuf* ) ;
v irtu a l ~ iostream ();
protected:
iostreamO ;
>;
thus it provides high-level methods for input/output streams.
T h e withassign Classes
www.MathSchoolinternational.com
360 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS H IERARCH Y
streambuf object whose address is passed with the stream and does a com
plete initialization.
Similarly, ostream_withassign is publicly inherited from ostream and
it adds an overload of the assignment operator; iostream_withassign is
publicly inherited from iostream and it adds an overload of the assignment
operator.
Exercises
1. Write a statement that reads the next 100 bytes from the standard input
(white space or not) and stores them in the char array a.
2. Write a statement that reads and discards the next 100 bytes from the
standard input (white space or not).
c in .ig n o re ( 50 ) ;
cout « cin.gcount( ) « endl;
Assume that the standard input is abcde (with e as the last character).
Tell which character would next be read after each sequence of statements
in Exercises 4-8 is executed.
6. cin .seek g( 2 ) ;
cin .seek g( 1, io s ::c u r ) ;
10. Write a code slice that reads strings, delimited by single quotes, from the
standard input until end-of-file and stores the strings in a two-dimensional
array of char. Example: If the input is
www.MathSchoolinternational.com
7.4 M A N IPU LA TO R S 361
Marty Kalin would be read and stored as the first string and Don Knuth
would be read and stored as the second string. Assume that there are no
errors in the input.
11. Write a code slice that reads lines (terminated by ’ \n’ ) from the standard
input and stores them in a two-dimensional array of char. Reading stops
when a line containing only ’ \n’ is encountered. This newline is removed
from the standard input but is not stored. Example: If the input is
Marty Kalin
Don Knuth
Grace S lick
the strings Marty Kalin and Don Knuth would be read and stored. The
file position marker would be on G in Grace Slick. Assume that the
standard input begins with a nonblank line.
12. Write a statement to write 50 characters from the char array a to the
standard output.
13. Overload « to print a zip code for the zip code class of Section 3.4.
7.4 Manipulators
We introduced manipulators in Section 2.4; here, we look at them in detail.
A manipulator is a function that either directly or indirectly modifies a
stream. For example, the system manipulator hex causes subsequent input
or output to be hexadecimal. A manipulator is used with the overloaded
input operator » or the overloaded output operator « . For example,
in t i = 10;
cout « hex « i « endl;
prints the value 10 in hexadecimal.
Several manipulators are predefined (see Figure 7.4.1). To use predefined
manipulators with no arguments (e.g., endl), include iostream.h. To use
predefined manipulators with arguments (e.g., s e tf i l l ) , include iomanip.h.
Example 7.4.1. We can rewrite Example 7.2.11 in which the output shows
the base, and uppercase letters are used on hexadecimal output:
cout « s e tio s fla g s ( i o s : : showbase I i o s : : uppercase )
« hex « "Hex: " « 168 « endl
« oct « "Octal: " « 168 « endl;
□
www.MathSchoolinternational.com
362 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
www.MathSchoolinternational.com
M A N IPU LA TO R S 363
return ( * f ) ( *th is ) ;
>
The argument f to o p e r a to r « is of type “pointer to a function with one
argument of type ostreamfe that returns type ostreamfe.” In practice, f is
a pointer to a manipulator. The method o p e r a to r « simply invokes the
manipulator to which f points.
os « ’ \n’ ;
return o s .flu s h O ;
}
When the statement
cout « endl;
is executed, o p e r a to r « is invoked as
c o u t.o p e r a to r «( endl ) ;
The body of o p e r a to r «
return ( * f ) ( *th is ) ;
is equivalent to
return endl( cout ) ;
which in turn is equivalent to
cout « ’ \n’ ;
return cout.f l u s h ( ) ;
www.MathSchoolinternational.com
364 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
Exam ple 7.4.4. We use the following template from iomanip.h that facil
itates writing one-argument manipulators:
template< class Typ > class OMANIP {
Typ n;
ostreamfe ( * f ) ( ostreamfe, Typ ) ;
p u b lic :
OMANIP( ostreamfe ( * f l ) ( ostreamfe, Typ ) , Typ nl )
: f ( f 1 ) , n( nl ) { }
frien d ostreamfe o p e r a t o r « ( ostreamfe os, OMANIPfe oman )
{ return om a n .(*f)( os, oman.n ) ; }
>;
The parameterized type Typ describes the type of the manipulator’s argu
ment. In our case, the type is int.
^Sorne older versions o f C + + may use macros rather than a parameterized class.
www.MathSchoolinternational.com
M A N IPU LATO RS 365
return os;
}
and the b e ll manipulator as
0MANIP< in t > b e l l ( in t n )
■C
return 0MANIP< in t >( b e ll_ rin g e r, n ) ;
>
The b e ll manipulator can be invoked as
cout « b e l l ( 10 ) ;
which is equivalent to
o p e r a t o r « ( cout, b e l l ( 10 ) ) ;
Because cout is a type derived from ostream and b e ll returns type
0MANIP< in t >, the correct version of « is invoked (i.e., the frien d version
in class 0MANIP< in t > that takes such an argument).
When the expression
0MANIP< in t >( b e ll_ rin g e r, n )
in b e ll is evaluated, the constructor for 0MANIP< in t > is invoked, and an
object temp of type 0MANIP< in t > comes into existence. The constructor
initializes f to b e ll_ rin g e r and n to 10. The function b e ll then returns
temp, which becomes the second argument to operator<<.
When o p e r a to r « executes with arguments cout and temp, it in effect
returns
b e ll_ r in g e r ( cout, 10 )
The bell is rung 10 times and the updated cout is returned. □
Although our examples in this section have dealt with ostream, exactly
the same techniques can be used to write manipulators for ios and istream.
The templates
SMANIP< class Typ >
www.MathSchoolinternational.com
366 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
Exercises
fstreambase
ofstream
ifstream
fstream
www.MathSchoolinternational.com
7.5 THE FILE IN P U T / O U T P U T CLASSES 367
fstream base
Its constructors, destructor, and methods contain code for associating files
with fstreambase objects.
Class fstreambase serves as a base class for the file input/output classes
of stream, ifstream, and f stream, which are the classes typically used by a
programmer to manipulate files. Each of of stream, ifstream, and f stream
is also derived from the corresponding stream class (ostream, istream,
or iostream) and, so, has methods for associating files with of stream,
ifstream, or fstream objects as well as methods for moving around in
files and for reading or writing files.
The derived classes of stream, ifstream, and f stream contain construc
tors, destructors, and methods with behavior similar to those in fstreambase.
Indeed, the definitions of the constructors, destructors, and methods in these
derived classes typically contain calls to the corresponding constructors, de
structors, and methods in fstreambase, where the actual implementation
takes place. Because of the similarity of the constructors, destructors, and
methods in fstreambase and the derived classes, we give examples only for
the derived classes.
The default constructor whose declaration is
fstreambase( ) ;
is used when an fstreambase object is created, but a file is not attached to
the object.
The constructor whose declaration is
fstreambase( const char* filename,
in t mode,
in t prt = f i l e b u f : : openprot ) ;
is used to associate an fstreambase object with the file filename, which
is opened in mode mode. The mode is described by oring mode bits de
fined in ios (see Figure 7.2.2). The static member openprot is declared
in class file b u f; it provides default protection when a file is opened. This
constructor provides a system defined buffer.
Among other things, the destructor
"fstreambase( ) ;
www.MathSchoolinternational.com
368 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
ofstream
>;
It contains constructors, a destructor, and methods to associate output files
with o f stream objects. The class of stream inherits methods from ostream
to write and move within files.
The default constructor whose declaration is
of streamO ;
is used when an of stream object is created, but a file is not attached to the
object.
The constructor whose declaration is
ofstream ( const char* filename,
in t mode = io s ::o u t,
in t prt = f i l e b u f : : openprot ) ;
is used to associate an of stream object with the file filename, which is
opened in mode mode. The default mode is output. If a mode is specified,
it is automatically ored by the constructor with io s: :out.
Recall (see Section 7.2) that an ios object can be used as a condition
in a statement. Since ofstream is indirectly derived from ios, an ofstream
object can be used as a condition.
www.MathSchoolinternational.com
THE FILE IN P U T / O U T P U T CLASSES 369
ofstream fo u t( "data.out" ) ;
i f ( Ifout )
cerr « "Can’ t open data.out\n";
attempts to open the file data.out for output. If the file cannot be opened,
an error message is written to the standard error. □
The method close, which is inherited from fstreambase, closes the file,
if any, attached to the ofstream object.
Example 7.5.4. The file data.dat associated with the ofstream object
fout of Example 7.5.3 may be closed with the statement
fo u t. c lo s e ( ) ;
www.MathSchoolinternational.com
370 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
ifstream
www.MathSchoolinternational.com
7.5 THE FILE IN P U T / O U T P U T CLASSES 371
has the same effect as that of Example 7.5.5. The file data.in is opened for
input and the ifstream object fin is associated with this file. □
The method close, which is inherited from fstreambase, closes the file,
if any, attached to the ofstream object.
Example 7.5.7. The following program copies one file to another. The
files, whose names are supplied on the command line, are opened in binary
mode so that the program performs a byte-for-byte copy.
#include <stdlib.h>
#include <fstream.h>
char c;
while ( f i n . g e t ( c ) )
fo u t.p u t( c ) ;
return EXIT_SUCCESS;
>
□
fstream
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
The method close, which is inherited from fstreambase, closes the file,
if any, attached to the fstream object.
The next section gives a major example involving the class fstream.
www.MathSchoolinternational.com
7.6 SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 373
Exercises
4. Since we could open a file for input and output with the statement
5. The following code attempts to open the file data.dat for input, do some
processing, close it, reopen it for output, and then do more processing.
What is the error?
// open f i l e fo r reading
ifstream f ( "data.dat" ) ;
// process
f .c lo s e ();
// open f i l e f o r w ritin g
ofstream f ( "data.dat" ) ;
// process
7. Write a complete program that copies files in the order listed on the
command line (the first file— the executable— is skipped) to the standard
output. Files that cannot be opened for reading are ignored. (This pro
gram is similar to the UNIX utility cat.)
A random access file is a file in which we can access records in any order
whatsoever and not necessarily in physical order. We implement a random
www.MathSchoolinternational.com
374 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS H IERARCH Y
access file class that allows the user to create and use a random access file.
In particular, the user can add a record, find a record, or remove a record.
In our implementation, the data read and written are binary data, so
that any kind of data can be stored and retrieved from the file. The user
can directly manipulate the binary data, or a class could be created as an
interface to the binary data.
The following sample input/output shows the random access file class in
action. We first create a new file. Although the random access file class
allows records and keys of any size, the records here are five bytes long to
simplify the example. The first three bytes make up the key. User input is
underlined.
New f i l e (Y/N)? y
[A] dd
[F]ind
[R]emove
[Q ]uit? a
Which record to add? 125xx
Record added
[A] dd
[F]ind
[R]emove
[Q]uit? f
Key? 125
Record found: 125xx
[A] dd
[F]ind
[R]emove
[Q ]uit? f
Key? 130
Record not found
[A] dd
[F]ind
[R]emove
[Q]uit? r
Key? 125
Record removed
www.MathSchoolinternational.com
7.6 SAM PLE APPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 375
[A] dd
[F]ind
[R]emove
[Q]uit? f
Key? 125
Record not found
[A] dd
[F]ind
[R]emove
[Q]uit? q
S o lu tio n _______________________________________________________________________
We use a relative file, that is, a file in which a record’s relative address
(as opposed to its physical address) is its position in the file: first, second,...
Given a key, we can translate it into a relative address. Once we have the
relative address, we can quickly determine approximately where the record is
located in the file and then access it directly. A relative file is thus analogous
to an array. Just as each of the array’s elements has a position relative to
the first, so each element in a relative file has a position relative to the first.
The records in a relative file are stored contiguously following the file
header, whose purpose we will explain later. The first byte of a record,
which is not part of the logical record, holds a status flag that indicates
whether a record is stored (T for “taken” ), whether a record was stored but
deleted (D for “deleted” ), or whether a record was never stored (F for “free” ).
The remaining bytes store the key and the rest of the record. If, as in the
sample input/output, the logical records are five bytes, the file appears as
in Figure 7.6.1, assuming a 256-byte header.
To access a record, we define a hash function h that, given a key,
produces a relative storage address:
Although there are many different ways to define hash functions, our imple
mentation uses the division-remainder method. We define the hash function
www.MathSchoolinternational.com
376 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
14 42 31 6
Relative address: 0 1 2 3 4 5 6 7 8 9 10 11 IS
14 43 31 6 135
Relative address: 0 1 2 3 4 5 6 7 8 9 10 11 IS
h by the rule
h{ key ) = key % divisor
where the modulus operator % yields the remainder after dividing key by
divisor. For example, if key is 134 and divisor is 13, the record’s relative
address is 4. If divisor is ra, the relative addresses range from 0 through
n — 1.
When two distinct keys hash to the same relative storage address, we say
that a collision occurs. For example, if our hash function is
h( key ) = key % 13
we have
h( 134 ) = 4 = h( 147 )
There is a collision: The keys 134 and 147 map to the same relative address.
Any hashing system must provide a collision resolution policy— a
way of handling collisions. Our collision resolution policy is called linear
probing. When a collision occurs, we simply move to the next highest
relative address (with the first record position assumed to follow the last
record position). For example, if we insert the keys 42, 6, 31, and 14 in
the relative file with relative addresses 0 through 12 using the hash function
h( key ) = key % 13, we obtain the situation shown in Figure 7.6.2. Now
suppose that we insert the key 135. Because
h( 135 ) = 5 = h( 31 )
a collision occurs. Using linear probing, we insert 135 in the next highest
unoccupied spot, 7. We obtain the situation shown in Figure 7.6.3.
Divisors should be chosen to minimize collisions. Research and experi
ence show that divisors with no small prime factors do reasonably well at
avoiding collisions. Avoiding collisions requires more than a good divisor,
however. As more and more records are added to a relative file, collisions
become more likely. A file’s load factor, defined as
www.MathSchoolinternational.com
7.6 SAM PLE APPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 377
( addr + 1 ) % divisor
If the record at relative address addr has status F (free), the search termi
nates unsuccessfully since, if the record were present, we would have found
it before reaching the free slot. If the record at relative address addr has
status D (deleted), we must continue the search by checking the record at
relative address
( addr + 1 ) % divisor
since the record we are searching for may have been inserted before the
record at address addr was deleted and would thus be found after further
probing.
Distinguishing between free and deleted slots usually allows us to termi
nate the search for a nonexistent record before searching the entire file.
#include <stdio.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h >
#include <ctype.h>
www.MathSchoolinternational.com
378 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
long key_size;
long total_bytes;
long no_records; // no of records stored
long loc_address; // computed by locate
char* b u ffe r; // holds one record
char* stored_key; // holds one key
long get_address( const char* ) ;
int lo c a te ( const char* ) ;
p u b lic :
frandomO ;
frandom( const char* ) ; // open existing f i l e
frandom( const char*, in t, in t, int ) ; // open new f i l e
"frandomO ;
void open( const char* ) ; // open existing f i l e
void open( const char*, in t, in t, int ) ; // open new f i l e
void c lo se O ;
long g e t _ s lo t s () { return s lo ts; }
long get_record _size() { return record_size; >
long get_key_size() { return key_size; }
long ge t_to ta l_b y te s() { return total_bytes; }
long get_no_records( ) { return no_records; }
in t add_record( const char* ) ;
in t find_record( char* ) ;
in t remove_record( const char* ) ;
>;
frandom: : "frandomO
if ( isopen ) {
delete [ ] stored_key;
delete [ ] bu ffer;
char b u f f [ header_size ] ;
fo r ( int i = 0; i < header_size; i++ )
b u ff[ i ] = ’ ’ ;
s p r in t f( b u ff, "‘/.Id ‘/.Id %ld ’/.Id",
slo ts , record_size,
key_size, no_records ) ;
seekp( 0, i o s : :beg ) ;
w rite ( b u ff, header_size ) ;
}
>
www.MathSchoolinternational.com
7.6 SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 379
fstream::open( filename,
i o s : : in I
i o s : :out |
io s : : binary |
io s : :nocreate ) ;
if ( isopen ) {
char b u f f [ header_size ] ;
read( b u ff, header_size ) ;
sscanf ( b u ff, "‘/.ldV.ld’/.ld'/.ld" ,
ftslots, &record_size, &key_size,
&no_records ) ;
total_bytes = slo ts * record_size + header_size;
// get_address needs \0
stored_key = new chair [ key_size + 1 ] ;
bu ffer = new char [ record_size ] ;
>
>
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
if ( isopen ) {
char b u f f [ header_size ] ;
slo ts = s i;
record_size = actual_record_size + 1;
key_size = ks;
total_bytes = slo ts * record_size + header_size;
no_records = 0;
// get_address needs \0
stored_key = new char [ key_size + 1 ] ;
fo r ( int i = 0; i < header_size; i++ )
b u ff[ i ] = ’ ’ ;
s p r in t f( b u ff, "*/.ld ’/.Id ’/.Id */.ld",
slo ts , record_size,
key_size, no_records ) ;
w rite ( b u ff, header_size ) ;
bu ffer = new char [ record_size ] ;
fo r ( i = 1; i < record_size; i++ )
b u ffe r [ i ] = ’
b u f fe r [ 0 ] = Free;
fo r ( i = 0; i < s lo ts; i++ )
w rite ( b u ffe r, record_size ) ;
>
>
// hash function
long frandom::get_address( const char* key )
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 381
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS H IERARCH Y
loc_address = unocc_address;
return F a il;
>
if ( lo c a te ( record ) ) {
seekg( loc_address + 1, io s ::b e g ) ;
read( record, record_size - 1 ) ;
return Success;
>
else
return F a il;
>
if ( lo c a te ( key ) ) {
— no_records;
seekp( loc_address, io s ::b e g ) ;
w rite ( ftDeleted, 1 ) ;
return Success;
>
else
return F a il;
>
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS
i o s : : out I
i o s : : binary I
i o s : :nocreate ) ;
if ( open_fl ) {
isopen = open_fl;
char b u f f [ header_size ] ;
read( b u ff, header_size ) ;
sscanf( b u ff, "%ld%ld%ldXld",
feslots, &record_size, &key_size,
&no_records ) ;
total_bytes = slo ts * record_size + header_size
// get_address needs \0
stored_key = new char [ key_size + 1 ] ;
bu ffer = new char [ record_size ] ;
}
}
i f ( open_fl ) {
isopen = open_fl;
char b u f f [ header_size ] ;
slo ts = s i;
record_size = actual_record_size + 1;
key_size = ks;
total_bytes = slo ts * record_size + header_size
no_records = 0;
// get_address needs \0
stored_key = new char [ key_size + 1 ] ;
www.MathSchoolinternational.com
384 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
void frandom:: c lo se ()
if ( isopen ) ■[
delete [ ] stored_key;
delete [ ] b u ffer;
char b u f f [ header_size ] ;
fo r ( int i = 0; i < header_size; i++ )
b u ff[ i ] = ’ ’ ;
sp rin tf ( b u f f , "'/.Id ‘/.Id ’/.Id */,ld" ,
slo ts , record_size,
key_size, no_records ) ;
seekp( 0, io s ::b e g ) ;
w rite ( b u ff, header_size ) ;
fstream base::close() ;
>
>
int mainO
■C
char b [ 10 ] , c;
frandom finout;
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 385
return EXIT_FAILURE;
}
}
else {
finout.open( "data.dat" );
if ( !finout ) {
cerr « "Couldn’t open f i l e " « endl;
return EXIT_FAILURE;
}
do {
cout « "\n\n[A]dd\n[F]ind\n[R]emove\n[Q]uit? " « flu sh ;
cin » c;
switch ( toupper( c ) ) {
case ’ A’ :
cout « "Which record to add? " « flush;
cin » b;
i f ( fin o u t.add_record( b ) )
cout « "Record added" « endl;
else
cout « "Record not added" « endl;
break;
case ’ F ’ :
cout « "Key? " « flush;
cin » b;
i f ( fin o u t.fin d _reco rd ( b ) ) {
b [ 5 ] = ’ \0’ ;
cout « "Record found: " « b « endl;
>
else
cout « "Record not found" « endl;
break;
case ’R’ :
cout « "Key? " « flush ;
cin » b;
i f ( finout.remove_record( b ) )
cout « "Record removed" « endl;
else
cout « "Record not removed" « endl;
break;
case ’ Q’ :
break;
www.MathSchoolinternational.com
386 C H APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
Member Purpose
isopen 1, if file is open; 0, if file is closed.
s lo ts Number of slots.
record_size Actual record size + 1 (for flag).
k ey.size Size of key.
tota l_b ytes s lo ts * record_size
no_records Number of records stored.
loc_address Set by method locate. loc_address is where a record was
found or where a record can be stored.
b u ffer Storage for one record.
stored_key Storage for one key plus null terminator.
d e fa u lt:
cout « " I l l e g a l choice" « endl;
break;
>
} while ( toupper( c ) != ’ Q’ ) ;
return EXIT_SUCCESS;
>
We derive our random access file class from the library input/output file
class fstream:
class frandom : public fstream {
>;
We provide constructors and a destructor, with behavior similar to those in
the base class fstream, for associating a random access file with an frandom
object. We also provide methods for associating a random access file with an
already existing frandom object; for adding, finding, and removing records;
and for obtaining information about the file (e.g., the number of slots, the
record size, etc.).
The data members of frandom and their purposes are listed in Figure
7.6.4. The first 256 bytes of the file are reserved as a header for the file. The
values of slots, record_size, key_size, and no_records, in this order,
are stored in the file header.
The default constructor
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 387
>
invokes the base class constructor, initializes certain members to zero, and
sets the isopen flag:
isopen = fstreambase: :rdbuf() -> is _ o p e n ();
The member rdbuf in fstreambase returns a pointer to a buffer object. The
buffer class contains the method is_open that returns 1 if the file is open,
or 0 if the file is not open. The default constructor does not associate a file
with an frandom object. If an frandom object is created with the default
constructor, the method open could be used to open a file and associate it
with the frandom object.
The constructor
frandom::frandom( const char* filename,
in t s i ,
in t actual_record_size,
in t ks ) : fstreamO
>
creates an frandom object and associates the new file filename with it.
After invoking the base class default constructor and initializing b u ffe r
and stored_key, the file is opened using the method open from fstream:
fstream ::open( filename,
io s : : in I
io s : : out |
io s : : binary |
i o s : :noreplace ) ;
The file is opened as a binary file for input and output, thus allowing any
kind of data to be read and written. The flag
io s : : noreplace
causes open to fail if the file exists, unless ate or app is set, which is not the
case here. Thus the file is successfully opened only if it is a new file.
The next statement initializes is_open
isopen = fstream base::rdbuf0 -> is _ o p e n ();
just as in the default constructor.
If the file is opened
if ( isopen ) {
www.MathSchoolinternational.com
388 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
we initialize data members, allocate storage, write the file header, and ini
tialize the file.
We first allocate storage for the header
char b u ff[ header_size ] ;
and initialize slots, record_size, key_size, total_bytes, and no_records.
We then allocate storage for the key:
stored_key = new char [ key_size + 1 ] ;
Next we place the text for the header in buff and then write the header to
the file:
fo r ( in t i = 0; i < header_size; i++ )
b u ff[ i ] = * ’ ;
s p rin tf ( b u ff, "*/.ld ‘/.Id ‘/.Id */.ld",
s lo ts , record_size,
key_size, no_records ) ;
w r it e ( b u ff, header_size ) ;
We then create storage for a record and write s lo ts Free records to the
file:
b u ffe r = new char [ record_size ] ;
fo r ( i = 1; i < record_size; i++ )
b u ffe r [ i ] = ’ ’ ;
b u ffe r [ 0 ] = Free;
fo r ( i = 0; i < s lo ts ; i++ )
w r ite ( b u ffer, record_size ) ;
We use the methods read and w rite throughout since their purpose is to
read and write binary data.
The constructor
frandom::frandom( const char* filename ) : fstreamO
>
creates an frandom object and associates an existing file filename with it.
After invoking the base class default constructor and initializing b u ffer
and stored_key, the file is opened using the method open from fstream:
fstream ::open( filename,
i o s : : in I
i o s : : out I
i o s : :binary |
ios::nocreate ) ;
The file is opened as a binary file for input and output. The flag
io s : :nocreate
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 389
causes open to fail if the file does not exist. Thus the file is successfully
opened only if it is an existing file.
The next statement initializes is_open as in the other two constructors.
If the file is opened, we create storage for the header, read the header,
initialize slots, record_size, key_size, total_b ytes, and no_records:
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
www.MathSchoolinternational.com
SAM PLE A PPLIC A TIO N : A R A N D O M ACCESS FILE CLASS 391
loc_address = address;
return Success;
>
break;
If the key matches, loc_address is set to the address of the record and
Success is returned to signal a successful search. If locate was called by
f ind_record, f ind_record will store the record at address loc_address. If
locate was called by delete_record, delete_record will change the flag
to D at address loc_address.
If the record was not found and an F slot did not terminate the search,
address is updated to the next slot and the search continues:
address += record_size;
i f ( address >= tota l_b ytes )
address = header_size;
if ( lo c a te ( record ) ) {
seekg( loc_address + 1, io s ::b e g ) ;
read( record, record_size - 1 ) ;
return Success;
>
else
return F a il;
www.MathSchoolinternational.com
392 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS H IERARCH Y
www.MathSchoolinternational.com
7.7 THE CHARACTER A R R A Y IN P U T / O U T P U T CLASSES 393
strstreambase
ostrstream
istrstream
strstream
strstream base
>;
It serves as a base class for the character array input/output classes o s tr
stream, istrstream, and strstream, which are the classes used by a pro
grammer to manipulate character arrays. Each of ostrstream, istrstream,
and strstream is also derived from the corresponding stream class (ostream,
istream, or iostream) and, so, has methods for moving around in charac
ter arrays and for reading and writing character arrays. The derived classes
provide constructors for associating user-defined character arrays or system-
defined (dynamic) character arrays with objects in these derived classes.
The only public member in strstreambase is rdbuf. Its declaration is
strstreambuf* rdbuf( ) ;
The method returns a pointer to the strstreambuf buffer object associated
with the strstreambase object.
Class strstreambase has a protected constructor that contains code
for associating a user-specified character array buffer with an strstream
object. A second protected (default) constructor permits the system to
dynamically allocate the character array buffer. Class strstreambase also
contains a protected destructor that, among other things, deallocates any
dynamically allocated storage. These protected constructors and destruc
tor are typically invoked by public constructors, destructors, and methods
in derived classes.
ostrstream
www.MathSchoolinternational.com
394 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
www.MathSchoolinternational.com
7.7 THE CHARACTER A R R A Y IN P U T / O U T P U T CLASSES 395
because, if we change the size of the array name, the definition is automati
cally updated to the new size. □
is trs tre a m
The class istrstream is used to read formatted input into character arrays.
It performs somewhat the same functionality as the C function sscanf.
The entire declaration of the class istrstream is
class istrstream : public strstreambase, public istream {
p u b lic :
istrstream ( char* buff ) ;
www.MathSchoolinternational.com
CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
It inherits public methods from istream to read and move within character
arrays. Notice that no default constructor is supplied; the user must specify
the character array to read.
The constructor whose declaration is
istrstream ( char* buff ) ;
is used to associate an istrstream object with the user-specified character
array buff. In this case, a null terminator marks the end of the data, and
this null terminator itself is never read. Here, buff is an ordinary null-
terminated C string.
The constructor
istrstream ( char* b u ff, in t len ) ;
is used to associate an istrstream object with the user-specified, len-byte,
character array buff. In this case, the byte at index len — 1 marks the end
of the data.
www.MathSchoolinternational.com
7.7 THE CHARACTER A R R A Y IN P U T / O U T P U T CLASSES 397
char c , s [ 5 ] ;
in t i ;
fo r ( i = 0, c = ’ a ’ ; i < 5;i++, C + + )
s [ i ] = c;
istrstream s in ( s, s iz e o f ( s ) ) ;
while ( sin » c )
cout « "Input succeeded, c = " « c « endl;
cout « "at end of array" « endl;
is
Input succeeded, c= a
Input succeeded, c= b
Input succeeded, c= c
Input succeeded, c= d
Input succeeded, c= e
at end of array
□
strstream
The class strstream is used to read and write formatted input and output
in character arrays.
The entire declaration of the class strstream is
class strstream : public strstreambase, public iostream {
p u b lic:
strstreamO ;
strstream ( char* b u ff, in t len, in t mode ) ;
“ strstreamO ;
char* s t r ( ) ;
>;
It inherits public methods from iostream to read, write, and move within
character arrays.
The default constructor is used when an strstream object is created but
a character array is not attached to the object. As for class ostrstream,
the system uses its own dynamically created character array buffer.
The constructor whose declaration is
strstream( chax* b u ff, in t len , in t mode ) ;
is used to associate an strstream object with the user-specified character
array buff of length len. The character array is opened in mode mode. If
mode is ios: :app (append) or io s : :ate (at end), a null terminator ’ \0’
must occur in the array and the stream position marker is placed at this null
terminator.
www.MathSchoolinternational.com
398 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
The method s tr behaves exactly like the method with the same name
in ostrstream.
Exercises
Use an appropriate object from this section to place the characters be
tween the first pair of double quotes in the character array f i r s t and
the characters between the second pair of double quotes in the character
array second.
S o lu tio n _______________________________________________________________________
www.MathSchoolinternational.com
7.8 SAM PLE A PPLIC A TIO N : A HIGH-LEVEL C O P Y F U N C TIO N 399
not skip white space,” because we want to copy all of the characters— white
space or not. Before returning from the function, we restore the format flags.
After presenting the C + + implementation, we give several examples using
classes discussed in this chapter.
char c;
lo n g f l ;
w h ile ( in » c )
out « c;
// r e s t o r e f l a g s
in .fla g s ( f l );
>
We present several main programs to show how copy can be used to copy
one object to another when the objects are in classes derived from is tre a m
and ostream.
The following code copies the standard input to the standard output:
# in clu d e < iostream .h >
# in clu d e < s t d lib .h >
in t mainO
{
c o p y( c in , cout ) ;
re tu rn EXIT_SUCCESS;
}
The next code copies from the file data.in to the file data.out:
www.MathSchoolinternational.com
400 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
#include <fstream.h>
#include <stdlib.h>
int mainO
{
ifstream f i n ( "data.in " ) ;
ofstream fo u t( "data.out" ) ;
return EXIT_SUCCESS;
>
The next code copies a character array to a character array and then
writes to the standard output to confirm the copy:
#include <strstream.h>
#include <stdlib.h>
in t mainO
{
char b u ff[ 30 ] ;
istrstream s in ( "Junior G-Men of the A ir" ) ;
ostrstream sout( b u ff, s ize o f ( buff ) ) ;
return EXIT_SUCCESS;
}
Notice that it is necessary to append a null terminator because the null
terminator is not copied by the copy function.
Our last example copies an array to the file data. out-.
#include <fstream.h>
#include <strstream.h>
#include <stdlib.h>
www.MathSchoolinternational.com
7.9 THE BUFFER CLASSES 401
int m a i n O
{
istrstream s in ( "Junior G-Men of the A ir" ) ;
ofstream fo u t( "data.out" ) ;
return EXIT_SUCCESS;
>
Exercises
5. Write a high-level copy function that replaces each tab character by the
appropriate number of spaces. The copy function should have a third
parameter that describes the tab setting (e.g., if this parameter is 3, the
tabs are set at columns 4, 7,10,..., where column 1 is the first column).
www.MathSchoolinternational.com
402 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
classes. For this reason, many programmers never directly use these buffer
classes.
Each object in a buffer class uses a character array as a buffer. We refer
to this array as a character buffer and the classes or objects themselves as
buffer classes or buffer objects.
streambuf
Class streambuf is the base buffer class. The default constructor creates
a streambuf object without assigning a character buffer. The constructor
whose declaration is
streambuf( char* b u ff, in t len ) ;
creates a streambuf object, which uses the len-byte array bu ff as a char
acter buffer.
The methods
streambuf* setbuf( signed char* b u ff, in t len ) ;
streambuf* setbu f( unsigned char* b u ff, in t len ) ;
associate a streambuf object, created with the default constructor, with the
len-byte array buff, which serves as the character buffer.
The method
in t in _ a v a il();
returns the number of characters remaining in the input character buffer and
the method
in t o u t_ a v a il();
returns the number of characters remaining in the output character buffer.
The method
in t sbumpcO;
returns the current character in the input character buffer and advances the
buffer position marker, which designates the character to read or write, one
byte. If sbumpc fails (e.g., we are at the end of the file), it returns EOF. This
low-level method resembles the high-level method get in class istream.
The method
in t sg etcO ;
returns the next character in the character buffer. The buffer position marker
is unchanged. If sgetc fails, it returns EOF. This low-level method resembles
the high-level method peek in class istream.
The method
in t sgetn( char* store, in t n ) ;
returns the next n characters from the character buffer and stores them in
store. It returns the number of characters actually retrieved. The buffer
www.MathSchoolinternational.com
THE BUFFER CLASSES 403
www.MathSchoolinternational.com
404 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
moved. The low-level methods seekof f and seekpos resemble the high-level
methods seekg and seekp in classes istream and ostream.
We defer examples to the next subsections, which consider the derived
classes file b u f and strstreambuf, as it is these classes that provide the
facilities for associating buffer objects with files and character arrays.
file b u f
>;
It provides buffered access to files.
The default constructor creates a file b u f object that is not associated
with any file.
The method open
file b u f* open( const char* filename,
in t mode,
in t pr = f i l e b u f : : openprot ) ;
opens the file filename in mode mode and associates it with the file b u f
object. The file receives default protection openprot if a protection is not
specified.
www.MathSchoolinternational.com
THE BUFFER CLASSES 405
in t mainO
{
char in b u ff[ b u ffs ize ] , ou tb u ff[ b u ffs iz e ] ;
file b u f f in , fou t;
in t c;
c = f in .s g e tc O ;
while ( c != EOF ) {
fou t.sp u tc( c ) ;
c = fin .s n e x tc O ;
}
return EXIT_SUCCESS;
>
After setting up the character buffers inbuff and outbuff and opening
the files, we read a character from the input character buffer inbuff, but
the input buffer position marker does not move:
www.MathSchoolinternational.com
CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
c = fin .s g e tc O ;
If we are not at the end of the file, we enter the body of the while loop. We
write one character to the output character buffer out b u ff and move one
byte in the input character buffer and return that character:
fou t.sp u tc( c ) ;
c = f in. snextcO ;
We continue until all of the characters have been read from the input file. □
The method
file b u f* c lo s e O ;
closes the file associated with the file b u f object and flushes the character
buffer. The destructor also closes the file and flushes the character buffer.
Exam ple 7.9.4. When the program of Example 7.9.3 terminates, the de
structor is automatically called for fin and fout. The destructor closes the
files. The destructor for fout flushes the output character buffer; that is,
data still in the output character buffer but not yet written to the file is now
written to the file. □
The methods overflow and underflow take action when the character
buffer is full or empty. The method
in t overflow ( in t stop = EOF ) ;
flushes the character buffer. More precisely, it writes all the data in the
character buffer, up to but not including stop, to the destination file.
The method
in t underflowO;
reads data from the source file into the character buffer.
Exam ple 7.9.5. In this example, we look more closely at what happens
when the code of Example 7.9.3 executes. For the purposes of illustration,
we assume that b u ffsize is 8, rather than 256.
When we first execute
c = fin .s g e tc O ;
the input character buffer is empty, so method underflow is invoked and
the input character buffer is filled (see Figure 7.9.1).
Next we execute
fou t.sp u tc( c ) ;
and c is written to the output character buffer (see Figure 7.9.2). We then
execute
c = fin .sn ex tcO ;
www.MathSchoolinternational.com
7.9 THE B UFFER CLASSES 407
sg e t c
Buffer
position ------------
marker
outbuff
I
sputc
e I
Buffer
position
marker
I - a m L-J n O t
^^snextc
www.MathSchoolinternational.com
408 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
Buffer
position ■
marker
int>uff
I a m i_j n 0 t
snextc
sputc
o u t b u ff
I a m n 0 t
Buffer
position
marker
snextc
I
Figure 7.9.5 Refilling the input buffer the first time.
and the next character in the input character buffer is read (see Figure 7.9.3).
Figure 7.9.4 shows the situation somewhat later—just after we execute
fo u t.sp u tc( c ) ;
for the eighth time. At this point, both the input and output character
buffers are full. When we next execute
c = fin .sn e xtcO ;
no characters are available in the input character buffer, so method under
flow is invoked and the input character buffer is refilled (see Figure 7.9.5).
Next we execute
fo u t.sp u tc( c ) ;
Since the output character buffer is full, the method overflow is invoked
and the output character buffer is flushed (see Figure 7.9.6).
Figure 7.9.7 shows the situation when the statement
c = fin .sn e xtcO ;
is executed and the last character ! is read; underflow again occurs. Next
fo u t.sp u tc( c ) ;
www.MathSchoolinternational.com
7.9 THE BUFFER CLASSES 409
Buffer
position
marker
o u tb u ff
1 a m n 0 t
-
overflow
i
d a ta .o u t : I am not
Buffer
position '
marker
i
o u tb u ff
L-J a m n 0 t
spu tc
Buffer ) underflow
position
marker
in b u ff
! a c r 0 0 k
s n e x tc
A!
is executed; overflow occurs and the output character buffer is flushed (see
Figure 7.9.8).
When we next execute
c = fin .s n e x tc O ;
since we are at the end of the file, snextc returns EOF and the w h ile loop
terminates. When the program terminates and the destructor for fo u t is
called, the output character buffer is flushed and the last character ( ! ) is
written to the file data.out (see Figure 7.9.9).
If the program terminated without the destructor for fout being called,
the output character buffer would not be flushed the last time and data.out
would contain
I am not a crook
For example, the destructor would not be called if the program terminated
with a call to exit:
www.MathSchoolinternational.com
410 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
Buffer
position ■
marker
o u t b u ff
a c r 0 0 k
H "
data.out: I am n ot a crook!
Buffer
position
marker
o u t b u ff
i
] a c r 0 O k
sputo
1
Buffer
position
marker
outbuff
1 a c r 0 O k
Figure 7.9.9 The result of the destructor flushing the output buffer.
www.MathSchoolinternational.com
7.9 THE BUFFER CLASSES 411
in t mainO
{
while ( c != EOF ) {
fout.sputc( c );
c = fin.snextc();
}
e x it ( EXIT.SUCCESS ) ;
>
□
The method
in t is _ o p e n ();
returns nonzero if the file is open and zero if the file is not open.
The method seekoff behaves exactly like the method with the same
name in streambuf.
strstream buf
>;
It provides access to character buffers.
The default constructor creates an strstreambuf object that uses dy
namic storage allocation; that is, the character buffer is allocated as needed.
Similarly, the constructor
strstreambuf( in t n ) ;
creates an strstreambuf object that uses dynamic storage allocation begin
ning with a character buffer of n bytes. (If necessary, the buffer is expanded.)
Dynamic buffers are useful for output.
Each of the constructors
strstreambuf( signed char* b,
in t le n ,
signed chair* s = 0 ) ;
strstreambuf( unsigned char* b,
in t len,
unsigned chair* s = 0 ) ;
creates an strstreambuf object that uses the static len-byte character
buffer b. Static buffers are useful for input.
www.MathSchoolinternational.com
412 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
The program prints the contents of the destination array outbuff to confirm
that the input array inbuff was copied.
#include <strstream.h>
#include <string.h>
#include <stdlib.h>
in t main()
{
char in b u ff[ ] = "Magical Mystery Tour",
ou tb u ff[ 25 ] ;
c = sin .sgetcO ;
while ( c != EOF ) {
sout.sputc( c ) ;
c = sin. snextcO ;
}
return EXIT_SUCCESS;
>
□
The method
void fr e e z e ( in t fla g = 1 ) ;
with a nonzero argument, freezes the output— no more characters can be
written to the character buffer. With argument zero, the output is unfrozen.
The methods seekof f and s tr behave exactly like the methods with the
same names in streambuf.
The methods overflow and underflow take action appropriate to the
type of character buffers defined— dynamic or static.
www.MathSchoolinternational.com
COMMON PRO G R A M M IN G ERRORS 413
Exercises
1. Write statements that open the file balance.dat for input and output,
associate it with the file b u f object finout, and use a 256-byte user-
supplied character buffer.
2. Using class file b u f, write a complete program that copies files in the or
der listed on the command line (the first file— the executable— is skipped)
to the standard output. Files that cannot be opened for reading are ig
nored.
3. Rewrite Example 7.9.3. Change b u ffs ize to 8 and print the contents of
inbuff and outbuff at various points so that the process of reading and
writing the character buffers is clarified.
5. The C + + class library has separate classes istream and ostream for
high-level input and output. Why do you think that the C + + designers
declared a single buffer class streambuf for both input and output?
ios
streambuf
istream
ostream
iostream
istream_withassign
ostream_withassign
iostream_withassign
www.MathSchoolinternational.com
414 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
file b u f
fstreambase
ifstream
ofstream
fstream
strstreambuf
strstreambase
istrstream
ostrstream
strstream
7. The flag e o fb it in class ios is set by attempting to read beyond the end
of the file. Simply reading the last byte does not set e o fb it. For this
reason, the following code that attempts to echo integers in the standard
input to the standard output is incorrect; an extra line is printed:
in t i ;
A correct version is
in t i ;
do {
cin » i;
www.MathSchoolinternational.com
COM M ON PR O G R A M M IN G ERRORS 415
if
( Ic in .e o fO )
cout « i « endl;
} while ( Ic in .e o fO ) ;
8. The method fla g s with one argument in class ios sets the format flags
to the value passed, whereas method s e tf, also in class ios, sets specified
flags without changing the other flags. For example,
c o u t.fla g s ( i o s : : showpoint ) ;
cout. s e t f ( i o s : : showpoint ) ;
is
c8
c8
10. When the versions of methods seekg and seekp whose declarations are
are used with files, the files should be opened as binary files. These
methods may not work properly if they are used with files which were
not opened in binary mode.
When the versions of methods seekg and seekp whose declarations are
www.MathSchoolinternational.com
416 CHAPTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCHY
are used with files, the files can be opened as binary or non-binary files.
The argument should be a value returned by t e l l g (for seekg) or t e llp
(for seekp).
11. When the overloaded operator » is used to read a character, the default
action is to skip white space. Do not assume (as in C) that the next
character, white space or not, is read.
12. When the overloaded operator » is used to read a string and the field
width is set to n ^ 0, do not assume that the next n characters, white
space or not, are read and stored. The default action is to skip white
space and then read and store all non-white space characters up to the
next white space character, or n — 1 characters, whichever occurs first. A
null terminator is always added. As examples, if the standard input is
uuuPepper
the code
chair a [ 10 ] ;
cin » setw( 6 ) » a;
Peppe
uuuDruPepper
the code
chax a [ 10 ] ;
cin » setw( 6 ) » a;
Dr
13. When overloading » for input, the first argument should be of type
istreamfe and the second argument should be the user-defined type. The
return type should be istreamfe. The type istreamfe is necessary to
correctly update the istream object passed.
14. When overloading « for output, the first argument should be of type
ostreamfe and the second argument should be the user-defined type. The
return type should be ostreamfe. The type ostreamfe is necessary to
correctly update the ostream object passed.
www.MathSchoolinternational.com
COM M ON PR O G R A M M IN G ERRORS 417
15. The code for a manipulator must return the modified stream. For this
reason,
void b e l l ( ostreamfe os )
{
// * * * * * ERROR: Must return the stream
os « "\a";
>
ostreamfe b e l l ( ostreamfe os )
return os « "\a";
>
16. It is an error to omit the mode when opening a file and associating it
with an fstream object
fstream f i o ;
// * * * * * ERROR: No mode
fio .o p e n ( "p a y ro ll.d a t" ) ;
since no default mode is supplied. The mode can be omitted for ifstream
and ofstream objects; the default mode for an ifstream object is input,
and the default mode for an ofstream object is output.
ostrstream s;
s « "Wow";
char* p = s . s t r ( ) ;
I I * * * * * ERROR: No null terminator
cout « p;
s « "Wow";
by
www.MathSchoolinternational.com
418 CH APTER 7 THE C + + IN P U T / O U T P U T CLASS HIERARCH Y
s « "Wow" « ends;
19. The method sgetc in class streambuf returns the next character in the
character buffer but does not change the buffer position marker. For this
reason,
20. When supplying a buffer for file input/output, set the buffer before open
ing the file:
If the last two lines are reversed, the programmer’s buffer b is ignored:
21. The output file character buffer is not flushed if the file is not closed.
The file may be closed by using the method close or passively by the
destructor.
Programming Exercises
7.1. Modify the random access file class of Section 7.6 in the following manner.
Add another field to the header, which flags the file as a random access
www.MathSchoolinternational.com
PRO G RAM M ING EXERCISES 419
file, by writing RA in the first two bytes of the header. When an existing
file is opened, this flag is checked. If the file is the wrong type, it is closed
and an error condition is set.
7.2. Provide implementations of fla g s, se tf, and unsetf (see Section 7.2).
7.4. Derive a sequential file class from fstream (see Section 7.6).
7.5. Derive an indexed file class from fstream (see Section 7.6). The un
derlying data structure should be a B-tree [see, e.g., L. Nyhoff and S.
Leestma, Data Structures and Program Design in Pascal, 2nd ed., (New
York: Macmillan, 1992)]. The indexed file class should allow the following
operations:
7.6. Develop a class that serves as an interface to the frandom class of Section
7.6. The class should contain a pointer to another class that describes a
record. The record must contain a member of type char*, which serves
as the key.
7.8. Write a high-level (in the sense of Section 7.8) encryption function based
on Huffman codes [see, e.g., L. Nyhoff and S. Leestma, Data Structures
and Program Design in Pascal, 2nd ed., (New York: Macmillan, 1992)].
7.9. Rewrite the frandom class (see Section 7.6) using buffer classes directly.
7.10. Derive a class scrn_out from ostream that provides output in specified
colors to specified parts of the screen.
www.MathSchoolinternational.com
www.MathSchoolinternational.com
Chapter 8
Advanced Topics
421
www.MathSchoolinternational.com
422 CHAPTER 8 ADVANCED TOPICS
>;
s t r i n g : : s tr in g ( int size )
{
// define "out of bounds" exception and throw i t
i f C size < minSize || size > maxSize )
throw( size ) ;
s = new chart size ] ;
// define "out of memory" exception and throw it
i f ( s == 0 )
throw( "Out of Memory" ) ;
>
www.MathSchoolinternational.com
E X C E PTIO N HANDLING 423
void f ( in t n )
{
try {
strin g s t r ( n ) ;
>
catch( in t k )
{
cerr « "Out of range error: " « k « endl;
f ( string::m axSize ) ;
>
s t r in g :: s tr in g ( in t )
throw( size ) ;
www.MathSchoolinternational.com
424 CHAPTER 8 ADVANCED TOPICS
throw( size ) ;
in the constructor. The exception is caught by the catch block whose argu
ment type matches that of the thrower. Since size, the throw argument, is
of type int, the exception is caught by the catch block
catch( in t k )
www.MathSchoolinternational.com
E X C E PTIO N HANDLING 425
whose argument is of type char*. An error message is printed and then the
library function abort, which terminates the program, is invoked. □
tr y {
}
catch( in t i )
if ( ... )
else
throw;
}
}
void g ()
tr y {
f();
>
catch( in t k )
>
>
g calls f , which is in a try block. When f executes, if an in t exception is
raised in f ’s tr y block, f ’s handler
catch( in t i )
if ( ... )
e ls e
throw;
>
is invoked. If the condition in the i f statement is false, the exception is
rethrown. Since f now terminates and returns to g, the rethrown exception
www.MathSchoolinternational.com
426 CH APTER 8 ADVANCED TOPICS
>
□
www.MathSchoolinternational.com
8.2 R U N -TIM E T Y P E ID E N TIFIC A TIO N 427
Exercises
catch( in t k )
are removed from the function f and f is invoked with argument 2000?
>
www.MathSchoolinternational.com
428 CH APTER 8 ADVANCED TO PIC S
T h e dynamic_cast O perator
www.MathSchoolinternational.com
R U N -TIM E T Y P E ID E N TIFIC A TIO N 429
Exam ple 8.2.2. A dynamic cast expression can also be used as a condition.
For example, the function print_book_inf o can be rewritten as:
void print_book_info( Book* book_ptr )
if ( Textbook* ptr
= dynamic_cast< Textbook* >( book_ptr ) ) {
p tr -> p r i n t _ t i t l e ( ) ;
p tr -> p r i n t _ le v e l();
}
els e
book_ptr -> p r i n t _ t i t l e ( ) ;
>
□
Exam ple 8.2.3. We revise the code of Example 8.2.1 to use polymorphism
to achieve the same effect:
class Book {
p u b lic :
v irtu a l void p r i n t _ t i t l e ( ) ;
v irtu a l void p r in t _ le v e l();
>;
www.MathSchoolinternational.com
430 CHAPTER 8 ADVANCED TO PICS
void p r i n t _ t i t l e ( ) ;
void p r i n t _ l e v e l ( ) ;
>;
The code of Example 8.2.3 is cleaner than that of Example 8.2.1 and is
preferable. In Example 8.2.3, the use of v ir tu a l functions automatically
takes care of the details of determining which versions of p r in t _ t it le and
p r in t_ le v e l to use. If, however, the programmer cannot modify the classes,
the technique of Example 8.2.1 may be the only safe way to obtain the desired
result.
T h e typeid O perator
The typeid operator returns a reference to an object in the library class
Type_info that describes the run-time type of an object. When using the
typeid operator, the header file TypeJnfo.h must be included.
The typeid operator is invoked as
type id ( typename )
or
type id ( expression )
If the operand of the typeid operator is the type typename, typ eid returns
a reference to a Type_inf o object that represents typename. If the operand
of the typeid operator is the expression expression, typeid returns a ref
erence to a Type_info object that represents the expression’s type. The
programmer need not know the details of the return type to use the typeid
operator to compare types, as the following examples illustrate.
Exam ple 8.2.4. The typeid operator can be used with built-in types and
operators. Figure 8.2.1, which assumes the definitions
flo a t x;
long va l;
www.MathSchoolinternational.com
8.2 R U N -TIM E T Y P E ID E N TIFIC A TIO N 431
Expression Value
ty p eid ( x ) == ty p e id ( flo a t ) True
ty p eid ( x ) == ty p e id ( double ) False
typ eid ( x ) == typ eid ( flo a t * ) False
ty p eid ( v a l ) == ty p e id ( long ) True
typ eid ( v a l ) == ty p eid ( short ) False
typ eid ( 5280 ) == typ eid ( in t ) True
ty p e id ( 9.218836E-9L ) == typ eid ( long double ) True
Figure 8.2.1 Using the typeid operator to test run-time built-in types.
Expression Value
ty p e id ( book_ptr ) == ty p e id ( Book* ) True
typ eid ( book_ptr ) == typ eid ( Book ) False
ty p eid ( *book_ptr ) == ty p e id ( Book ) False
typ eid ( book_ptr ) == typ eid ( Textbook* ) False
ty p eid ( book_ptr ) == ty p e id ( Textbook ) False
ty p eid ( *book_ptr ) == ty p e id ( Textbook ) True
Figure 8.2.2 Using the typeid operator to test run-time class types.
shows the values of several expressions that use the typeid operator. □
Exam ple 8.2.5. Figure 8.2.2, which assumes the declarations of Example
8.2.1 and the definition
shows the values of several expressions that use the typeid operator.
The value of the expression
ty p e id ( book_ptr )
represents the type (Book*) declared for book_ptr, not the type of object
(Textbook) to which book_ptr points. For this reason, the first expression
is true, but the second, fourth, and fifth expressions are false.
The value of the expression
ty p e id ( *book_ptr )
represents the type of object (Textbook) to which book_ptr points. For this
reason, the third expression is false, but the last expression is true. □
www.MathSchoolinternational.com
432 CHAPTER 8 ADVANCED TO PICS
Exercises
Give the value of each expression in Exercises 4-27. Assume the declara
tions of Example 8.2.1 and the statements
double* dptr;
short i ;
char student[ 100 ] [ 80 ] ;
Book* bptr == new Book;
www.MathSchoolinternational.com
8.3 NAMESPACES 433
8.3 Namespaces
C + + uses namespaces to distinguish among identical global names. With
out namespaces, a programmer could not directly use two libraries each of
which contains identical global names.
Exam ple 8.3.1. Suppose that two libraries each contain a toplevel func
tion named clr_screen. To use namespaces to resolve the ambiguity, the
libraries, say l i b l and lib2, put the global declarations in namespaces: the
library l i b l contains the code
namespace l i b l {
void c lr _ s c r e e n ();
>
and the library lib 2 contains the code
namespace lib 2 {
void c lr _ s c r e e n ();
>
www.MathSchoolinternational.com
434 CHAPTER 8 ADVANCED TO PICS
The line
using l i b l : : clr_screen;
is equivalent to declaring a variable named clr_screen. Any reference there
after to clr_screen within the scope of the declaration is to clr_screen in
l i b l ’s namespace. If the declaration is in a block, the identifier clr_screen
is known only within the block; otherwise, the identifier is known to the end
of the file.
void printnameO
>
contains an error since printname contains two declarations of fname. □
www.MathSchoolinternational.com
8.4 OTHER OBJECT-ORIENTED LANGUAGES 435
Exercises
1. Given
namespace kalin_software {
class strin g {
char item [ 100 ] ;
in t len;
p u b lic :
void s to re ( char* ) ;
char* g e t ( ) ;
>;
>
and
namespace jbaugh_software {
class strin g {
char item [ 100 ] ;
p u b lic :
void s to re ( char* ) ;
char* g e t ( ) ;
>;
>
write code that creates an object k of type strin g from kalin_softw are
and an object j of type strin g from jbaugh_software.
www.MathSchoolinternational.com
436 CHAPTER 8 ADVANCED TO PICS
Sm alltalk
www.MathSchoolinternational.com
8.4 OTHER OBJECT-ORIENTED LANGUAGES 437
Object
t
Dictionary O rderedCollection FixedCollection
t / \
SortedCollection A rray String
if b is an object.
The syntax for keyword messages with more than one argument is quite
different from C + + . For example, the message between: and: takes two
arguments as indicated by the two colons. If the object has a value between
the two arguments, between: and: returns True; otherwise, it returns False.
For example, the statement
x := y between: a and: b.
sets x to True, if y is between a and b, and to False otherwise.Equivalent
C + + statements are
x = between( y, a, b ) ;
or
x = y.between( a, b ) ;
if y is an object.
Smalltalk has one base class Object from which all other classes are
directly or indirectly derived. A partial tree of a typical class library is
shown in Figure 8.4.1. Notice that characters, integers, and so on are indeed
classes, as are strings, sets, and arrays.
Since an array is an object, a method called a t : must be used to access
data in the array. The counterpart of the C + + statement
x = a[ i ] ;
in Smalltalk is
x := a a t : i .
The assignment operator simply copies a pointer. For example, the state
ments
s t r l := ’ Cool, Beavis’ .
str2 := s t r l.
point s t r l and str2 to the same string object (see Figure 8.4.2). The
operator = tests whether two variables (pointers) reference equal objects.
www.MathSchoolinternational.com
438 CH APTER 8 ADVANCED TO PICS
The operator == tests whether two variables (pointers) contain the same
address. Thus after the two previous statements execute, the conditions
s t r l = str2
s t r l == str2
are both true. For the situation in Figure 8.4.3, the condition
s t r l = str2
is true, but the condition
s t r l == str2
is false.
Since Smalltalk is typeless, the version of a method to be invoked is
determined by the kind of object that is being referenced. In other words,
all binding is done at run-time and polymorphism is automatic. For example,
the method a t : can be applied to an array object to obtain the item at a
specified index or to a string object to obtain the character at a specified
index.
Smalltalk has instance methods and class methods. An instance method,
which is like an ordinary method in C + + , applies to an object. In the
preceding examples, all methods are instance methods. A class method, on
the other hand, applies to a class. An example of a class method is the
method new, which is the counterpart of the C + + operator new. Method
new is defined in class Object (see Figure 8.4.1) and thus is inherited by
any class indirectly derived from Object. For example, if Complex is a class
indirectly derived from Object,
c := new Complex.
passes the message new to the class Complex. The effect is to create a
Complex object and return its address, which is then copied into c. No
d elete method is furnished since it is unnecessary; Smalltalk provides au
tomatic garbage collection.
In Smalltalk, every class except Object is a subclass of some existing
class. When a new hierarchy is constructed, it is customary to make the top
class a subclass of the library class Object. The class declaration
www.MathSchoolinternational.com
8.4 OTHER OBJECT-ORIENTED LANGUAGES 439
www.MathSchoolinternational.com
440 CHAPTER 8 ADVANCED TO PIC S
real = 0.0
imag = 0.0
i , j : INTEGER
Storage is reserved for two integers and i and j refer to this storage. The
instruction
i := 3
copies the value 3 to the storage named i. The instruction
j := 1
then copies i ’s value to j (see Figure 8.4.4).
Variables x and y of type COMPLEX, where COMPLEX is a class, are declared
as
x, y: COMPLEX
Storage is reserved for two pointers, but no COMPLEX objects are created. To
obtain a COMPLEX object and point x to it, we would write
x.Create
A Create method is provided by Eiffel although it can be overridden. The
instruction
y := x
then copies the address of the object so that both x and y point to the object
(see Figure 8.4.5).
The Clone method
y.C lone(x)
creates a copy of the object referenced by x and stores the address of the
object in y (see Figure 8.4.6).
The equality test (=) compares the values of simple types and the ad
dresses of objects for class types. For the situations in Figures 8.4.4 and
8.4.5, the expression
x = y
is true, but for the situations in Figures 8.4.6 and 8.4.7, the expression
www.MathSchoolinternational.com
8.4 OTHER OBJECT-ORIENTED LANGUAGES 441
re al = 0.0
im ag = 0.0
re al = 0.0
im ag = 0.0
re al = 0.3
imag = 0.0
re al = 0.0
imag = 0.0
x = y
is false.
The Equal method tests whether the data members of objects are equal.
For the situations in Figures 8.4.5 and 8.4.6, the expression
x.Equal(y)
is true, but for the situation in Figure 8.4.7, the expression
x.Equal(y)
is false.
As in C + + , the dot notation is used to pass a message to an object. After
declaring z to be type COMPLEX and associating z with a COMPLEX object, we
could invoke the method in it with arguments -4 and 26.9 for the object z
by writing
z . i n i t ( -4, 26.9 )
Class COMPLEX could be written as
class COMPLEX export
in it
feature
r e a l, imag: REAL;
i n i t ( re: REAL, im REAL ) is
— i n i t i a l i z e the re a l and imaginary parts
do
re a l := re;
imag := im
end — in it
end — class COMPLEX
www.MathSchoolinternational.com
442 CHAPTER 8 ADVANCED TO PICS
Two dashes introduce a comment, which extends to the end of the line. Semi
colons serve as statement separators. The data members and methods listed
in the export section are available outside the class (export is like public in
C + + ). Data members and methods not listed in the export section are not
available outside the class hierarchy; they are like protected members in
C ++. All data members and methods are specified in the feature section.
Methods are distinguished from data members by the is-do-end syntax.
Eiffel includes preconditions, postconditions, and class invariants as part
of the language. A precondition is signaled by the keyword require and a
postcondition is signaled by the keyword ensure:
class C export
feature
f ( . . . ) is
require
— preconditions fo r f
do
ensure
— postconditions fo r f
end;
end
A class invariant is signaled by the keyword invariant:
class C export
feature
invariant
— class invariants
end
At compile time, the programmer can elect to check no assertions, to check
preconditions only, or to check all assertions. If an assertion to be checked is
false at run-time, the program is terminated and an error message is printed.
Eiffel also has automatic garbage collection, generic classes, exception
handling (much like that in C + + ), and multiple inheritance. Polymorphism
is the default in Eiffel, so there is no need for a “virtual” flag as in C + + .
O bjective C
www.MathSchoolinternational.com
OTHER OBJECT-ORIENTED LANGUAGES 443
www.MathSchoolinternational.com
444 CHAPTER 8 ADVANCED TO PICS
@implementation Complex
- ( void ) i n i t i a l i z e : ( double ) re i : ( double ) im
{
re a l = re;
imag = im;
>
Send
As shown, code to implement the methods is delimited by ^implementation
and Send and is said to belong to the implementation part of the code.
The new method is used to dynamically create an object
Complex z;
z = [ Complex new ] ;
and the fre e method is used to free a dynamically allocated object
[ Complex fre e ] ;
There is no automatic garbage collection in Objective C.
Other Languages
Other languages that include support for object-oriented programming are
• Object Pascal, QuickPascal, Turbo Pascal, Actor
— Each extends Pascal to include object-oriented features. Quick
Pascal is an implementation of Object Pascal. L. Telser, “Ob
ject Pascal Report,” (Santa Clara, Calif.: Apple Computer, 1985),
describes Object Pascal, and N. Shammas, Object-Oriented Pro
gramming with QuickPascal, (New York: Wiley, 1990), describes
QuickPascal. Turbo Pascal is described in the programming guide
that accompanies the product from Borland International, Scotts
Valley, Calif. Actor is described in the Actor Language Manual,
(Evanston, 111.: The Whitewater Group, 1987).
• Simula
— An object-oriented extension of Algol 60 [see B. Kirkerud, Object-
Oriented Programming with Simula, (Reading, Mass.: Addison-
Wesley, 1989)], which is considered to be the first object-oriented
language. Simula is a general-purpose language, but, as its name
suggests, it includes support for simulations.
• CLOS (Common Lisp Object System)
— An object-oriented extension of Lisp [see S. E. Keene, Object-
Oriented Programming in Common Lisp, (Reading, Mass.: Addi
son-Wesley, 1989)].
www.MathSchoolinternational.com
8.5 N E W ISSUES 445
Exercises
8.5 N ew Issues
In this section we discuss some current topics and future directions.
Concurrency
Persistence
The major database model is the relational model. The basic structure
within a relational database is a table (see Figure 8.5.1). Records correspond
to rows, and columns describe attributes of the records. Operators on a
relational database manipulate the tables (e.g., store a table, retrieve a table,
combine tables).
www.MathSchoolinternational.com
446 CHAPTER 8 ADVANCED TO PICS
Future Directions
www.MathSchoolinternational.com
N E W ISSUES 447
www.MathSchoolinternational.com
www.MathSchoolinternational.com
Appendix A
A S C II Table
449
www.MathSchoolinternational.com
450 A P P E N D IX A
www.MathSchoolinternational.com
ASCII TABLE 451
www.MathSchoolinternational.com
452 A P P E N D IX A
www.MathSchoolinternational.com
Appendix B
Selected C + + Functions
Before summarizing in detail several useful library functions and class meth
ods, we shall briefly describe each. The following lists group the functions
by type:
Math Functions
abs Absolute value of an int floor Floor
acos Arccosine labs Absolute value of a long
asin Arcsine log logex
at an Arctangent loglO logio x
atof Convert string to double pow xy
atoi Convert string to int rand Generate a random integer
atol Convert string to long sin Sine
ce il Ceiling sinh Hyperbolic sine
cos Cosine sqrt Square root
cosh Hyperbolic cosine srand Seed the random number
generator
exp ex tan Tangent
f abs Absolute value of a double tanh. Hyperbolic tangent
453
www.MathSchoolinternational.com
454 APPENDIX В
www.MathSchoolinternational.com
SELECTED C + + FUNCTIO NS 455
String Functions
memchr Find leftmost character in strlen Length of string
object
memcmp Compare objects strncat Concatenate strings
memcpy Copy object strncmp Compare strings
memmove Copy object strncpy Copy string
strcat Concatenate strings strpbrk First break character
strchr Find leftmost character in strrchr Find rightmost character in
string string
strcmp Compare strings strspn Span
strcpy Copy string strstr Find substring
strcspn Complement of span
Miscellaneous Functions
abort Cause abnormal pro set_unexpected Specify function for
gram termination unexpected to call
bsearch Binary search signal Invoke a function to
handle a signal
clearerr Clear end-of-file and er system Execute a command
ror indicators
difftim e Compute difference be terminate End because of excep
tween times tion handling error
exit Terminate program time Find time
qsort Quicksort unexpected Called when illegal
throw specification
set_terminate Specify function for
terminate to call
We now list the functions and class methods alphabetically. Class meth
ods are designated as such and the class to which each belongs is specified.
Each description consists of the file to include (when the Working Paper
so specifies), the function’s declaration, and a few sentences that describe
what the function does. All character codes are given in ASCII. When we
write string, it is the address of (pointer to) a sequence of null-terminated,
contiguous chars.
www.MathSchoolinternational.com
456 A P P E N D IX B
a bort
#include <stdlib.h>
void abort( ) ;
abs
#include <stdlib.h>
in t abs( in t in teger ) ;
Returns the absolute value of integer. See also fabs and labs.
acos
#include <math.h>
double acos( double re a l ) ;
Returns the arccosine (in radians) of real. The value returned is between 0
and 7T.
as in
#include <math.h>
double asin ( double re a l ) ;
Returns the arcsine (in radians) of real. The value returned is between —^
and
a t an
#include <math.h>
double atan( double re a l ) ;
Returns the arctangent (in radians) of real. The value returned is between
- f a n d f-
at of
#include <stdlib.h>
double a t o f( const char *s trin g ) ;
www.MathSchoolinternational.com
SELECTED C + + FUNCTIONS 457
a to i
#include <stdlib.h>
in t a t o i( const char *strin g ) ;
a to l
#include <stdlib.h>
long a t o l( const char *s trin g ) ;
bad
#include <iostream.h>
in t i o s : :b a d ();
bsearch
#include <stdlib.h>
void *bsearch( const void *key,
void *s ta rt,
s iz e _ t n o_elts,
s iz e _ t s iz e _ e lt,
in t ( *cmp ) ( const void *, const void * ) );
Searches for *key in a sorted array of size no_elts whose initial cell is at
address start. The parameter s iz e _ e lt is the size in bytes of one cell
of the array. The parameter cmp is a pointer to a function that compares
*key and an element in the array and returns an integer to signal the result
of the comparison. The first argument to the comparison function *cmp
is key and the second is a pointer to an item in the array. The value of
the expression *cmp( * f i r s t , *second ) is negative if * f i r s t precedes
♦second in the sorted order; *cmp( * f i r s t , *second ) is zero if * f i r s t
is equal to *second; and *cmp( * f i r s t , *second ) is positive if * f i r s t
follows *second in the sorted order. If *key is in the array, bsearch returns
a pointer to a cell containing *key; if *key is not in the array, bsearch
returns NULL.
www.MathSchoolinternational.com
458 A P P E N D IX B
c e il
#include <math.h>
double c e i l ( double re a l ) ;
Returns the least integer (as a double) greater than or equal to real.
c le a r
#include <iostream.h>
void io s : : c le a r ( in t st = 0 ) ;
c le a r e r r
#include <stdio.h>
void c le a re rr( FILE * file _ p o in te r ) ;
Clears the end-of-file and error indicators in the file referenced by f ile _ p o in t-
er.
c lo s e
#include <fstream.h>
void fstream base:: c lo s e ( ) ;
cos
#include <math.h>
double cos( double re a l ) ;
cosh
#include <math.h>
double cosh( double re a l ) ;
d ifft im e
#include <time.h>
double d ifftim e ( time_t end, time_t begin ) ;
Returns the difference (end —begin), in seconds, between the times end and
begin. See also time.
www.MathSchoolinternational.com
SELECTED C + + FUNCTIONS 459
eof
#include <iostream.h>
in t i o s : : e o f( ) ;
e x it
#include <stdlib.h>
void e x it ( in t status_value ) ;
Terminates the program and sends the value status_value to the invoking
process (operating system, another program, etc.). The constants EXIT_SUC-
CESS and EXIT_FAILURE, defined in stdlib.h, may be used as arguments to
e x it to indicate successful or unsuccessful termination. The function e x it
flushes all buffers and closes all open files.
exp
#include <math.h>
double exp( double re a l ) ;
Returns ereal, where e (2.71828...) is the base of the natural logarithm. See
also pow.
f abs
#include <math.h>
double fa b s( double re a l ) ;
Returns the absolute value of real. See also abs and labs.
fa il
#include <iostream.h>
in t i o s : : f a i l ( ) ;
fc lo s e
#include <stdio.h>
in t fc lo s e ( FILE * file _ p o in te r ) ;
Closes the file referenced by f ile_p oin ter. Flushes all buffers. If successful,
f close returns 0; otherwise, it returns EOF.
www.MathSchoolinternational.com
460 A P P E N D IX B
fg e t c
#include <stdio.h>
in t fg e t c ( FILE * file _ p o in te r ) ;
Returns the next character from the file referenced by f ile_p o in ter, or if
the end of the file is reached or an error occurs, it returns EOF. Equivalent
to the function getc. See also getc, getchar, and ungetc.
fgets
#include <stdio.h>
char * fg e t s ( char ^storage, in t max_line,
FILE * file _ p o in te r ) ;
Reads the next line from the file referenced by file _ p o in te r and stores it
at address storage. The “next line” consists of
The next max_line — 1 characters.
or
All characters up to and including the next newline character.
or
All characters up to the end of the file.
whichever is shortest. If at least one character is stored, fg e ts adds a
terminating null ’ \0’ to the end of the line. Notice that fg e ts stores the
newline character if it was read, and that fg e ts never stores more than
max_line characters (including newline and ’ NO’ ). If no characters are
stored or an error occurs, fg e ts returns NULL; otherwise, fg e ts returns the
address storage. See also gets.
fill
#include <iostream.h>
char i o s : : f i l l ( ) ;
char i o s : : f i l l ( char fill_ c h a r ) ;
The first version returns the current fill character. The second version
changes the fill character to fill_ c h a r and returns the old fill character.
flags
#include <iostream.h>
long i o s : : f l a g s ( ) ;
long i o s : : f la g s ( long new_flags ) ;
The first version returns the current format flags. The second version changes
the format flags to new_f lags and returns the old flags.
www.MathSchoolinternational.com
SELECTED C + + FUNCTIONS 461
flo o r
#include <math.h>
double f l o o r ( double re a l ) ;
Returns the greatest integer (as a double) less than or equal to real.
flu s h
#include <iostream.h>
ostreamfe ostream::f l u s h ();
f open
#include <stdio.h>
FILE *fopen( const char *s trin g , const chair *mode ) ;
www.MathSchoolinternational.com
462 A P P E N D IX B
fp r in tf
#include <stdio.h>
in t f p r in t f ( FILE * file _ p o in t e r , const char *strin g, );
Reads up to count items, each of s ize bytes, from the file referenced by
file _ p o in te r. The items are stored in memory, beginning at address
storage. The function fread returns the number of items ( not bytes) read.
fscanf
#include <stdio.h>
in t fs c a n f( FILE * file _ p o in t e r , const char * s t r in g ,. . . ) ;
Reads formatted input from the file referenced by f ile_p o in ter. The con
verted data are stored at addresses given by the arguments that follow
string, which contains the format specifications for the data read. If the
end of the file is reached before any conversion, fscanf returns EOF; other
wise, it returns the number of items read and stored. See also scanf and
sscanf.
www.MathSchoolinternational.com
SELECTED C + + FUNCTIO NS 463
f seek
#include <stdio.h>
in t fs e e k ( FILE * file _ p o in te r , long o ffs e t , in t base ) ;
Repositions the file position marker in the file referenced by f ile_p o in ter.
In a binary file, fseek repositions the file position marker o ffs e t bytes from
the beginning of the file (if base is equal to SEEK_SET), from the current
position of the file position marker (if base is equal to SEEK_CUR), or from
the end of the file (if base is equal to SEEK_END). In a text file, base must
be equal to SEEK_SET and o ffs e t must be either zero (in which case the file
position marker is moved to the beginning of the file) or a value returned
previously by f t e l l (in which case the file position marker is moved to
a previously saved position). If successful, fseek returns 0; otherwise, it
returns a nonzero value. See also f t e l l and rewind.
ft e ll
#include <stdio.h>
long f t e l l ( FILE * file _ p o in te r ) ;
Returns the location of the file position marker in the file referenced by
f ile _ p o in te r, or in case of error, it returns —1. If the file is a binary file,
the location is measured in bytes from the beginning of the file. If the file
is a text file, the value returned by f t e l l is useful only as an argument to
fseek. See also fseek.
fw r it e
#include <stdio.h>
s iz e _ t fw r it e ( const void ^storage, s iz e _ t s iz e ,
s ize _ t count, FILE * file _ p o in te r ) ;
Writes count items from address storage (unless an error occurs), each of
s iz e bytes, to the file referenced by file _ p o in te r. Returns the number of
items written.
gcount
#include <iostream.h>
in t istrea m ::gcount( ) ;
www.MathSchoolinternational.com
464 A P P E N D IX B
get
#include <iostream.h>
istreamfe istrea m ::g e t ( signed char* b u ff,
in t n,
char stop = ’ \n’ ) ;
istreamfe is tre a m ::g e t( unsigned char* b u ff,
in t n,
char stop = ’ \n’ ) ;
istreamfe istrea m ::g e t ( signed charfe c ) ;
istreamfe is tre a m ::g e t( unsigned charfe c ) ;
istreamfe is tre a m ::g e t( streambuffe sbu ff, char stop = ’ \n’ ) ;
in t is tr e a m ::g e t ();
In the first two versions, characters are read from the steam intothe array-
buff until the character stop, whose default value is ’ \n’ ,is encountered,
until end-of-stream, or until n - 1 characters have been read into buff,
whichever happens first. The character stop is not placed in the array buff,
nor is it removed from the stream. The method get adds a null terminator
’ \0’ .
In the third and fourth versions, the next character, white space or not,
is read into c.
In the fifth version, characters are read from the stream into the stream
buf object sbuff until the character stop, whose default value is ’ \n’ , is
encountered. The character stop is not placed into sbuff, nor is it removed
from the stream.
In all but the last version, get returns the updated stream.
In the last version, the next character, white space or not, is returned,
or if no characters remain to be read, get returns EOF.
g e tc
#include <stdio.h>
in t g e tc ( FILE * file _ p o in te r ) ;
The function getc is equivalent to fg etc, except that getc is usually im
plemented as a macro. The function getc returns the next character from
the file referenced by f ile _p o in te r, or if the end of the file is reached or an
error occurs, it returns EOF. See also fg etc, get char, and ungetc.
getch ar
#include <stdio.h>
in t getchar( void ) ;
Returns the next character from the standard input, or if the end of the
file is reached or an error occurs, it returns EOF. See also fgetc, getc, and
ungetc.
www.MathSchoolinternational.com
SELECTED C + + FUN C TIO N S 465
gets
#include <stdio.h>
char * g e ts ( char *storage ) ;
Reads the next line from the standard input. The “next line” consists of
all characters up to and including the next newline character or the end of
the file, whichever comes first. If at least one character is read, gets stores
at address storage all characters read except the newline that is discarded
and adds a terminating null to the end of the line. Notice that gets never
stores a newline character. If no characters are stored or an error occurs,
gets returns NULL; otherwise, gets returns the address storage. See also
fg ets.
good
#include <iostream.h>
in t io s ::g o o d ();
ignore
#include <iostream.h>
istreamft ign ore( in t count = 1, in t stop = EOF ) ;
Removes count characters from the stream, or all characters from the stream
up to stop, whichever comes first. The removed characters are not stored,
but discarded. Returns the updated stream.
isalnum
#include <ctype.h>
in t isalnum( in t character ) ;
is a lp h a
#include <ctype.h>
in t isalpha( in t character ) ;
www.MathSchoolinternational.com
466 A P P E N D IX B
is c n t r l
#include <ctype.h>
in t is c n t r l( in t character ) ;
is d ig it
#include <ctype.h>
in t i s d i g i t ( in t character ) ;
isgrap h
#include <ctype.h>
in t isgraph( in t character ) ;
is lo w e r
#include <ctype.h>
in t islo w er( in t character ) ;
is p r in t
#include <ctype.h>
in t is p r in t( in t character ) ;
ispunct
#include <ctype.h>
in t ispunct( in t character ) ;
www.MathSchoolinternational.com
SELECTED C + + FUNCTIO NS 467
isspace
#include <ctype.h>
in t isspace( in t character ) ;
isupper
#include <ctype.h>
in t isupper( in t character ) ;
is x d i g i t
#include <ctype.h>
in t is x d i g i t ( in t character ) ;
labs
#include <stdlib.h>
long la b s( long in teger ) ;
Returns the absolute value of integer. See also abs and fabs.
lo g
#include <math.h>
double lo g ( double re a l ) ;
loglO
#include <math.h>
double lo g lO ( double re a l ) ;
www.MathSchoolinternational.com
468 A P P E N D IX B
memchr
#include <string.h>
void *memchr( const void *block, in t character, s iz e _ t numb ) ;
Returns the address of the first occurrence of character in the first numb
bytes of the object at address block, or if character does not appear in
the first numb bytes of the object, it returns NULL. On some systems, memchr
may execute faster than strchr. See also strchr and strrchr.
memcmp
#include <string.h>
in t memcmp( const void *b lock l,
const void *block2,
s iz e _ t numb ) ;
Compares the first numb bytes of the object at address blockl with the first
numb bytes of the object at address block2. Returns a negative integer if the
item at blockl is less than the item at block2. Returns zero if the item at
blockl is equal to the item at block2. Returns a positive integer if the item
at blockl is greater than the item at block2. On some systems, memcmp
may execute faster than strncmp. See also strcmp and strncmp.
memcpy
#include <string.h>
void *memcpy( void *b lock l, const void *block2, s iz e _ t numb ) ;
Copies the first numb bytes of the object at address block2 into the object at
address blockl and returns blockl. The copy may not work if the objects
overlap. On some systems, memcpy may execute faster than memmove and
strncpy. See also memmove, strcpy, and strncpy.
memmove
#include <string.h>
void *memmove( void *b lock l, const void *block2, s iz e _ t numb ) ;
Copies the first numb bytes of the object at address block2 into the object at
address blockl and returns blockl. The objects are allowed to overlap. On
some systems, memmove may execute faster than strncpy. See also memcpy,
strcpy, and strncpy.
www.MathSchoolinternational.com
SELECTED C + + FUNCTIONS 469
open
#include <fstream.h>
void fstream base::open( const char* filename,
in t mode,
in t p tr = f i l e b u f : : openprot ) ;
void ofstream :: open( const char* filename,
in t mode = io s : : out,
in t p tr = f i l e b u f : : openprot ) ;
void ifs tre a m ::open( const char* filename,
in t mode = io s ::in ,
in t p tr = f i l e b u f : : openprot ) ;
void fstrea m ::open( const char* filename,
in t mode,
in t p tr = f i l e b u f : : openprot ) ;
Opens the file filename in mode mode with protection p tr and associates it
with an already existing object.
pcount
#include <strstream.h>
in t ostrstream ::pcount( ) ;
peek
#include <iostream.h>
in t is tre a m ::p e e k ();
Returns, but does not remove, the next character from the stream. If no
characters remain to be read, it returns EDF.
pow
#include <math.h>
double pow( double r e a ll, double real2 ) ;
#include <iostream.h>
in t i o s : :p r e c is io n ();
in t io s ::p r e c is io n ( in t new_prec ) ;
The first version returns the current precision. The second version changes
the precision to new_prec and returns the old precision.
www.MathSchoolinternational.com
470 A P P E N D IX B
p r in tf
#include <stdio.h>
in t p r in t f( const char * s t r in g ,. . . ) ;
Puts the character c back into the stream and returns the updated stream.
putc
#include <stdio.h>
in t putc( in t character, FILE * file _ p o in te r ) ;
The function putc is equivalent to fputc, except that putc is usually im
plemented as a macro. The function putc writes character to the file ref
erenced by f ile_p o in ter. In addition, putc returns the character written,
or in case of error, it returns EOF. See also fputc and putchar.
put chair
#include <stdio.h>
in t putchar( in t character ) ;
www.MathSchoolinternational.com
SELECTED C + + FUNCTIO NS 471
qsort
#include <stdlib.h>
void q s o rt( void *s ta rt, s iz e _ t n o_elts, s iz e _ t s iz e _ e lt ,
in t ( *cmp ) ( const void *, const void * ) ) ;
Sorts an array of size no_elts whose initial cell is at address start. The
parameter s iz e _ e lt is the size of one cell of the array in bytes. The pa
rameter cmp is a pointer to a function that compares two elements whose
data type is the same as that of the array and returns an integer to signal
the result of the comparison. The arguments to the comparison function
♦cmp are pointers to the two items to be compared. The value of the ex
pression * cmp ( * f i r s t , *second ) is negative if * f i r s t precedes * second
in the sorted order; *cmp( * f i r s t , *second ) is zero if * f i r s t is equal
to * second; and *cmp( * f i r s t , *second ) is positive if * f i r s t follows
♦second in the sorted order.
rand
#include <stdlib.h>
in t rand( void ) ;
rdbuf
#include <strstream.h>
strstreambuf* strstreambase: : rdbuf( ) ;
rd s ta te
#include <iostream.h>
in t i o s : : rd s ta te ( ) ;
read
#include <iostream.h>
istreamfe read( signed char* b u ff, in t n ) ;
istreamfe read( unsigned char* b u ff, in t n ) ;
www.MathSchoolinternational.com
472 A P P E N D IX B
rewind
#include <stdio.h>
void rewind( FILE * file _ p o in te r ) ;
#include <stdio.h>
in t scanf( const char * s t r in g ,. . . ) ;
Reads formatted input from the standard input. The converted data are
stored at addresses given by the arguments that follow string, which con
tains the format specifications for the data read. If the end of the file is
reached before any conversion, scanf returns EOF; otherwise, it returns the
number of items read and stored. See also fscanf and sscanf.
seekg
#include <iostream.h>
istreamfe istrea m :: seekg( streamoff o f f , seek_dir d ir ) ;
istreamfe istrea m ::seekg( streampos pos ) ;
The first version moves the input stream position marker o f f bytes from d ir,
which must be one of: beg (from the beginning of the stream), cur (from the
current position), or end (from the end of the stream). The second version
sets the input stream position marker to location pos, which should be a
value returned by t e llg . Returns the updated stream.
seekp
#include <iostream.h>
ostreamfe ostream :: seekp( streamoff o f f , seek_dir d ir ) ;
ostreamfe ostream :: seekp( streampos pos ) ;
The first version moves the output stream position marker o f f bytes from
dir, which must be one of: beg (from the beginning of the stream), cur
(from the current position), or end (from the end of the stream). The second
version sets the output stream position marker to location pos, which should
be a value returned by t e llp . Returns the updated stream.
se tf
#include <iostream.h>
long i o s : : s e t f ( long spec_flags ) ;
long i o s : : s e t f ( long spec_flags, long f i e l d ) ;
The first version sets specified format flags spec_flags. In the second ver
sion, f i e l d must be one of
www.MathSchoolinternational.com
SELECTED C + + FUNCTIO NS 473
set_term in ate
typedef v o id ( *PFV ) ( ) ;
PFV set_term inate( PFV ) ;
set-unexpected
typedef v o id ( *PFV ) ( ) ;
PFV set_unexpected( PFV ) ;
sig n a l
#include <signal.h>
void ( *s ig n a l( in t s ig , void ( ^handler ) ( in t ) ) ) ( in t ) ;
Catches a signal and invokes a function to handle the signal. If the request
can be handled, signal returns the value of handler for the previous call
to sign al for the given sig; otherwise, it returns SIG_ERR.
sm
#include <math.h>
double s in ( double re a l ) ;
www.MathSchoolinternational.com
474 A P P E N D IX B
sinh
#include <math.h>
double sinh( double re a l ) ;
s p r in t f
#include <stdio.h>
in t sp rin tf ( char *storage, const chair * s t r in g , . . . ) ;
s q rt
#include <math.h>
double s q r t( double re a l ) ;
srand
#include <stdlib.h>
void srand( unsigned in t seed ) ;
Seeds the random number generator. Calling srand with seed equal to 1 is
equivalent to calling the random number function rand without first invoicing
srand. See also rand.
sscan f
#include <stdio.h>
in t sscanf( const char * s tr in g l, const char * s tr in g 2 ,. . . ) ;
Reads formatted input from s trin g l. The converted data are stored at
addresses given by the arguments that follow string2, which contains the
format specifications for the data read. If the end of s tr in g l is reached
before any conversion, sscanf returns EOF; otherwise, it returns the number
of items read and stored. See also f scanf and scanf.
www.MathSchoolinternational.com
SELECTED C + + FUNCTIO NS 475
str
#include <strstream.h>
char* ostrstream :: s t r ( ) ;
char* s tr s tr e a m ::s tr ();
Returns a pointer to the character array buffer. If the buffer was allocated
by the system, the user is now responsible for deallocating it.
strcat
#include <string.h>
char * s tr c a t( char * s tr in g l, const char *string2 ) ;
Copies string2 to the end of s trin g l. Returns s trin g l (the address of the
first string). See also strncat.
strchr
#include <string.h>
char *s trc h r( const char *s trin g , in t character ) ;
strcmp
#include <string.h>
in t strcmp( const char * s tr in g l, const char *strin g2 ) ;
strcpy
#include <string.h>
char *strcp y ( char * s tr in g l, const char *string2 ) ;
strcspn
#include <string.h>
s iz e _ t strcspn( const char * s tr in g l, const char *string2 ) ;
www.MathSchoolinternational.com
476 A P P E N D IX B
s t r le n
#include <string.h>
s iz e _ t s tr le n ( const chair *s trin g ) ;
strn c a t
#include <string.h>
char *strn ca t( chau: * s tr in g l, const char *strin g2,
s iz e _ t max_len ) ;
strncmp
#include <string.h>
in t strncmp( const char * s tr in g l,
const char *strin g2 , s iz e _ t max_len ) ;
strncpy
#include <string.h>
char *strncpy( chair * s tr in g l, const char *strin g2 ,
s iz e _ t max_len ) ;
Copies exactly max_len characters (counting the null terminator ’ \0’ ) from
string2 to s trin g l. If the length of string2 is less than maLX_len, null
terminators are used to fill s trin g l. The resulting string is not not null
terminated if the length of string2 is greater than or equal to maix_len.
Returns s tr in g l (the address of the first string). See also strcpy, memcpy,
and memmove.
strp b rk
#include <string.h>
char *strpbrk( const chair * s tr in g l, const chair *strin g2 ) ;
www.MathSchoolinternational.com
SELECTED C + + FUNCTIO NS 477
strrchr
#include <string.h>
char *s trrc h r( const char *strin g , int character ) ;
strspn
#include <string.h>
s iz e _t strspn( const char * s t r in g l, const char *strin g2 ) ;
strstr
#include <string.h>
char * s t r s t r ( const char * s t r in g l, const char *strin g2 ) ;
sync_with_stdio
#include <iostream.h>
s ta tic void io s ::s y n c _w ith _s td io ();
system
tan
#include <math.h>
double tan( double re a l ) ;
www.MathSchoolinternational.com
478 A P P E N D IX B
tanh
#include <math.h>
double tanh( double re a l ) ;
#include <iostream.h>
streampos i s t r e a m : : t e llg ();
#include <iostream.h>
streampos o s tr e a m ::t e llp ();
#include <iostream.h>
ostream* i o s : : t i e ( ostream* out ) ;
ostream* i o s : : t i e ( ) ;
In the first version, out is tied to the (input) stream object, on which t i e is
invoked. If out is zero, t i e breaks the tie, if any. In either case, t i e returns
the output stream to which the (input) stream object was previously tied
or, if the stream object was not tied to an output stream, it returns zero.
In the second version, t i e returns the stream to which the (input) object
is tied, or zero, if it is not tied to an output stream.
time
#include <time.h>
tim e_t tim e( tim e_t *storage ) ;
www.MathSchoolinternational.com
SELECTED C + + FUNCTIONS 479
tolow er
#include <ctype.h>
in t tolow er( int character ) ;
toupper
#include <ctype.h>
int toupper( int character ) ;
unexpected
void unexpectedO ;
ungetc
#include <stdio.h>
int ungetc( int c, FILE *file _p o in te r ) ;
unsetf
#include <iostream.h>
long io s ::u n s e t f( long spec_flags ) ;
width
#include <iostream.h>
int i o s : : w id t h ();
int io s ::w id th ( int new_width ) ;
The first version returns the field width. The second version changes the
field width to new_width and returns the old field width.
www.MathSchoolinternational.com
480 A P P E N D IX B
w rite
#include <iostream.h>
ostreamfe ostream ::w r ite ( const signed char* b u ff, in t n ) ;
ostreamfe ostream ::w r ite ( const unsigned char* b u ff, in t n ) ;
Writes n characters from the array buff to the output stream. Returns the
updated stream.
www.MathSchoolinternational.com
Appendix C
U N IX
On-line Help
man
’/, man cp
asks the system to display to the standard output the manual pages on the
cp command. (We are using */, as the system prompt.) The man command
also may be used with benign self-reference. The command
V, man man
asks the system to display information about the man command itself. If you
want more information about the commands discussed in this appendix, you
may find it convenient to use the man command.
481
www.MathSchoolinternational.com
482 A P P E N D IX C
a single load module is produced. (The files can be listed in any order.) The
object modules produced along the way, main, o, sensors, o, and plans, o, are
deleted automatically once the load module has been produced. Each object
module receives a . 0 extension by default. The load module is named a. out
by default. To execute the load module, the user enters its name
'/, a.out
% g++ -c plans.C
www.MathSchoolinternational.com
UNIX 483
The -c ( “compile” only) flag specifies that an object module, rather than a
load module, should be produced as output. In this case, the object module
is named plans, o. After separately compiling each of main. C, sensors. C, and
plans. C, we have the object modules main.o, sensors, o, and plans, o. These
object modules can then be linked by issuing the command
’/, g++ main.o plans.o sensors.o
The load module is named a. out. The g++ command can be invoked with
any mix of .C and .o files. For example, the command
’/, g++ main.C plans.o sensors.C
produces a load module from the source files main. C and sensors. C and the
object module plans, o. The load module is again named a. out.
The g++ command allows several options including:
Option Meaning
-c Compile separately, producing an object module rather
than a load module.
-lm Load referenced modules from the mathematics library.
-o name Name the resulting load module name instead of a. out,
the default.
-w Suppress warning messages.
-E Have the preprocessor, but not the compiler, pass over
the file and print the result to the standard output.
-0 Use the optimizer.
www.MathSchoolinternational.com
484 A P P E N D IX C
is the full path name of the file robotplans. C, which resides in the child direc
tory fred whose parent directory is users, which in turn is a child directory
of root (see Figure D .l). A working directory is the directory in which
you currently find yourself. For example, after you have just logged onto the
system, you may find that your working directory is /users/fred. We next
consider some UNIX commands for navigating its directory structure.
pwd, cd
The command pwd ( “print working directory” ) displays the working direc
tory. For example, if the working directory is /users/'fred/robotplans, then
’/. pwd
displays
/users/fred/robotplans
The command cd ( “change directory” ) changes the working directory.
For example, if the working directory is /users/fred/robotplans, then
’/, cd roughdraft
changes the working directory to /users/fred/robotplans/roughdraft, assum
ing that roughdraft is a child directory of /users/fred/robotplans. The com
mand
'/, cd /users/fred/robotplans/roughdraft
has the same effect regardless of what the working directory is, as the com
mand specifies the full path name.
m kdir, rmdir
Directories may be created with the mkdir ( “make directory” ) command and
destroyed with the rmdir ( “remove directory” ) command. If the working
directory is /users/fred, the command
*/, mkdir scratch
www.MathSchoolinternational.com
UNIX 485
rm
Is, c a t, p r, lp , more
UNIX provides various commands for displaying files, finding files, finding
contents of files, and copying or moving files. The command Is ( “list” ) lists
files in the working directory, except those such as .profile or .login whose
names begin with a period. The command
’/, Is -a
lists all such files, including those such as .profile whose names do begin with
a period. The Is command also can be used with the wildcard character
and with full path names. For example, the command
www.MathSchoolinternational.com
486 A P P E N D IX C
V, Is /users/fred/robotplans/*.h
lists all files with a .h extension in the subdirectory /users/fred/robotplans,
whatever the working directory may be.
The command cat ( “concatenate” )
*/, cat walk.C talk.C chew_gum.C
displays to the standard output the contents of files walk.C, talk.C, and
chew-gum. C if these files reside in the working directory. Again, cat may
specify the full path name, as in
’/, cat /users/fred/robotplans/defs.h
The pr ( “print” ) command behaves similarly to the cat command, ex
cept that it does some formatting. For example, pr breaks the displayed
text into numbered pages, whereas cat does not. Either command may be
used with wildcard characters as, for example, in the command
'/, pr /users/fred/robotplans/*.h
which formats and displays the contents of all files with a .h extension in the
specified directory.
If we cat or pr a file that has too many lines to be displayed all at once,
UNIX simply displays the lines without pausing so that the top lines cannot
be seen when the bottom ones are finally displayed. A solution is to use the
more command, which stops after displaying as many lines as will fit on the
display. An example is
*/, more /users/f r ed/scr at ch/dr aiftl.C
After the screen fills, to advance one line, the user hits Return-, to advance
one full screen, the user hits the space bar.
The command lp ( “line printer” ) sends a designated file to the line
printer. For example, the command
*/, lp /users/fred/robotplans/defs.h
requests that the file /users/fred/robotplans/defs.h be printed. Later in this
appendix we explain how the pr and lp commands may be combined.
grep , fin d
The command grep ( “grab regular expression” ) can be used to search a file
for a pattern, and the command find ( “find” ) can be used to find a file.
Suppose, for example, that we want to find all occurrences of the pattern
misanthrope
in any file with a .txt extension in the working directory. The command
'/, grep misanthrope * .t x t
does the job by displaying to the standard output any line in the file that
contains the pattern misanthrope. If the pattern contains white space, it
should be enclosed in single quotation marks. For example, the command
www.MathSchoolinternational.com
UNIX 487
cp, mv
UNIX has commands to copy and move files. The command cp ( “copy” )
makes a copy of a specified file, whereas the command mv ( “move” ) moves a
specified file. For example, the command
*/, cp /users/fred/games.C /tmp/hide.C
copies the file /users/fred/games.C to the file /tmp/hide.C. If the latter file
does not already exists, UNIX creates it; if it does exist, UNIX overwrites
the previous contents with /users/fred/games.C. Accordingly, cp should be
used with caution.
The command
*/, mv /users/fred/games.C newgames.C
moves the file /users/fred/games.C to the file newgames.C in the working
directory. Again, UNIX creates newgames. C if it does not exist already and
overwrites it otherwise. After the mv command, the file /users/fred/games. C
ceases to exist; after the cp command, /users/fred/games.C continues to
exist.
www.MathSchoolinternational.com
488 APPENDIX C
To use the make utility, we first create a file called makefile, which looks like
taxes: main.o income.o expenses.o
g++ -o taxes main.o income.o expenses.o
main.o: glob als.h main.C
g++ -c main.C
income.o: glob als.h income.C
g++ -c income.C
expenses.o: glob als.h defs.h expenses.C
g++ -c expenses.C
The file has two types of commands. The unindented commands, such as
taxes: main.o income.o expenses.o
are dependency descriptions. A dependency description shows which mod
ules depend on other modules in the sense that certain modules are needed to
produce another module. This particular dependency description shows that
the (load) module taxes depends on the object modules main.o, income.o,
and expenses.o. The indented commands, such as
g++ -o taxes main.o income.o expenses.o
are compile-link descriptions. A compile-link description shows what needs
to be compiled and/or linked to obtain the required module. This par
ticular compile-link description shows the command that links main.o, in
come, o, and expenses.o to obtain taxes. Our example makefile also shows
that main.o depends on globals.h and main.C; income.o depends on globals.h
and income. C] and expenses, o depends on globals.h, defs.h, and expenses. C.
Furthermore, we obtain main.o by compiling main.C', we obtain income.o
by compiling income. C; and we obtain expenses, o by compiling expenses. C.
www.MathSchoolinternational.com
UNIX 489
www.MathSchoolinternational.com
490 A P P E N D IX C
stock-tips reads from the standard input and writes to temp.dat, after which
report-tips reads from temp.dat and writes to the standard output. A pipe
accomplishes the same result, but more conveniently:
The vertical bar I designates a pipe, stock-tips pipes its output into re-
port-tips, which then writes to the standard output.
A pipeline may be built out of individual pipes. Suppose that we want
the input to stock-tips to be sorted before it is formatted by report-tips and
written to the standard output and that we have a program sort-tips that
does the sorting. We could build a pipeline as follows:
The input to stock-tips is the standard input. Because of the first pipe, the
output of stock-tips is the input to sort-tips. Because of the second pipe, the
output of sort-tips is the input to report-tips, and report-tips writes to the
standard output.
Pipes can be combined with redirection. The following command is the
same as the preceding command except that the report is written to the file
report, dat:
'/, pr /users/fred/robotplans/defs.h I lp
As a final example, suppose that we want a printed copy of the UNIX manual
pages on the command grep. The command
% man grep | lp
redirects the output of man to lp, which gives us a printed copy. UNIX
encourages its users to become pipers.
www.MathSchoolinternational.com
UNIX 491
Run-Tim e Libraries
System header files such as math.h usually contain function declarations
in addition to macros and typedefs. For example, the header file math.h
includes declarations such as
extern double pow( double, double ) ;
extern double f l o o r ( double ) ;
extern double c e i l ( double ) ;
because C + + requires that all functions have prototype declarations. The
system typically provides the functions themselves as object modules col
lected in a run-time library, that is, a library of functions that an applications
program can access at run time but for which the source code is not avail
able. For example, the functions declared in math.h are available in most
UNIX systems in the run-time library libm. a. To access the functions in this
library, an applications program typically must be linked explicitly with this
library. This can be done by using the -lm option in the g++ command. For
instance, if we wrote statistics functions that needed mathematics functions
such as pow, flo o r , and c e il, and placed these functions in the file stats.C,
our g++ command might look like
*/• g++ -c stats.C -lm
The -lm option in the command directs the linker to the library named
libm. a. If the g++ command succeeds, the object module produced, stats, o,
contains not only the functions defined in stats. C but also any functions in
libm. a, such as pow, invoked in stats. C.
In general, run-time libraries have names of the pattern libNAME.a,
where NAM E identifies the particular library. To take a second example,
most UNIX implementations provide a library named libcurses.a, which con
tains functions for screen management and basic graphics. This library, too,
can be linked through the -1 option in the g++ command:
'/• g++ - c cusses_with_curses.C -lcurses
In the two preceding examples, the -1 option does not give the full path name
for the library because UNIX searches one or more default directories to find
a specified library. Many run-time libraries, such as libm.a and libcurses.a,
reside in the directory /usr/lib.
Programmers often find it useful to build run-time libraries of their own,
thereby allowing the component functions to be shared among many different
applications programs. It is common for each such library to have its own
header file that contains declarations for the functions implemented in the
library. The library and the header file could be located in any directory,
but it is convenient to place them in default directories so that their full
path names need not be given in #include directives or -1 options. The
C + + preprocessor, when encountering an #include directive with a header
www.MathSchoolinternational.com
A P P E N D IX C
file name in angle brackets, searches one or more default directories for the
header file. A familiar example is
#include <string.h>
Many system header files, such as string.h, reside in the directory
/usr/include. If our header files reside in a default directory, angle brack
ets may be used in the corresponding #include directive. If our run-time
library’s name follows the pattern libNAME. a and resides in a default direc
tory the -1 option in the g++ command need not give the library’s full path
name. We illustrate with a short example that assumes that /usr/include
is a default directory for header files and that /usr/lib is a default directory
for run-time libraries.
Suppose that we want to build a library of statistical functions for use
in a variety of applications programs. We create a header file
/usr/include/stats, h
// mean of n doubles
extern double mean( double nums[ ] , in t n ) ;
// variance of n doubles
extern double va r( double nums[ ] , in t n, double mean ) ;
An applications program now can #include our header file with the direc
tive
#include <stats.h>
Definitions for our statistical functions, which invoke mathematics functions
such as pow and flo o r, reside in the file stats. C. Accordingly, we compile
stats. C with the -lm option:
'/» g++ ~c stats.C -lm
The object module produced, stats, o, contains our functions and ones from
the mathematics library. Next, we use the object module to create a run
time library named, say, libstats. a and we move libstats. a to a default library
directory such as /usr/lib. (On most UNIX systems, a run-time library is
created from one or more object modules by using the Id commands with
specified flags.) An applications program that needs to access our run-time
library should have the #include directive for stats.h in the appropriate
source files and should use the -1 option in the g++ command:
'/. g++ -o sm all_lies source.C -ls ta ts
www.MathSchoolinternational.com
UNIX 493
Note that the application sees no distinction between our run-time library
and one furnished by a UNIX system.
www.MathSchoolinternational.com
www.MathSchoolinternational.com
Appendix D
Borland C+-J
This appendix summarizes the commands for compiling, linking, and run
ning a C + + program in Borland C + + . Borland C + + provides two different
ways to compile programs. The first way is to issue UNIX-like instructions
from the command line, and the second way is to use a windows-like envi
ronment that includes a compiler, linker, editor, and debugger. We discuss
each method in turn.
We first discuss the situation in which the entire program resides in one file,
say convert.cpp. (Borland C + + files typically use the extension .cpp.) To
compile and link the program, we issue the command
C> bcc convert.cpp
(We assume that C> is the system prompt.) The executable file is named
convert.exe. To rim the program, we type
C> convert
To compile and link multiple source modules that make up a program,
we proceed as follows. Suppose that the program comprises the modules se
ries. cpp, sum. cpp, and transform, cpp. To compile and link the three modules
from the command line, we issue the command
C> bcc series.cpp sum.cpp transform.cpp
The name of the load module produced, series.exe, is derived from the first
file listed. To run the program, we type
495
www.MathSchoolinternational.com
496 A PPE N D IX D
C> series
It is also possible to compile each file individually and then link the
resulting object files. In this case, we issue the commands
C> bcc -c series.cpp
C> bcc -c sum.cpp
C> bcc -c transform.cpp
At this point, we have the object modules series, obj, sum. obj, and trans
form, obj. To link these object modules and produce the load module se
ries. exe, we issue the command
C> bcc se rie s.o b j sum.obj transform.obj
T h e Integrated Environment
www.MathSchoolinternational.com
BO RLAND C + + 497
= F ile Edit Search. Run Compile Debug Project Options W indow Help
- p [ > ] ----- COUVEB,T.CPP = ------- 8 = [ T ] =f]
▲
▼
1:1 = • < ■ I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I I II .J
---------------------------------- M e s s a g e -------------------- 1-
key. To correct the first error, hit Return. You will automatically be placed
into the editor, and the cursor will be at the position in the file that caused
the error message to be generated. You can now correct this error.
To correct the next error, click on Next Msg at the bottom of the screen
or hit Alt-F8; either moves the cursor to the line that caused the next error
message. Since you remain in the editor, the next error can immediately
be corrected. Clicking on Prev Msg or hitting Alt-F7 moves to the previous
error, and clicking on Next Msg or hitting Alt-F8 moves to the next error.
After correcting all the errors, the program can be rerun by selecting Run
on the main menu and then selecting Run on the run pop-up menu.
To save the editor file, select File on the main menu and then Save on
the file pop-up menu, or hit F2. To leave any pop-up menu, hit Esc. To
leave the integrated environment and return to windows or DOS, select File
on the main menu and then Quit on the file pop-up menu, or type Alt-x.
When the convert program is successfully compiled and linked, the ex
ecutable file convert.exe is created. This file can be run from the MS-DOS
command line by typing
C> convert
To compile, link, and run a C + + program divided among two or more
source files in the integrated environment, we first use the editor to create the
www.MathSchoolinternational.com
498 A P P E N D IX D
Find/Replace/Block Commands
Action Command
Find Ctrl-qf
Find/replace Ctrl-qa
Begin block Ctrl-kb
End block Ctrl-kk
Copy block Ctrl-kc
Delete block Ctrl-ky
Hide/display block Ctrl-kh
Move block Ctrl-kv
www.MathSchoolinternational.com
BORLAND C + + 499
files, say series, cpp, sum. cpp, and transform, cpp. We then create a “project”
that tells Borland C + + the names of the files that make up the program.
To open a project, select Project on the main menu and then select Open
on the project pop-up menu. In the space provided, type the name of the
project. In this example, we might select the name series. At this point,
the message window at the bottom of the screen is replaced by the project
window. To add files to the project, select Project on the main menu and
then select Add on the project pop-up menu. A window pops up into which
the names of the files that make up the project can be entered. Type in the
file names series, cpp, sum. cpp, and transform, cpp, and terminate each with
Return. After each file name is entered, it is also displayed in the project
window. After all the files are added, hit Esc to leave the add pop-up
window. To compile the program, select Compile on the main menu. Then
in the compile pop-up window, select Make. Borland C + + tries to compile
and link all files in the project into an executable file. Errors are flagged and
corrected, as described previously. After the files are successfully compiled
and linked, hit Return to leave the compile message window. To rim the
program, select Run on the main menu, then select the Run option on the
run pop-up window.
When the program is successfully compiled and linked, the executable file
series.exe, whose name is derived from the project name series, is created.
This file can be run from the MS-DOS command line by typing
C> series
www.MathSchoolinternational.com
i
www.MathSchoolinternational.com
Hints and Solutions to
Odd-Numbered Exercises
Section 1.1
7. When code that has been carefully designed and tested is reused, the
reused version will perform as reliably as the original. Since object-
oriented design provides a cleaner separation of the components, mainte
nance— being easier— will also be more reliable.
Section 1.2
3. Method store should copy the characters passed into the array data and
set len to the length of the string. Method length should simply return
len.
5. class stack {
in t data[ 100 ] ;
in t top;
501
www.MathSchoolinternational.com
502 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
p u b lic :
void i n i t ( ) ;
void push( in t ) ;
in t popO ;
>;
Method in it would be invoked to set up an empty stack by initializ
ing top to —1. Method push would increment top and then store the
value passed in data[ top ]. Method pop would copy the value in
data[ top ], decrement top, and then return the saved value.
7. s.push( 10 ) ;
s_arr [ 8 ] .popO ;
Section 1.3
1. class book {
char t i t l e [ 100 ] ;
char author[ 100 ] ;
long id_number;
public:
void s t o r e _ t it le ( char* ) ;
void store_author( char* ) ;
void store_id_number( long ) ;
>;
3. class person {
p u b lic :
char name[ 100 ] ;
char address[ 100 ] ;
>;
Derive a class book_borrower from book and person and add a flag to
indicate whether the person has borrowed the book.
Section 1.4
1. book* book_array[ 50 ] ;
www.MathSchoolinternational.com
H INTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 503
3. The following code shows one solution in C. The idea is to store pointers
to the various drawing functions in the array.
e tc .
*/
Section 2.1
I. good_jobs jo b l, job2;
3. string s i, s 2 ;
9. Legal
// The statement
//
// return EXIT_SUCCESS;
//
// is explained in Section 2.2.
www.MathSchoolinternational.com
504 HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES
#include <stdio.h>
#include <math.h>
#include <stdlib.h >
int main()
count = 0;
sum = 0.0;
while ( count < max )
if ( scanf( "%f", &x ) != EOF ) {
a [ count++ ] = x;
sum += x;
>
else
break;
if ( count == 0 ) {
p r in t f ( "No numbers read\n" ) ;
return EXIT_SUCCESS;
>
return EXIT_SUCCESS;
>
Section 2.2
3. Portable
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 505
5. Portable
7. Portable
9. x = 5, y = -12
11. x = 4, y = -11
return &a[ i - 1 ] ;
>
The first line would be rewritten as
val = *new_index_C( a, 8 ) ;
*new_index_C( a, 8 ) = -16;
p r in t f( "*/,s\n", s t r .s ) ;
>
17. Function prin t promises not to modify the structure to which fp points;
however, print then passes fp to fp r in t f which does modify the struc
ture to which fp points. The error can be corrected by omitting the
modifier const in p rin t’s header.
Section 2.3
1. 18 4
5. d e le te [ ] s tr;
if ( current == 0 )
return 0;
9. p tr = ftodometer: : miles;
www.MathSchoolinternational.com
506 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
13. p = &odl;
Section 2.4
1. cin » i » x » s tr;
3. The program will go into an infinite loop since the newline will never be
read and discarded.
Section 3.1
1. Both data members and methods are private by default.
3. union Sample {
p riv a te :
int x;
flo a t y;
char c;
p u b lic :
void msg( char* ) ;
>;
5. class Dilemma {
enum Horn { Hornl, Horn2 >;
char h o rn l[ 100 ] ;
char horn2[ 200 ] ;
p u b lic :
int horn_crushed( Horn ) ;
void re s o lv e _p e a c e fu lly ();
>;
7. In the class created with the keyword struct, all datamembers and
methods are public by default. In the class created with thekeyword
class, all data members and methods are private by default.
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 507
13. Yes.
17. A class declaration must end with a semicolon. The correct declaration
is:
class C {
p u b lic :
void w rite ( ) ;
>; // must end in semicolon
19. No.
Section 3.2
1. // return top item without popping
char Stack::view _top()
{
if ( empty( ) )
return EmptyFlag;
else
return items[ top ] ;
>
www.MathSchoolinternational.com
508 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
Section 3.3
I. No.
5. Constructors for the same class must differ in either the number or the
data type(s) of their arguments. C has two constructors that expect a
single char* argument.
7. Yes.
class C {
in t x;
p u b lic :
C( Cft ) ; // ok
>;
13. No.
17. The destructor automatically frees the storage to which p tr points when
ever a C object is destroyed.
19. One.
www.MathSchoolinternational.com
HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES 509
Section 3.4
1. void Z ip C :: shorten()
{
i f ( s t r le n ( p tr ) == MinZip )
return ;
char temp[ BigZip + 1 ] ;
// save o rig in a l
strcpy( temp, code ) ;
d e le te [ ] code;
// shorten
code = new char[ MinZip + 1 ] ;
strncpy( code, temp, MinZip ) ;
code[ MinZip ] = ’ \0’ ;
>
Section 3.5
instead of
www.MathSchoolinternational.com
HINTS AN D SOLUTIONS TO ODD-NUM BERED EXERCISES
class C {
char* strin g;
flo a t flo a te r ;
p u b lic :
in t operator==( const C ) const;
>;
.6
return Complex( re a l += c .r e a l,
imag += c . img ) ;
>
return Complex( re a l =
( re a l * c .r e a l + imag * c.imag ) / abs_sq,
imag =
( imag * c .re a l - re a l * c.imag ) / abs_sq ) ;
}
The const in the parameter list indicates that the the parameter is to be
read only. The const after the parameter list indicates that the object’s
data members (re a l and imag) are to be read only.
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 511
Section 3.7
class C {
Section 3.8
1. #include <stdio.h>
#include <iostream.h>
#include <string.h>
#include <assert.h>
const in t MinZip = 5;
const in t BigZip = 10;
const in t MaxZip = 32;
const in t InitChax = ;
www.MathSchoolinternational.com
HINTS AND SOLUTIONS TO ODD-NUMBERED EXERCISES
class ZipC {
char* code;
p u b lic :
ZipCO;
ZipC( const char* ) ;
ZipC( const unsigned long ) ;
"ZipC O ;
void w rite ( ) { cout « code « endl; }
void expand( const char* ) ;
>;
Z ip C ::ZipCO
www.MathSchoolinternational.com
HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES 513
ZipC: : "ZipCO
{
d e le te [ ] code;
>
Section 3.9
1. The class is C< class Typ > not C. The correct code is
>
www.MathSchoolinternational.com
514 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
"StackO ;
void push( Typ ) ;
Typ popO ;
int empty( ) ;
int f u l l O ;
>;
items[ ++top ] = c ;
>
www.MathSchoolinternational.com
HINTS AND SOLUTIONS TO ODD-NUMBERED EXERCISES 515
Section 4.1
1. String s i; // default
String s2( 1000 ) ; // convert
String s3( "fre d " ) ; //convert
String s4( s3 ) ; // copy
class C {
chax* name;
p u b lic:
C( chax* n )
■C
name = new chax[ s tr le n ( n ) + 1 ] ;
strcpy( name, n ) ;
>
>;
C c l ( "bar" ) ;
C c2( c l ) ;
puts( s tr ) ;
putc( ’ \n’ ) ;
return s tr le n ( s tr ) ;
}
www.MathSchoolinternational.com
516 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
fp u ts( s tr , o u tfile ) ;
fp utc( ’ W , o u t file ) ;
return s tr le n ( s tr ) ;
>
return len = s tr le n ( s tr ) ;
>
i f ( !i n f i l e )
return ReadFail;
else {
fg e t s ( s tr , MaxStrLen, i n f i l e ) ;
return len = s tr le n ( s tr ) ;
>
>
return strcmp( s tr , s .s t r ) != 0;
>
>;
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 517
( a [ j ] . *compare_op ) ( a [ next ] ) ;
17. Data member s tr points to a char vector, i.e., to a sequence of char cells
rather than to a single, standalone char cell. Therefore, the storage is
freed with d elete [ ] rather than with delete.
23. The const in the parameter list means that the String argument is read
only. The const to the right of the parameter list means that the object
whose operator+ method is invoked is read only.
Section 4.2
1. String s i; // defau lt
String s2 = s i; // copy
String s3; // defau lt
s3 = s i; // assignment
String s4( "g lo ry days by bs" ) ; // convert
String s5; // defau lt
s5 = s4; // assignment
String s6 = s5; // copy
String s7 = S trin g ( "judy blue eyes" ) ; // convert
3. A String vector (i.e., contiguous Strings allocated through the new op
erator) cannot be given initial values. All Strings in the vector are
initialized through the default constructor.
5. Yes.
www.MathSchoolinternational.com
518 HINTS AND SOLUTIONS TO ODD-NUMBERED EXERCISES
we want s i . s tr and s2. s tr to point to different cells that hold the same
chars. The compiler’s assignment operator would result in the two s tr
data members pointing to the same vector.
S trin g s l ( "jean" ) ;
s i = s i;
11. It is hard to imagine such a situation. The rule of thumb for writing your
own copy constructor and assignment operator is the same: You should
do so if the data members include a pointer.
13. No. Call by reference involves a pointer to an object, not a copy of the
object. Therefore, the copy constructor is not needed in call by reference.
15. Even if the compiler provided a default overload of op erator! =, the over
loaded operator would use member-by-member tests for equality. In a
code slice such as
Section 4.3
1. class Cl {
>;
class C2 ■[
frien d Cl;
www.MathSchoolinternational.com
HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES 519
class C3 {
frien d C2;
>;
3. No.
Section 4.4
1. Yes.
postorderAux( root ) ;
}
as its body.
9. The BST method addNodeAux accesses the Node data members val, lc,
and rc.
www.MathSchoolinternational.com
520 HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES
Section 4.5
if ( n -> emptyO )
return;
nodeStack[ nextNode++ ] = n;
stackNodesAux( n -> lc ) ;
stackNodesAux( n -> rc ) ;
>
3. IterBST methods need to access root and count in BST and lc and rc
in Node.
5. Neither Node nor BST methods access any IterBST data members or meth
ods.
Section 4.6
3. A s ta tic data member must not be defined inside a block. In this ex
ample, X: :sX is defined inside main’s body.
5. A s ta tic data member must be defined without the keyword sta tic.
7. Yes.
II. No. A destructor belongs to a specific object in a class, not to the class
as a whole.
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 521
Section 5.1
1. B
Dl D2 D3
/
DD1
Dl D2
DD 1
/
/
DDD1
/
DDDD1
DDDDD1
/
B has directly derived classes D l and D2. B has in d irectly derived classes
DD1, DDD1, DDDD1, and DDDDD1.
9. T h e error is
y = x;
11. T h e error is
p tr -> f l = 3.14;
www.MathSchoolinternational.com
522 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
13. class B {
class D : public B {
>;
15. »
t
Q
t
p
17. A protected data member or method is accessible only within a class hi
erarchy, whereas a public data member or method is globally accessible.
Accordingly, a protected data member or method exemplifies informa
tion hiding, a guiding principle of object-oriented programming.
b l.x = 8 ;
23. numl = n l;
num2 = n2;
num3 = n3;
a.x = 1;
www.MathSchoolinternational.com
HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES 523
Section 5.2
3. #include <iostream.h>
class A {
in t dummy;
pu b lic:
A () { cout « "A ::A " « endl; }
>;
class B : public A {
in t dummy;
p u b lic:
B() : A () { cout « "B::B" « endl; >
>;
class C : public B {
in t dummy;
p u b lic:
CO : BO { cout « "C::C" « endl; >
>;
A a l;
B b l, b2;
C c l, c2, c3;
5. No.
D d; // D::D fir e s
www.MathSchoolinternational.com
524 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
S ection 5.3
1. Desktop is a derived class with respect to Computer but a base class with
respect to WS and PC.
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 525
Section 5.4
I. A!
3. Z!
p tr -> f ( ) ;
ptr -> Z : : f ( ) ;
7. Compile-time binding.
class Abstract {
v irtu a l void f ( ) = 0;
>;
>;
www.MathSchoolinternational.com
526 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
15. Yes.
Section 5.5
if ( n -> em ptyO )
re tu rn ;
p o s to rd erA u x ( n -> l c );
p osto rd erA u x ( n -> r c ) ;
n -> w r i t e ( );
>
9. The PreBST default and copy constructors simply invoke the BST default
and copy constructors to do their work. Therefore, the PreBST versions
have empty function bodies.
II. In the original version, the programmer determines the type of tree traver
sal (e.g., inorder) by eocplicitly invoking the inorder method on a BST. In
the revised version, the object determines the sort of traversal appropri
ate to it. For example, a preorder traversal is appropriate to a PreBST
object. The v irtu a l method traverse is invoked on any BST object
because the object itself then determines which version of the v irtu a l
function is appropriate to it. This is polymorphism at work. The original
version has no polymorphism.
Section 5.6
1. X::X
Y: :Y
X: :X
Y: :Y
Z: :Z
Z: :~Z
Y: :~Y
X: : ~X
www.MathSchoolinternational.com
H INTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 527
Y: : ~Y
X: : “ X
3. Z () and ~Z().
5.No, and a derived class destructor typically does not invoke a base class
destructor even if one exists.
class A {
in t* ptrA;
p u b lic:
A () { ptrA = new i n t [ 1000 ] ; }
>;
class B : public A {
in t* ptrB;
p u b lic:
B () { ptrB = new i n t [ 1000 ] ; }
>;
Section 5.7
3. R has four data members: x and y inherited from P, and a and b inherited
from Q.
www.MathSchoolinternational.com
528 HINTS AND SOLUTIONS TO ODD-NUMBERED EXERCISES
Section 6.1
5. class C {
in t x;
in t y;
p u b lic :
// sample overload of && as frien d
frien d in t operator&&( C a l, C a2 )
i f ( a l <= 0 I I a2 <= 0 )
return 0;
return al == a2;
}
>;
7. class C {
in t x;
in t y;
p u b lic :
// sample overload of + as frien d
frien d in t operator+( C a l, C a2 )
return a l * a l + a2 * a2;
>
II. Yes, with the exception of the memory management operators new,
d elete, and d e le te [ ].
13. The s iz e o f operator already works on any data type, built-in or user-
defined. It is hard to imagine a need to overload such a basic operator in
the language.
15. class C {
in t x;
in t y;
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 529
p u b lic:
// sample overload of ,
frien d in t o p era to r,( C a l, C a2 )
{
return a l . x ;
}
>;
Section 6.2
1. void Matrix::dump()
{
fo r ( in t i = 0; i < side * side; i++ )
cout « c e lls [ i ] « endl;
>
// copy
fo r ( in t i = 0; i < side * side; i++ )
c e l l s [ i ] = m .c e lls [ i ] ;
}
Matrix m;
m[ 3, 4 ] ; // * * * * * ERROR: [ ] is unary
Section 6.3
www.MathSchoolinternational.com
530 HINTS AND SOLUTIONS TO ODD-NUMBERED EXERCISES
default constructor already handles this task. Methods add, write, and
match must be adjusted to handle String rather than char* data mem
bers.
5. The first pair of parentheses identifies the operator, i.e., operator ( ) . The
second pair is the argument list, which is empty.
7. The function call operator ( ) may take zero or more arguments, which
makes it very flexible.
int i = 0;
while ( i < count )
i f ( e n trie s [ i ] .match( w ) )
// any room?
i f ( s tr le n ( e n trie s [ i ] .def +
s tr le n ( d ) < MaxDef ) ) {
s trc a t( e n trie s [ i ]. d e f , d ) ;
break;
>
else
i++;
>
Section 6.4
1. A type conversion operator must not have a return value in its definition.
3. The first const signals that code outside the String class should not
modify the storage to which s tr points. The second const signals that
the type conversion operator does not change this storage.
5. The compiler determines from context the type of value required for an
operation. For instance, the i f condition
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUM BERED EXERCISES 531
7. The compiler rather than the programmer typically invokes a type conver
sion operator; and, in writing a type conversion operator, the programmer
may not have anticipated all contexts in which compiler will invoke the
operator. This can lead to subtle bugs.
Section 6.5
1. F ile R e f’s overload of operator= and its type conversion operator (from
a F ileR ef to a char) both reference F ile ’s fp t r p riva te data member.
F ile f ( "out.dat" ) ;
f [ 0 ] = ’Z’ ;
f [ 0 ] = ...;
is now legal for Files. The user does not need to understand how the
assignment operator is working (e.g., that it does an fseek into a F ile ),
or even whether the assignment operator is built-in or overloaded. Ac
cordingly, these details are hidden from the user within class FileR ef.
7. The overloaded assignment operator comes into play during writes but
not during reads. During reads, the type conversion operator (F ileR ef
to char) comes into play.
9. In a an expression such as
www.MathSchoolinternational.com
532 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
Section 6.6
5. No.
Section 7.1
Section 7.2
3. The not operator ( ! ) is overloaded so that the value of the expression ! cin
is converted to a pointer. (If the pointer value is NULL the expression is
false; otherwise, the expression is true.)
7. cout.s e t f( io s : : showpoint );
15. 0X42$$0X42$$0X420X42
Section 7.3
1. cin
3. 50
5. e
7. e
www.MathSchoolinternational.com
HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES 533
Section 7.4
return i s . s e t f ( ios::skipw s ) ;
}
www.MathSchoolinternational.com
534 HINTS AN D SOLUTIONS TO ODD-NUMBERED EXERCISES
Section 7.5
1. ifstream fin ;
fin .o p en ( "weather.in" ) ;
5. It is illegal to have two definitions of the same variable in the same scope.
7. #include <fstream.h>
#include <stdlib.h>
char c;
ifstream fin ;
return EXIT_SUCCESS;
>
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 535
Section 7.7
1. char b u f f [ 100 ] ;
int i = 6;
ostrstream( b u ff, sizeof ( bu ff ) ) ;
sout « "Santa Claus Conquers " « i « " Martians" « ends;
cout « bu ff « endl;
Section 7.8
1. #include <fstream.h>
#include <strstream.h>
#include <std lib.h >
int mainO
char b u f f [ 10000 ] ;
ifstream f i n ( "data.in " ) ;
ostrstream sout( b u ff, sizeof ( bu ff ) ) ;
copy( f i n , sout ) ;
return EXIT_SUCCESS;
>
3. #include <fstream.h>
#include <std lib.h >
int mainO
{
ifstream f i n ( "d ata.in " ) ;
return EXIT_SUCCESS;
>
www.MathSchoolinternational.com
536 HINTS AND SOLUTIONS TO ODD-NUMBERED EXERCISES
in t i ;
f l = in .u n setf( ios::skipw s ) ;
in t c, count = 0, i , numb;
while ( in » c )
i f ( c == J\ t ’ ) {
numb = tabsize - ( count */, tabsize ) ;
fo r ( i = 0; i < numb; i++ )
out « ’ ’ ;
count += numb;
>
else {
count++;
out « c;
i f ( c == ’ \n’ )
count = 0;
>
in . f la g s ( f l ) ;
>
Section 7.9
Section 8.1
www.MathSchoolinternational.com
HINTS A N D SOLUTIONS TO ODD-NUMBERED EXERCISES 537
Section 8.2
ptr -> p r i n t _ t i t l e ( ) ;
ptr -> p r i n t _ l e v e l ( ) ;
is executed.
ptr -> p r i n t _ t i t l e ( ) ;
is executed.
5. True
7. True
9. False
II. True
13. True
15. False
17. False
19. False
21. False
23. False
25. False
27. False
Section 8.3
www.MathSchoolinternational.com
www.MathSchoolinternational.com
Index
539
www.MathSchoolinternational.com
IN D E X
www.MathSchoolinternational.com
IN D EX 541
www.MathSchoolinternational.com
IN D E X
www.MathSchoolinternational.com
1
INDEX 543
www.MathSchoolinternational.com
544 IN D E X
www.MathSchoolinternational.com
IND EX 545
www.MathSchoolinternational.com
546 IN D E X
www.MathSchoolinternational.com
IN D EX 547
www.MathSchoolinternational.com
www.MathSchoolinternational.com
PRENTICE HALL
Englewood Cliffs, NJ 07632 ISBN 0 -0 2 -3 6 0 6 8 2 -7
780023 606823
www.MathSchoolinternational.com