Search for notes by fellow students, in your own course and all over the country.

Browse our notes for titles which look like what you need, you can preview any of the notes via a sample of the contents. After you're happy these are the notes you're after simply pop them into your shopping cart.

My Basket

You have nothing in your shopping cart yet.

Title: FULL CONCEPT FOR C++ PROGRAMMING LANGUAGE
Description: Fundamentals 1 Development and Properties of C++ 2 Object-Oriented Programming 4 Developing a C++ Program 6 A Beginner’s C++ Program 8 Structure of Simple C++ Programs 10 Exercises 12 Solutions 14 Chapter 2 Fundamental Types, Constants, and Variables 15 Fundamental Types 16 Constants 22 Escape Sequences 26 Names 28 Variables 30 The Keywords const and volatile 32 Exercises 34 Solutions 36 contents Chapter 3 Using Functions and Classes 39 Declaring Functions 40 Function Calls 42 Type void for Functions 44 Header Files 46 Standard Header Files 48 Using Standard Classes 50 Exercises 52 Solutions 54 Chapter 4 Input and Output with Streams 57 Streams 58 Formatting and Manipulators 60 Formatted Output of Integers 62 Formatted Output of Floating-Point Numbers 64 Output in Fields 66 Output of Characters, Strings, and Boolean Values 68 Formatted Input 70 Formatted Input of Numbers 72 Unformatted Input/Output 74 Exercises 76 Solutions 78 Chapter 5 Operators for Fundamental Types 81 Binary Arithmetic Operators 82 Unary Arithmetic Operators 84 Assignments 86 Relational Operators 88 Logical Operators 90 Exercises 92 Solutions 94 Chapter 6 Control Flow 95 The while Statement 96 The for Statement 98 The do-while Statement 102 Selections with if-else 104 Else-if Chains 106 Conditional Expressions 108 Selecting with switch 110 Jumps with break, continue, and goto 112 Exercises 114 Solutions 116 xii ■ CONTENTS Chapter 7 Symbolic Constants and Macros 119 Macros 120 Macros with Parameters 122 Working with the #define Directive 124 Conditional Inclusion 126 Standard Macros for Character Manipulation 128 Redirecting Standard Input and Output 130 Exercises 132 Solutions 134 Chapter 8 Converting Arithmetic Types 139 Implicit Type Conversions 140 Performing Usual Arithmetic Type Conversions 142 Implicit Type Conversions in Assignments 144 More Type Conversions 146 Exercises 148 Solutions 150 Chapter 9 The Standard Class string 153 Defining and Assigning Strings 154 Concatenating Strings 156 Comparing Strings 158 Inserting and Erasing in Strings 160 Searching and Replacing in Strings 162 Accessing Characters in Strings 164 Exercises 166 Solutions 168 Chapter 10 Functions 171 Significance of Functions in C++ 172 Defining Functions 174 Return Value of Functions 176 Passing Arguments 178 Inline Functions 180 Default Arguments 182 Overloading Functions 184 Recursive Functions 186 Exercises 188 Solutions 191 Chapter 11 Storage Classes and Namespaces 197 Storage Classes of Objects 198 The Storage Class extern 200 CONTENTS ■ xiii The Storage Class static 202 The Specifiers auto and register 204 The Storage Classes of Functions 206 Namespaces 208 The Keyword using 210 Exercises 212 Solutions 216 Chapter 12 References and Pointers 221 Defining References 222 References as Parameters 224 References as Return Value 226 Expressions with Reference Type 228 Defining Pointers 230 The Indirection Operator 232 Pointers as Parameters 234 Exercises 236 Solutions 238 Chapter 13 Defining Classes 243 The Class Concept 244 Defining Classes 246 Defining Methods 248 Defining Objects 250 Using Objects 252 Pointers to Objects 254 Structs 256 Unions 258 Exercise 260 Solution 262 Chapter 14 Methods 265 Constructors 266 Constructor Calls 268 Destructors 270 Inline Methods 272 Access Methods 274 const Objects and Methods 276 Standard Methods 278 this Pointer 280 Passing Objects as Arguments 282 Returning Objects 284 Exercises 286 Solutions 290 xiv ■ CONTENTS Chapter 15 Member Objects and Static Members 297 Member Objects 298 Member Initializers 300 Constant Member Objects 302 Static Data Members 304 Accessing Static Data Members 306 Enumeration 308 Exercises 310 Solutions 314 Chapter 16 Arrays 321 Defining Arrays 322 Initializing Arrays 324 Arrays 326 Class Arrays 328 Multidimensional Arrays 330 Member Arrays 332 Exercises 334 Solutions 338 Chapter 17 Arrays and Pointers 349 Arrays and Pointers (1) 350 Arrays and Pointers (2) 352 Pointer Arithmetic 354 Arrays as Arguments 356 Pointer Versions of Functions 358 Read-Only Pointers 360 Returning Pointers 362 Arrays of Pointers 364 Command Line Arguments 366 Exercises 368 Solutions 372 Chapter 18 Fundamentals of File Input and Output 379 Files 380 File Streams 382 Creating File Streams 384 Open Modes 386 Closing Files 388 Reading and Writing Blocks 390 Object Persistence 392 Exercises 394 Solutions 398 CONTENTS ■ xv Chapter 19 Overloading Operators 411 Generals 412 Operator Functions (1) 414 Operator Functions (2) 416 Using Overloaded Operators 418 Global Operator Functions 420 Friend Functions 422 Friend Classes 424 Overloading Subscript Operators 426 Overloading Shift-Operators for I/O 428 Exercises 430 Solutions 432 Chapter 20 Type Conversion for Classes 441 Conversion Constructors 442 Conversion Functions 444 Ambiguities of Type Conversions 446 Exercise 448 Solution 450 Chapter 21 Dynamic Memory Allocation 453 The Operator new 454 The Operator delete 456 Dynamic Storage Allocation for Classes 458 Dynamic Storage Allocation for Arrays 460 Application: Linked Lists 462 Representing a Linked List 464 Exercises 466 Solutions 468 Chapter 22 Dynamic Members 477 Members of Varying Length 478 Classes with a Dynamic Member 480 Creating and Destroying Objects 482 Implementing Methods 484 Copy Constructor 486 Assignment 488 Exercises 490 Solutions 492 Chapter 23 Inheritance 499 Concept of Inheritance 500 Derived Classes 502 xvi ■ CONTENTS Members of Derived Classes 504 Member Access 506 Redefining Members 508 Constructing and Destroying Derived Classes 510 Objects of Derived Classes 512 Protected Members 514 Exercises 516 Solutions 520 Chapter 24 Type Conversion in Class Hierarchies 529 Converting to Base Classes 530 Type Conversions and Assignments 532 Converting References and Pointers 534 Explicit Type Conversions 536 Exercises 538 Solutions 540 Chapter 25 Polymorphism 543 Concept of Polymorphism 544 Virtual Methods 546 Destroying Dynamically Allocated Objects 548 Virtual Method Table 550 Dynamic Casts 552 Exercises 554 Solutions 558 Chapter 26 Abstract Classes 565 Pure Virtual Methods 566 Abstract and Concrete Classes 568 Pointers and References to Abstract Classes 570 Virtual Assignment 572 Application: Inhomogeneous Lists 574 Implementing an Inhomogeneous List 576 Exercises 578 Solutions 580 Chapter 27 Multiple Inheritance 587 Multiply-Derived Classes 588 Multiple Indirect Base Classes 590 Virtual Base Classes 592 Constructor Calls 594 Initializing Virtual Base Classes 596 Exercises 598 Solutions 602 CONTENTS ■ xvii Chapter 28 Exception Handling 607 Traditional Error Handling 608 Exception Handling 610 Exception Handlers 612 Throwing and Catching Exceptions 614 Nesting Exception Handling 616 Defining Your Own Error Classes 618 Standard Exception Classes 620 Exercises 622 Solutions 626 Chapter 29 More About Files 637 Opening a File for Random Access 638 Positioning for Random Access 640 File State 644 Exception Handling for Files 646 Persistence of Polymorphic Objects 648 Application: Index Files 652 Implementing an Index File 654 Exercises 656 Solutions 660 Chapter 30 More About Pointers 681 Pointer to Pointers 682 Variable Number of Arguments 684 Pointers to Functions 688 Complex Declarations 690 Defining Typenames 692 Application: Dynamic Matrices 694 Exercises 696 Solutions 698 Chapter 31 Manipulating Bits 705 Bitwise Operators 706 Bitwise Shift Operators 708 Bit Masks 710 Using Bit Masks 712 Bit-Fields 714 Exercises 716 Solutions 718 Chapter 32 Templates 721 Function and Class Templates 722 Defining Templates 724 xviii ■ CONTENTS Template Instantiation 726 Template Parameters 728 Template Arguments 730 Specialization 732 Default Arguments of Templates 734 Explicit Instantiation 736 Exercises 738 Solutions 742 Chapter 33 Containers 749 Container Types 750 Sequences 752 Iterators 754 Declaring Sequences 756 Inserting in Sequences 758 Accessing Objects 760 Length and Capacity 762 Deleting in Sequences 764 List Operations 766 Associative Containers 768 Sets and Multisets 770 Maps and Multimaps 772 Bitsets 774 Exercise 778 Solution 780

Document Preview

Extracts from the notes are below, to see the PDF you'll receive please use the links above


A Complete Guide to
Programming in C++

Ulla Kirch-Prinz
Peter Prinz

JONES AND BARTLETT PUBLISHERS

A Complete Guide to
Programming in C++
Ulla Kirch-Prinz
Peter Prinz

World Headquarters
Jones and Bartlett Publishers
40 Tall Pine Drive
Sudbury, MA 01776
978-443-5000
info@jbpub
...
jbpub
...

All rights reserved
...

Cover Image: Stones on shore-line and yellow leaf, Bjorkliden, Sweden, by Peter Lilja
Library of Congress Cataloging-in-Publication Data
Prinz, Peter
...
English]
A complete guide to programming in C++ / Peter Prinz, Ulla Kirch-Prinz; translated by Ian Travis
...
cm
...
C++ (Computer program language) I
...
II
...

QA76
...
C153 P73713 2001
005
...
Jones, Jr
...
P
...
Hauck
V
...
, Design and Production: Anne Spencer
V
...
, Manufacturing and Inventory Control: Therese Bräuer
Editor-in-Chief: Michael Stranz
Development and Product Manager: Amy Rose
Marketing Manager: Nathan Schultz
Production Assistant: Tara McCormick
Cover Design: Night & Day Design
Composition: Northeast Compositors
Text Design: Mary McKeon
Printing and Binding: Courier Westford
Cover printing: John Pow Company, Inc
...
11 on a Macintosh G4
...
The first printing was printed on 50 lb
...

Printed in the United States of America
05 04 03 02 01

10 9 8 7 6 5 4 3 2 1

Dedicated to our children, Vivi and Jeany

This page intentionally left blank

preface

This book was written for readers interested in learning the C++ programming
language from scratch, and for both novice and advanced C++ programmers
wishing to enhance their knowledge of C++
...

The C++ language definition is based on the American National Standards Institute ANSI Standard X3J16
...
The C++ programming language is thus platform-independent
in the main with a majority of C++ compilers providing ANSI support
...
Visit the Jones and Bartlett web site
at www
...
com for a listing of compilers available for this text
...
The order in which these
elements are discussed reflects our goal of helping the reader to create useful
programs at every step of the way
...
This type of visual representation offered by each
spread will provide students and professionals with an unmatched guide throughout the
text
...
In addition, filter programs and case studies introduce the reader to a
wide range of application scenarios
...
Thus, each chapter includes exercises followed by sample solutions, allowing the reader to test and enhance his or her performance and understanding
of C++
...

In order to test and expand your acquired knowledge, you can download sample programs and solutions to the exercises at:
http://completecpp
...
com

Content Organization
Chapter 1 gives a thorough description of the fundamental characteristics of the objectoriented C++ programming language
...
Many examples are provided to
help enforce these steps and to demonstrate the basic structure of a C++ program
...
Integral types and constants, fundamental types, and Boolean constants
are just a few of the topics discussed
...
This chapter also
teaches students to use standard classes, including standard header files
...

Chapter 4 explains the use of streams for input and output, with a focus on formatting
techniques
...

Chapter 5 introduces operators needed for calculations and selections
...

Chapter 6 describes the statements needed to control the flow of a program
...

Chapter 7 provides a thorough introduction to the definition of symbolic constants
and macros, illustrating their significance and use
...

Chapter 8 introduces implicit type conversions, which are performed in C++ whenever different arithmetic types occur in expressions
...


PREFACE



vii

Chapter 9 takes an in-depth look at the standard class string, which is used to represent strings
...
These include inserting and erasing, searching and replacing, comparing, and concatenating strings
...
The basic rules are covered,
as are passing arguments, the definition of inline functions, overloading functions and
default arguments, and the principle of recursion
...

Object lifetime and scope are discussed, along with global, static, and auto objects
...

Chapter 12 explains how to define references and pointers and how to use them as
parameters and/or return values of functions
...

Chapter 13 provides a complete description of how classes are defined and how
instances of classes, or objects, are used
...

Chapter 14 describes how constructors and destructors are defined to create and
destroy objects
...
Furthermore, the chapter explains the pointer this, which is available for all methods, and what you need to pay attention to when passing objects as arguments or returning objects
...
In addition, this chapter describes constant members and enumerated types
...
Of particular interest are one-dimensional and multidimensional arrays, C strings, and class arrays
...
This includes
pointer arithmetic, pointer versions of functions, pointers as return values and read-only
pointers, and pointer arrays
...

Chapter 18 explains sequential file access using file streams
...

Chapter 19 provides a complete description of the various uses of overloaded operators
...
In addition,
the concept of friend functions, which is introduced in this context, is particularly
important for overloading operators
...

Chapter 20 discusses how implicit type conversion occurs in C++ when an expression
cannot be compiled directly but can be compiled after applying a conversion rule
...
Finally, the chapter discusses
ambiguity that occurs due to type conversion and how to avoid it
...
Dynamic memory allocation is an important factor in many C++ programs, and the following chapters contain several case studies to
help students review the subject
...
These include your own copy constructor definition and overloading
the assignment operator
...

Chapter 23 provides a thorough description of how derived classes can be constructed
from existing classes by inheritance
...

Chapter 24 discusses implicit type conversion within class hierarchies, which occurs
in the context of assignments and function calls
...

Chapter 25 gives a complete explanation of how to develop and manage polymorphic
classes
...

Chapter 26 describes how defining pure virtual methods can create abstract classes
and how you can use abstract classes at a polymorphic interface for derived classes
...

Chapter 27 describes how new classes are created by multiple inheritance and
explains their uses
...

Chapter 28 explains how a C++ program uses error-handling techniques to resolve
error conditions
...
In
addition, the use of standard exception classes is discussed
...
Exception handling for files is discussed as well
...
The applications introduced in this chapter include simple index files and hash
tables
...
These
include pointers to pointers, functions with a variable number of arguments, and pointers
to functions
...

Chapter 31 describes bitwise operators and how to use bit masks
...
Finally, the definition of bit-fields is introduced
...
In addition,
special options, such as default arguments, specialization, and explicit instantiation, are

PREFACE



ix

discussed
...
Thus, templates are a powerful tool for
automating program code generation
...
These include sequences, such as lists and
double ended queues; container adapters, such as stacks, queues, and priority queues;
associative containers, such as sets and maps; and bitsets
...


Additional Features
Chapter Goals A concise chapter introduction, which contains a description of the
chapter’s contents, is presented at the beginning of each chapter
...


Chapter Exercises Each chapter contains exercises, including programming problems,
designed to test students’ knowledge and understanding of the main ideas
...
Solutions are included to allow
students to check their work immediately and correct any possible mistakes
...


Notes This feature provides students with helpful tips and information useful to learning
C++
...


Hints These are informative suggestions for easier programming
...


Acknowledgements
Our thanks go out to everyone who helped produce this book, particularly to
Ian Travis, for his valuable contributions to the development of this book
...

Michael Stranz and Amy Rose at Jones and Bartlett Publishers, who managed the publishing agreement and the production process so smoothly
...
In addition, you will be introduced
to the steps necessary for creating a fully functional C++ program
...


1

2



CHAPTER 1

FUNDAMENTALS



DEVELOPMENT AND PROPERTIES OF C++

Characteristics

C++

C
-universal
-efficient
-close to the machine
-portable

OOP
-data abstraction
-data hiding
-inheritance
-polymorphism

Extensions
-exception handling
-templates

DEVELOPMENT AND PROPERTIES OF C++



3

ᮀ Historical Perspective
The C++ programming language was created by Bjarne Stroustrup and his team at Bell
Laboratories (AT&T, USA) to help implement simulation projects in an object-oriented and efficient way
...
As the name C++ implies, C++ was derived from the C
programming language: ++ is the increment operator in C
...
The aim was to have as many
compiler vendors and software developers as possible agree on a unified description of
the language in order to avoid the confusion caused by a variety of dialects
...


ᮀ Characteristics of C++
C++ is not a purely object-oriented language but a hybrid that contains the functionality
of the C programming language
...


The large quantities of existing C source code can also be used in C++ programs
...


Various language elements were added to C++, such as references, templates, and exception handling
...


4



CHAPTER 1

FUNDAMENTALS



OBJECT-ORIENTED PROGRAMMING

Traditional concept

function1
data1
function2
data2
function3

Object-oriented concept
object1

object2

Properties

Properties

Capacities

Capacities

OBJECT-ORIENTED PROGRAMMING



5

ᮀ Traditional Procedural Programming
In traditional, procedural programming, data and functions (subroutines, procedures) are
kept separate from the data they process
...
g
...


Both of these points can lead to errors and neither support low program maintenance
requirements
...
A program designed to maintain bank
accounts would work with data such as balances, credit limits, transfers, interest calculations, and so on
...

OOP objects combine data (properties) and functions (capacities)
...
Objects communicate by sending each other “messages,” which in turn activate another object’s capacities
...
More
specifically, an object can reject erroneous access attempts
easy re-use: objects maintain themselves and can therefore be used as building
blocks for other programs
low maintenance requirement: an object type can modify its own internal data
representation without requiring changes to the application
...
First, a text editor is used to save the C++ program in a text file
...
In larger projects the programmer will normally use modular programming
...

2
...
If everything works as
planned, an object file made up of machine code is created
...

3
...
These further modules contain functions from standard libraries or
parts of the program that have been compiled previously
...
Although
the file extension depends on the compiler you use, the most commonly found file extensions are
...
cc
...
Header files are text files containing information needed by various source files, for example, type definitions or declarations of variables and functions
...
h, but they may not have any file extension
...

Modern compilers normally offer an integrated software development environment, which
combines the steps mentioned previously into a single task
...
Moreover, additional tools, such as a debugger, can be launched
...
Additional error
messages may be shown if the compiler attempts to continue despite having found an error
...


In addition to error messages, the compiler will also issue warnings
...


8



CHAPTER 1

FUNDAMENTALS



A BEGINNER’S C++ PROGRAM

Sample program
#include
using namespace std;
int main()
{
cout << "Enjoy yourself with C++!"
return 0;
}

<< endl;

Screen output
Enjoy yourself with C++!

Structure of function main()

Function name
Type of function
Beginning of
function

int main()
{

...

What the program does
What the program does
(satements)
(statements)


...

End of function

}

Function block

A BEGINNER’S C++ PROGRAM



9

A C++ program is made up of objects with their accompanying member functions and
global functions, which do not belong to any single particular class
...
You can create functions yourself or use ready-made functions from the standard library
...

The short programming example on the opposite page demonstrates two of the most
important elements of a C++ program
...

The first line begins with the number symbol, #, which indicates that the line is
intended for the preprocessor
...
You can type
#include

to have the preprocessor copy the quoted file to this position in the source code
...
The header
file iostream comprises conventions for input and output streams
...

Predefined names in C++ are to be found in the std (standard) namespace
...

Program execution begins with the first instruction in function main(), and this is
why each C++ program must have a main function
...
Apart from the fact that the name cannot be changed, this
function’s structure is not different from that of any other C++ function
...
The first statement
cout << "Enjoy yourself with C++!" << endl;

outputs the text string Enjoy yourself with C++! on the screen
...

The two less-than symbols, <<, indicate that characters are being “pushed” to the output stream
...
The statement
return 0;

terminates the function main() and also the program, returning a value of 0 as an exit
code to the calling program
...

Note that statements are followed by a semicolon
...


10



CHAPTER 1

FUNDAMENTALS



STRUCTURE OF SIMPLE C++ PROGRAMS

A C++ program with several functions
/******************************************************
A program with some functions and comments
******************************************************/
#include
using namespace std;
void line(), message();

// Prototypes

int main()
{
cout << "Hello! The program starts in main()
...
" << endl;
return 0;
}
void line()
// To draw a line
...

{
cout << "In function message()
...

----------------------------------In function message()
...


STRUCTURE OF SIMPLE C++ PROGRAMS



11

The example on the opposite page shows the structure of a C++ program containing
multiple functions
...
For
example, you could define the function message() first, followed by the function
line(), and finally the main() function
...
In other words, main() calls functions that have yet to be
defined
...

This example also introduces comments
...
*/ or starting with // are interpreted as comments
...
Comments that cover several lines are useful when troubleshooting, as you can use them to mask complete sections of your program
...

As to the layout of source files, the compiler parses each source file sequentially,
breaking the contents down into tokens, such as function names and operators
...
The order of the source code is important but it is not important
to adhere to a specific layout, such as organizing your code in rows and columns
...
"
endl;}

<<

might be difficult to read, but it is a correct definition of the function message()
...
The number sign, #, at the beginning of a line can be preceded only by a
space or a tab character
...
In addition,
make generous use of comments
...


Exercise 2
The following program contains several errors:
*/ Now you should not forget your glasses //
#include
int main
{
cout << "If this text",
cout >> " appears on your display, ";
cout << " endl;"
cout << 'you can pat yourself on '
<< " the back!" << endl
...


Exercise 3
What does the C++ program on the opposite page output on screen?



13



CHAPTER 1



solutions

14

FUNDAMENTALS

SOLUTIONS

Exercise 1
// Let's go !
#include
using namespace std;
int main()
{
cout <<
cout <<
cout <<
cout <<

"
"
"
"

Oh what " <<
a happy day!
Oh yes, " <<
what a happy

endl;
" << endl;
endl;
day! " << endl;

return 0;
}

Exercise 2
The corrected places are underlined
...


15

16



CHAPTER 2

FUNDAMENTAL TYPES, CONSTANTS, AND VARIABLES



FUNDAMENTAL TYPES

Overview*

For boolean values

bool

char
For characters

wchar_t

short

For integers

int

long

float

For floating-point
values

double

long double

* without type void, which will be introduced later
...
Since a computer uses different methods for processing
and saving data, the data type must be known
...
the internal representation of the data, and
2
...

A number such as -1000 can be stored in either 2 or 4 bytes
...
Moreover, the memory content, that is the bit sequence being read, must be
interpreted correctly as a signed integer
...
) are
based
...
C++ uses the bool type to represent boolean values
...


ᮀ The char and wchar_t Types
These types are used for saving character codes
...
The letter A is represented by code 65, for example
...
When displaying characters on
screen, the applicable character codes are transmitted and the “receiver,” that is the
screen, is responsible for correctly interpreting the codes
...
This 7-bit code contains definitions for 32 control characters
(codes 0 – 31) and 96 printable characters (codes 32 – 127)
...
This
amount of storage is sufficient for extended character sets, for example, the ANSI character set that contains the ASCII codes and additional characters such as German
umlauts
...
Unicode is a 16-bit code also used in
Windows NT and containing codes for approximately 35,000 characters in 24 languages
...

4 byte

Range of Values (decimal)
— to +127 or 0 to 255
128
0 to 255
— to +127
128

32768 to +32767 resp
...


0 to 65535 resp
...


int main()
{
cout << "Range of types int and unsigned int"
<< endl << endl;
cout << "Type
Minimum
Maximum"
<< endl
<< "--------------------------------------------"
<< endl;
cout << "int

" <<
<<

INT_MIN << "
INT_MAX << endl;

"

cout << "unsigned int

" << "
0
<< UINT_MAX << endl;

"

return 0;
}

FUNDAMENTAL TYPES (CONTINUED)



19

ᮀ Integral Types
The types short, int, and long are available for operations with integers
...
The table on the opposite page shows the
integer types, which are also referred to as integral types, with their typical storage
requirements and ranges of values
...
For 16-bit computers, int is thus equivalent to short, whereas
for 32-bit computers int will be equivalent to long
...
This means you can perform calculations with variables belonging to the char or wchar_t types in exactly the same
way as with int type variables
...
The
range of values is thus –128 to +127 or from 0 to 255, depending on whether the compiler interprets the char type as signed or unsigned
...

The wchar_t type is a further integral type and is normally defined as unsigned
short
...
However, integral types can be preceded by the keyword
unsigned
...
The keyword
unsigned can be used as an abbreviation for unsigned int
...
Since this is merely a convention and not mandatory, the signed keyword is available
...


NOTE
In ANSI C++ the size of integer types is not preset
...


The current value ranges are available in the climits header file
...
The program on the opposite page outputs the
value of these constants for the int and unsigned int types
...
4E+38

1
...
7E+308

2
...
1E+4932

3
...
The table above makes use of this representation
...
e
...


FUNDAMENTAL TYPES (CONTINUED)



21

ᮀ Floating-Point Types
Numbers with a fraction part are indicated by a decimal point in C++ and are referred to
as floating-point numbers
...
The following three types are available for calculations involving
floating-point numbers:
float
double
long double

for simple accuracy
for double accuracy
for high accuracy

The value range and accuracy of a type are derived from the amount of memory allocated
and the internal representation of the type
...
This means that “six decimal places” allows a
programmer to store two floating-point numbers that differ within the first six decimal
places as separate numbers
...
3456 and
12
...
And
remember, it is not a question of the position of the decimal point, but merely of the
numerical sequence
...

Readers interested in additional material on this subject should refer to the Appendix,
which contains a section on the representation of binary numbers on computers for both
integers and floating-point numbers
...
For example, sizeof(int)represents a value of 2 or 4 depending on
the machine
...


ᮀ Classification
The fundamental types in C++ are integer types, floating-point types, and the void type
...

The void type is used for expressions that do not represent a value
...


22



CHAPTER 2

FUNDAMENTAL TYPES, CONSTANTS, AND VARIABLES



CONSTANTS

Examples for integral constants
Decimal

Hexadecimal

Type

16

020

0x10

int

255

0377

OXff

int

32767

077777

0x7FFF

int

32768U

0100000U

0x8000U

unsigned int

100000

0303240

0x186A0

int (32 bit-)
long (16 bitCPU)

10L

012L

0xAL

long

27UL

033UL

0x1bUL

unsigned long

2147483648



Octal

020000000000

0x80000000

unsigned long

NOTE
In each line of the above table, the same value is presented in a different way
...

//
#include
using namespace std;
int main()
{
// cout outputs integers as decimal integers:
cout << "Value of 0xFF = " << 0xFF << " decimal"
<< endl;
// Output: 255 decimal
// The manipulator hex changes output to hexadecimal
// format (dec changes to decimal format):
cout << "Value of 27 = " << hex << 27 <<" hexadecimal"
<< endl;
// Output: 1b hexadecimal
return 0;
}

CONSTANTS



23

The boolean keywords true and false, a number, a character, or a character sequence
(string) are all constants, which are also referred to as a literals
...


Every constant represents a value and thus a type—as does every expression in C++
...


ᮀ Boolean Constants
A boolean expression can have two values that are identified by the keywords true and
false
...
They can be used, for example, to set flags
representing just two states
...
Hexadecimal numbers can be capitalized or noncapitalized
...
If the value of the constant is too large
for the int type, a type capable of representing larger values will be applied
...
For example,
12L
12U
12UL

and
and
and

12l
12u
12ul

correspond to the type long
correspond to the type unsigned int
correspond to the type unsigned long

24



CHAPTER 2

FUNDAMENTAL TYPES, CONSTANTS, AND VARIABLES



CONSTANTS (CONTINUED)

Examples for floating-point constants
5
...


0
...
0

0
...
OE-2

0
...
00004
0
...
75


...
4E-4

7
...
'

Dot

46

'0'

Digit 0

48

Terminating null character

0

'\0'

Internal representation of a string literal
String literal:

"Hello!"

Stored byte sequence:

'H'

'e'

'1'

'1'

'o'

'!'

'\0'

CONSTANTS (CONTINUED)



25

ᮀ Floating-Point Constants
Floating-point numbers are always represented as decimals, a decimal point being used to
distinguish the fraction part from the integer part
...


EXAMPLES:

27
...
8E–2

// Type: double

Here, 1
...
8*10–2
...
A decimal point or E (e) must always be used to distinguish floating-point constants
from integer constants
...
However, you can add F or f
to designate the float type, or add L or l for the long double type
...
Character constants take
the type char
...
The constant 'A'
thus has a value of 65 in ASCII code
...
A string constant consists of a sequence of characters enclosed in double
quotes
...
Thus, a string occupies one byte more in memory than the number of
characters it contains
...

The terminating null character \0 is not the same as the number zero and has a different character code than zero
...

The terminating null character \0 is an example of an escape sequence
...


26



CHAPTER 2

FUNDAMENTAL TYPES, CONSTANTS, AND VARIABLES



ESCAPE SEQUENCES

Overview
Single character

Meaning

ASCII code
(decimal)

\a

alert (BEL)

7

\b

backspace (BS)

8

\t

horizontal tab (HT)

9

\n

line feed (LF)

10

\v

vertical tab (VT)

11

\f

form feed (FF)

12

\r

carriage return (CR)

13

\"

" (double quote)

34

\'

' (single quote)

39

\?

? (question mark)

63

\\

\ (backslash)

92

\0

string terminating character

0

\ooo

numerical value of a character

ooo (octal!)

numerical value of a character

hh (hexadecimal!)

(up to 3 octal digits)

\xhh
(hexadecimal digits)

Sample program
#include
using namespace std;
int main()
{
cout << "\nThis is\t a string\n\t\t"
" with \"many\" escape sequences!\n";
return 0;
}

Program output:
This is

a string
with "many" escape sequences!

ESCAPE SEQUENCES



27

ᮀ Using Control and Special Characters
Nongraphic characters can be expressed by means of escape sequences, for example \t,
which represents a tab
...
The sequence
\t, for example, depends on the setting for the tab width, which defaults to eight blanks
but can be any value
...
The table on the opposite page shows the standard escape sequences, their decimal
values, and effects
...

Thus, the letter A (decimal 65) in ASCII code can also be expressed as \101 (three
octals) or \x41 (two hexadecimals)
...
The control sequences for
screen and printer drivers are, for example, initiated by the ESC character (decimal 27),
which can be represented as \33 or \x1b
...


EXAMPLES:

'\t'

"\tHello\n\tMike!"

The characters ', ", and \ have no special significance when preceded by a backslash, i
...

they can be represented as \', \", and \\ respectively
...
This helps to avoid any subsequent numbers being evaluated as part of the escape sequence
...
The sequence of hex numbers automatically terminates with
the first character that is not a valid hex number
...
The fact that a string can occupy two lines is another new feature
...

To continue a string in the next line you can also use a backslash \ as the last
character in a line, and then press the Enter key to begin a new line, where you can
continue typing the string
...
It is thus generally preferable to use the first method, that is, to terminate
the string with " and reopen it with "
...
The following
rules apply when creating names, which are also known as identifiers:






a name contains a series of letters, numbers, or underscore characters ( _ )
...
C++ is case sensitive; that is,
upper- and lowercase letters are different
...


The opposite page shows C++ keywords and some examples of valid and invalid names
...
To avoid confusion with these names, avoid use of the underscore at the beginning of a name
...
For this reason names of global objects, such as
functions, should be chosen so that the first eight characters are significant
...
The names of some variables tend to be associated with a specific use
...

In the case of software projects, naming conventions will normally apply
...


30



CHAPTER 2

FUNDAMENTAL TYPES, CONSTANTS, AND VARIABLES



VARIABLES

Sample program
// Definition and use of variables
#include
using namespace std;
int gVar1;
int gVar2 = 2;

// Global variables,
// explicit initialization

int main()
{
char ch('A');

// Local variable being initialized
// or: char ch = 'A';

cout << "Value of gVar1:
cout << "Value of gVar2:
cout << "Character in ch:

" << gVar1
" << gVar2
" << ch

<< endl;
<< endl;
<< endl;

int sum, number = 3; // Local variables with
// and without initialization
sum = number + 5;
cout << "Value of sum:
" << sum << endl;
return 0;
}



HINT
Both strings and all other values of fundamental types can be output with cout
...


Screen output
Value of gVar1:
Value of gVar2:
Character in ch:
Value of sum:

0
2
A
8

VARIABLES



31

Data such as numbers, characters, or even complete records are stored in variables to
enable their processing by a program
...


ᮀ Defining Variables
A variable must be defined before you can use it in a program
...
This memory
space is addressed by reference to the name of the variable
...
];

This defines the names of the variables in the list name1 [, name2
...
The parentheses [
...
Thus, one or more variables can be stated within a
single definition
...
This has the following effect:



a variable defined outside of each function is global, i
...
it can be used by all functions
a variable defined within a function is local, i
...
it can be used only in that function
...
However, they can be defined wherever a statement is permitted
...


ᮀ Initialization
A variable can be initialized, i
...
a value can be assigned to the variable, during its definition
...


EXAMPLES:

char c = 'a';
float x(1
...
In contrast, the initial
value for any local variables that you fail to initialize will have an undefined initial value
...
5
#include
using namespace std;
const double pi = 3
...
5;
area = pi * radius * radius;
circuit = 2 * pi * radius;
cout << "\nTo Evaluate a Circle\n" << endl;
cout << "Radius:
" << radius
<< "Circumference: " << circuit
<< "Area:
" << area

<< endl
<< endl
<< endl;

return 0;
}



NOTE
By default cout outputs a floating-point number with a maximum of 6 decimal places without trailing
zeros
...
5
9
...
06858

THE KEYWORDS CONST AND VOLATILE



33

A type can be modified using the const and volatile keywords
...
As an object of this type is
constant, it cannot be modified at a later stage and must be initialized during its definition
...
1415947;

Thus the value of pi cannot be modified by the program
...
0;

// invalid

ᮀ Volatile Objects
The keyword volatile, which is rarely used, creates variables that can be modified not
only by the program but also by other programs and external events
...


EXAMPLE:

volatile unsigned long

clock_ticks;

Even if the program itself does not modify the variable, the compiler must assume that
the value of the variable has changed since it was last accessed
...

It is also possible to combine the keywords const and volatile when declaring a
variable
...




CHAPTER 2



exercise s

34

FUNDAMENTAL TYPES, CONSTANTS, AND VARIABLES

EXERCISES

Screen output for exercise 2
I
"RUSH"
\TO\
AND
/FRO/

For exercise 3
Defining and initializing variables:
int a(2
...
2E+5);

const long large;
char c('\'');
unsigned char ch = '\201';
unsigned size(40000);
float val = 12345
...
For example, sizeof(short) is
equivalent to 2
...

Exercise 2
Write a C++ program to generate the screen output shown on the opposite
page
...
456 and 76
...




CHAPTER 2



solutions

36

FUNDAMENTAL TYPES, CONSTANTS, AND VARIABLES

SOLUTIONS

Exercise 1
#include
using namespace std;
int main()
{
cout <<
<<
<<
cout <<
cout <<
cout <<
cout <<
cout <<
cout <<
cout <<
<<

"\nSize of Fundamental Types\n"
" Type
Number of Bytes\n"
"----------------------------------" << endl;
" char:
" << sizeof(char) << endl;
" short:
" << sizeof(short)<< endl;
" int:
" << sizeof(int) << endl;
" long:
" << sizeof(long) << endl;
" float:
" << sizeof(float)<< endl;
" double:
" << sizeof(double)<" long double:
" << sizeof(long double)
endl;

return 0;
}

Exercise 2
// Usage of escape sequences
#include
using namespace std;
int main()
{
cout << "\n\n\t I"
"\n\n\t\t \"RUSH\""
"\n\n\t\t\t \\TO\\"
"\n\n\t\t AND"
"\n\n\t /FRO/" << endl;
return 0;
}

//
//
//
//
//

Instead of tabs
you can send the
suited number
of blanks to
the output
...
5);
const long large;
char z(500);
int big = 40000;
double he's(1
...
12345;

//
//
//
//
//
//
//
//
//
//

2
...
456F,
y = 76
...


This includes using standard header files
...
e
...

Functions and classes that you define on your own will not be
introduced until later in the book
...




Mathematical standard functions
double sin (double);

// Sine

double cos (double);

// Cosine

double tan (double);

// Tangent

double atan (double);

// Arc tangent

double cosh (double);

// Hyperbolic Cosine

double sqrt (double);

// Square Root

double pow (double, double);

// Power

double exp (double);

// Exponential Function

double log (double);

// Natural Logarithm

double log10 (double);

// Base-ten Logarithm

DECLARING FUNCTIONS



41

ᮀ Declarations
Each name (identifier) occurring in a program must be known to the compiler or it will
cause an error message
...
e
...

Each time a variable or a function is defined it is also declared
...
If you need to use a function that has already
been introduced in a library, you must declare the function but you do not need to redefine it
...
The function’s type is defined by
its return value, that is, the value the function passes back to the program
...
When a function is declared,
the compiler must therefore be provided with information on



the name and type of the function and
the type of each argument
...


Examples: int toupper(int);
double pow(double, double);

This informs the compiler that the function toupper() is of type int, i
...
its return
value is of type int, and it expects an argument of type int
...
The types of the arguments may be followed by names, however, the names are viewed as a comment only
...
Both junctions are standard junctions
...
If the header file is included in the
program’s source code by means of the #include directive, the function can be used
immediately
...
Additional details on header files can be found later in this
chapter
...
5, y;
// By means of a prototype, the compiler generates
// the correct call or an error message!
// Computes x raised
y = pow("x", 3
...
0);
y = pow(x, 3
...


cout << "2
...
5) yields: "
<< 2
...
0, x) << endl;
return 0;
}

Screen output
2
...
5) yields:

15
...
9017

FUNCTION CALLS



43

ᮀ Function Calls
A function call is an expression of the same type as the function and whose value corresponds to the return value
...


Example: y = pow( x, 3
...
0, and
the result, the power x3, is assigned to y
...
Thus, the
function pow() can be used to perform calculations for double values
...
0 + pow( 5
...
0 to the return value of pow(5
...

Any expression can be passed to a function as an argument, such as a constant or an
arithmetical expression
...

The compiler refers to the prototype to check that the function has been called correctly
...


Example: y = pow( x, 3);

// also ok!

The value 3 of type int is passed to the function as a second argument
...

If a function is called with the wrong number of arguments, or if type conversion
proves impossible, the compiler generates an error message
...


Example: float x = pow(3
...
7);

// Error!

The compiler recognizes that the number of arguments is incorrect
...
e
...


44



CHAPTER 3

USING FUNCTIONS AND CLASSES



TYPE void FOR FUNCTIONS

Sample program
// Outputs three random numbers
#include
#include

//
//
//
//

Declaration of cin and cout
Prototypes of srand(), rand():
void srand( unsigned int seed );
int rand( void );

using namespace std;
int main()
{
unsigned int seed;
int z1, z2, z3;
cout << "
--- Random Numbers --- \n" << endl;
cout << "To initialize the random number generator, "
<< "\n please enter an integer value: ";
cin >> seed;
// Input an integer
srand( seed);

// and use it as argument for a
// new sequence of random numbers
...


cout << "\nThree random numbers: "
<< z1 << "
" << z2 << "
" << z3 << endl;
return 0;
}



NOTE
The statement cin >> seed; reads an integer from the keyboard, because seed is of the
unsigned int type
...
The type void is available for functions of this type,
which are also referred to as procedures in other programming languages
...
Since the function does not return a value, it is of type void
...
The
value is used to create a series of random numbers
...


Example: int rand( void );

// or

int rand();

The standard function rand() is called without any arguments and returns a random
number between 0 and 32767
...


ᮀ Usage of srand() and rand()
The function prototypes for srand() and rand() can be found in both the cstdlib
and stdlib
...

Calling the function rand() without previously having called srand() creates the
same sequence of numbers as if the following statement would have been proceeded:
srand(1);

If you want to avoid generating the same sequence of random numbers whenever the
program is executed, you must call srand() with a different value for the argument
whenever the program is run
...
See
Chapter 6 for an example of this technique
...
h

//
//
//
//

// Declaration
// of cin, cout,
//
...
cpp
Copy

#include
#include "myheader
...

cin >> a;
cout << myfunc (a);

...
By using an #include
directive these declarations and macros can be made available to any other source file,
even in other header files
...
> or double quotes
"
...
If the name of the header file is enclosed by angled
brackets <
...

The current directory is not searched to increase the speed when searching for header
files
...
To enable the compiler to find these header files, the #include
directive must state the name of the header files in double quotes
...
h"
The compiler will then also search the current folder
...
h is normally used
for user-defined header files
...
When a header file is included, the classes defined and any objects declared
in the file are available to the program
...
cin is an object of the istream class and cout an object of the
ostream class
...
h and iomanip
...
Within
these header files the identifiers of iostream and iomanip are not contained in the std namespace
but are declared globally
...
h

limits
...
h

time
...
h

locale
...
h

wchar
...
h

math
...
h

wctype
...
h

setjmp
...
h

iso646
...
h

string
...
They are not indicated by the
file extension
...
Namespaces will be introduced in a later chapter
...
If you merely stipulate the
directive

Example: #include
the compiler would not be aware of the cin and cout streams
...


Example: #include
#include
using namespace std;

You can then use cin and cout without any additional syntax
...
This makes the string class available and allows userfriendly string manipulations in C++
...


ᮀ Header Files in the C Programming Language
The header files standardized for the C programming language were adopted for the C++
standard and, thus, the complete functionality of the standard C libraries is available to
C++ programs
...
h>
Mathematical functions are made available by this statement
...
This can cause name
conflicts in large programs
...
h, is
accompanied in C++ by a second header file, cname, which declares the same identifiers
in the std namespace
...
h is thus equivalent to

Example: #include
using namespace std;

The string
...
These header files grant access to the functionality of the
C string library and are to be distinguished from the string header file that defines the
string class
...

These may be graphics libraries or database interfaces
...

#include
#include
using namespace std;

// Declaration of cin, cout
// Declaration of class string

int main()
{
// Defines four strings:
string prompt("What is your name: "),
name,
// An empty
line( 40, '-'),
// string with 40 '-'
total = "Hello ";
// is possible!
cout << prompt;
getline( cin, name);
total = total + name;

// Request for input
...


cout << line << endl
// Outputs line and name
<< total << endl;
cout << " Your name is " // Outputs length
<< name
...
Strings can be printed with cout and the operator <<
...


Sample screen output
What is your name: Rose Summer
--------------------------------------Hello Rose Summer
Your name is 11 characters long!
---------------------------------------

USING STANDARD CLASSES



51

Several classes are defined in the C++ standard library
...

Each class is a type with certain properties and capacities
...
Methods are functions that belong to a class and cooperate with
the members to perform certain operations
...


ᮀ Creating Objects
An object is a variable of a class type, also referred to as an instance of the class
...


Example: string s("I am a string");
In this example the object s, an instance of the standard class string (or simply a
string), is defined and initialized with the string constant that follows
...

In general, there are several ways of initializing an object of a class
...


ᮀ Calling Methods
All the methods defined as public within the corresponding class can be called for an
object
...
The name of the object precedes the method and is separated from the method by
a period
...
length();

// object
...
e
...
This results in a value of 13 for the string s defined above
...
These functions perform certain
operations for objects passed as arguments
...


Example: getline(cin, s);
The keyboard input is terminated by pressing the return key to create a new-line character, '\n', which is not stored in the string
...
25
0
...
5
0
...
5);
b = rand( a );
cout << "\nRandom number: " << b << endl;
return 0;
}

EXERCISES



53

Exercise 1
Create a program to calculate the square roots of the numbers
4

12
...
0121

and output them as shown opposite
...

To calculate the square root, use the function sqrt(), which is defined by the
following prototype in the math
...


Exercise 2
The program on the opposite page contains several errors! Correct the errors
and ensure that the program can be executed
...

Read two lines of text from the keyboard
...
Output the new string on screen
...
0, x2 = 12
...
0121;
cout << "\n
cout << "\n
<< "\n
<< "\n

Number \t Square Root"
" << x1 << "
\t " <<
" << x2 << "
\t " <<
" << x3 << "
\t " <<

<< endl;
sqrt(x1)
sqrt(x2)
sqrt(x3) << endl;

cout << "\nType a number whose square root is to be"
" computed
...
h>
using namespace std;

// Introduces all names of namespace
// std into the global scope
...
// =
cout << message << endl;

SOLUTIONS



int len = message
...

srand(12);
// instead of: a = srand(12
...


55

This page intentionally left blank

chapter

4

Input and Output with
Streams
This chapter describes the use of streams for input and output, focusing
on formatting techniques
...
This gave rise to the I/O stream classes, which are now available in a library of
their own, the so-called iostream library
...
The class ios is the base class of all other stream classes
...
Effectively, the ios class



manages the connection to the physical data stream that writes your program’s
data to a file or outputs the data on screen
contains the basic functions needed for formatting data
...


The istream and ostream classes derived from ios form a user-friendly interface
for stream manipulation
...
The operator >> is defined in istream
and << is defined in ostream, for example
...

Further stream classes, a file management class, for example, are derived from the
classes mentioned above
...
These classes, which also contain methods for opening and closing
files, will be discussed in a later chapter
...
When a program is launched these objects are automatically created to read standard input or write to standard output
...
However,
standard input and output can be redirected to files
...

The other two standard streams cerr and clog are used to display messages when
errors occur
...


60



CHAPTER 4

INPUT AND OUTPUT WITH STREAMS



FORMATTING AND MANIPULATORS

Example: Calling a manipulator
Here the manipulator showpos is called
...
setf( ios::showpos);
cout << 123;

The other positive numbers are printed with their sign as well:
cout << 22;

// Output:

+22

The output of a positive sign can be canceled by the manipulator
noshowpos:
cout << noshowpos << 123;

// Output:

123

The last statement is equivalent to
cout
...
setf(ios::showpos);,
ios::showpos being the flag showpos belonging to the ios class



Using manipulators is easier than directly accessing flags
...




Old compilers only supply some of the manipulators
...


FORMATTING AND MANIPULATORS



61

ᮀ Formatting
When reading keyboard input, a valid input format must be used to determine how input
is to be interpreted
...

The stream classes istream and ostream offer various options for performing these
tasks
...

In previous chapters we have looked at the cin and cout streams in statements such
as:
cout << "Please enter a number: ";
cin >> x;

The following sections systematically describe the abilities of the stream classes
...
These operators are
defined for expressions with fundamental types—that is, for characters, boolean
values, numbers and strings
...
Manipulators can be used to generate formats for subsequent input/output
...

other methods for determining or modifying the state of a stream and unformatted input and output
...
In general, flags are represented by individual bits within a special integral variable
...

Each flag has a default setting
...

It is possible to modify individual formatting flags
...
However, the same effect can be achieved simply by using so-called manipulators, which are defined for all important flags
...


62



CHAPTER 4

INPUT AND OUTPUT WITH STREAMS



FORMATTED OUTPUT OF INTEGERS

Manipulators formatting integers
Manipulator

Effects

oct

Octal base

hex

Hexadecimal base

dec

Decimal base (by default)

showpos

Generates a + sign in non-negative numeric
output
...


uppercase

Generates capital letters in hexadecimal
output
...


Sample program
// Reads integral decimal values and
// generates octal, decimal, and hexadecimal output
...


int main()
{
int number;
cout << "Please enter an integer: ";
cin >> number;
cout << uppercase
// for hex-digits
<< " octal \t decimal \t hexadecimal\n "
<< oct << number << "
\t "
<< dec << number << "
\t "
<< hex << number << endl;
return 0;
}

FORMATTED OUTPUT OF INTEGERS



63

ᮀ Formatting Options
The << operator can output values of type short, int, long or a corresponding
unsigned type
...


In addition, the field width can be defined for the above types
...


ᮀ Numeric System
Integral numbers are displayed as decimals by default
...


Example: cout << hex << 11;

// Output: b

Hexadecimals are displayed in small letters by default, that is, using a, b,
...
The
manipulator uppercase allows you to use capitals
...


ᮀ Negative Numbers
When negative numbers are output as decimals, the output will always include a sign
...


Example: cout << dec << showpos << 11; //Output: +11
You can use noshowpos to revert to the original display mode
...


Example: cout << dec << -1 << "

" << hex << -1;

This statement causes the following output on a 32-bit system:
-1

ffffffff

64



CHAPTER 4

INPUT AND OUTPUT WITH STREAMS



FORMATTED OUTPUT OF FLOATING-POINT NUMBERS

Manipulators formatting floating-point numbers
Manipulator

showpoint

Effects
Generates a decimal point character
shown in floating-point output
...


noshowpoint

Trailing zeroes after the decimal point
are not printed
...


fixed

Output in fixed point notation

scientific

Output in scientific notation

setprecision (int n)

Sets the precision to n
...

Returns the used precision
...


Sample program
#include
using namespace std;
int main()
{
double x = 12
...
precision(2);
// Precision 2
cout << " By default:
" << x << endl;
cout << " showpoint: " << showpoint << x << endl;
cout << " fixed:
" << fixed
<< x << endl;
cout << " scientific: " << scientific << x << endl;
return 0;
}

FORMATTED OUTPUT OF FLOATING-POINT NUMBERS



65

ᮀ Standard Settings
Floating-points are displayed to six digits by default
...
Trailing zeroes behind the decimal point
are not printed
...


Examples: cout << 1
...
234;
cout << 1
...
234
// Output: 1
...

Very large and very small numbers are displayed in exponential notation
...
8; // Output: 1
...
You can




change the precision, i
...
the number of digits to be output
force output of the decimal point and trailing zeroes
stipulate the display mode (fixed point or exponential)
...


Example: cout << setprecision(3);

// Precision: 3
// or: cout
...
34;
// Output: 12
...
This also applies to all standard manipulators called with at least one
argument
...
The
number of digits being output (e
...
6) equals the current precision
...
0; // Output: 1
...
In this case, you can use the fixed manipulator with the precision defining the
number of decimal places
...


Example: cout << fixed << 66
...
000000

In contrast, you can use the scientific manipulator to specify that floating-point
numbers are output as exponential expressions
...


Examples
#include
#include
using namespace std;

// Obligatory
// declarations

1st Example: cout << '|' << setw(6) << 'X' << '|';
Output:
|
X|
// Field width 6
2nd Example: cout << fixed << setprecision(2)

Output:

<< setw(10) << 123
...
40
// Field width 10
1234567890

OUTPUT IN FIELDS



67

The << operator can be used to generate formatted output in fields
...


ᮀ Field Width
The field width is the number of characters that can be written to a field
...

The output will always contain at least the number of digits specified as the field width
...


Example: cout
...
The first example outputs the character 'X' to a field with width
of 6, but does not output the '|' character
...
You can also use the width() method to get the current
field width
...


Example: int fieldwidth = cout
...
You can either use the fill() method or the setfill() manipulator to specify
another fill character
...

As the previous example shows, output to fields is normally right-aligned
...
The manipulator internal left-justifies the sign and rightjustifies the number within a field
...
width(6); cout
...

#include
#include

// Declaration of cin, cout
// For manipulators being called
// with arguments
...
In this case the character
code is stored in an int variable and the variable is then output
...
The program on the opposite page
contains further examples
...
As in the case of other types, strings
can be positioned within output fields
...
The manipulator
right can be used to right-justify the output within the field
...
If you need to output the strings true or false instead, the
flag ios::boolalpha must be set
...


Example: bool ok = true;
cout << ok << endl
<< boolalpha << ok << endl;

// 1
// true

You can revert this setting using the noboolalpha manipulator
...

// Manipulator setw()

int main()
{
string label;
double price;
cout << "\nPlease enter an article label: ";
// Input the label (15 characters maximum):
cin >> setw(16);
// or: cin
...
sync();
cin
...
The program to be continued
return 0;
}



NOTE
The input buffer is cleared and error flags are reset by calling the sync() and clear() methods
...


FORMATTED INPUT



71

The >> operator, which belongs to the istream class, takes the current number base
and field width flags into account when reading input:



the number base specifies whether an integer will be read as a decimal, octal, or
hexadecimal
the field width specifies the maximum number of characters to be read for a
string
...
Keyboard input is thus
not read until confirmed by pressing the key
...

Input is displayed on screen by default
...
Any white space
characters (such as blanks, tabs, and new lines) are ignored by default
...

An input field is terminated by the first white space character or by the first character
that cannot be processed
...
However, the
characters that follow, FF and the newline character, remain in the input buffer and will
be read first during the next read operation
...


Example: string city;
cin >> city;

// To read just one word!

If Lao Kai is input, only Lao will be written to the city string
...
For a given field width of
n, a maximum of n–1 characters will be read, as one byte is required for the null character
...
The program on the opposite page illustrates
this point and also shows how to clear the input buffer
...
sync();
// Clears the buffer
cin
...
0, x2 = 0
...
number: ";
x1;
"2
...


Example: int n;
cin >> oct >> n;

An input value of 10 will be interpreted as an octal, which corresponds to a decimal
value of 8
...


ᮀ Inputting Floating-Point Numbers
The >> operator interprets any input as a decimal floating-point number if the variable is
a floating-point type, i
...
float, double, or long double
...


Example: double x;
cin >> x;

The character input is converted to a double value in this case
...
0, or 3e10 is valid
...
The next input field
begins with A
...
If, as in our example, no type conversion is performed, the
variable is not written to and an internal error flag is raised
...

Chapter 6, “Control Flow,” and Chapter 28, “Exception Handling,” show how a program can react to input errors
...


#include
#include
using namespace std;
string header =
"
--- Demonstrates Unformatted Input ---";
int main()
{
string word, rest;
cout << header
<< "\n\nPress to go on" << endl;
cin
...


cout << "\nPlease enter a sentence with several words!"
<< "\nEnd with and
...
A text of more than one line can be entered
...
The sample program requires that at least one word and a following white space are entered
...
The bytes read from a stream are passed to the program “as is
...


ᮀ Reading and Writing Characters
You can use the methods get() and put() to read or write single characters
...


Example: char ch;
cin
...
To prevent this from happening you can use
cin >> ch;

to read the first non-white space character
...
In this case, get()
returns the character code of type int
...
get();
The put() method can be used for unformatted output of a character
...


Example: cout
...


ᮀ Reading a Line
The >> operator can only be used to read one word into a string
...


Example: getline(cin, text);
This statement reads characters from cin and stores them in the string variable text
until a new line character occurs
...


Example: getline(cin, s, '
...
Any characters subsequent
to the first period will remain in the input buffer of the stream
...


Number of Pieces Price per piece

...
Dollar

Program listing for exercise 5
// A program with resistant mistakes
#include
using namespace std;
int main()
{
char ch;
string word;
cin >> "Let's go! Press the return key: " >> ch;
cout << "Enter a word containing
three characters at most: ";
cin

>> setprecision(3) >> word;

cout >> "Your input: " >> ch >> endl;
return 0;
}

EXERCISES



77

Exercise 1
What output is generated by the program on the page entitled “Formatted output
of floating-point numbers” in this chapter?
Exercise 2
Formulate statements to perform the following:
a
...
123456 in an output field with a width of 15
...
Output the number 23
...

c
...
456 as an exponential and with four decimal
spaces
...




Exercise 4
Write a C++ program that reads any given character code (a positive integer)
from the keyboard and displays the corresponding character and the character
code as a decimal, an octal, and a hexadecimal on screen
...


Why do you think the character P is output when the number 336 is entered?

Exercise 5
Correct the mistakes in the program on the opposite page
...

12
...
20e+001

Exercise 2
#include
#include
using namespace std;

// For setw() and setprecision()

int main()
{
double x1 = 0
...
987, x3 = -123
...
2346e+002
// A field width of 12 or more would be convenient!
return 0;
}

Exercise 3
// Input and formatted output of article characteristics
...
0;
// Input:
cout << "\nPlease enter article characteristics
...
Is only
// necessary, if input is > 255
...
Thus after the assignment, the variable c contains the value
80, representing the character P
...

//
#include
#include
// Manipulator setw()
#include
// Class string
using namespace std;
int main()
{
string word;

// To read a word
...


// cout <<
...
get();

cin >>
...
Overloading and other operators, such as those needed for
bit manipulations, are introduced in later chapters
...
0 << endl;
return 0;
}

Sample output for the program
Enter two floating-point values: 4
...
3456
The average of the two numbers is: 8
...
The operations being executed will depend on the
type of data — you could add, multiply, or compare numbers, for example
...

The following sections introduce you to the most important operators that can be
used for arithmetic types
...
A
unary operator has only one operand, whereas a binary operator has two
...
The opposite page shows an
overview
...
If at least one of the operands is a floating-point number,
the result will also be a floating-point number; e
...
, the division 7
...
5
...
For example, 7%2 computes to 1
...
Expressions can be used as the operands of operators to form more complex
expressions
...

Each expression that is not a void type returns a value
...


Examples: int a(4);

double
a * 512
//
1
...
9);
Type int
Type double
Type double, since one
operand is of type double

An expression can be used as an operand in another expression
...
e
...
In our example, 7*3 is first calculated before adding 2
...


Example: (2 + 7) * 3

// Multiplies 9 by 3
...


ᮀ Sign Operators
The sign operator – returns the value of the operand but inverts the sign
...


ᮀ Increment / Decrement Operators
The increment operator ++ modifies the operand by adding 1 to its value and cannot be
used with constants for this reason
...
In both cases the operation i = i + 1 is performed
...
The difference
becomes apparent when you look at the value of the expression; ++i means that the
value of i has already been incremented by 1, whereas the expression i++ retains the
original value of i
...


The decrement operator -- modifies the operand by reducing the value of the
operand by 1
...


ᮀ Precedence
How is an expression with multiple operators evaluated?

Example: float val(5
...
0/2
...
e
...
As you can see from the table opposite, ++ has the highest precedence and / has a higher precedence than -
...
0/2
...
The result is 1
...

If two operators have equal precedence, the expression will be evaluated as shown in
column three of the table
...
";
cout << "\n Please supply a divisor: ";
cin >> y;
x /= y;
cout << "\n And this is "
<< "your current lucky number: "
// without digits after
// the decimal point:
<< fixed << setprecision(0)
<< x << endl;
return 0;
}

ASSIGNMENTS



87

ᮀ Simple Assignments
A simple assignment uses the assignment operator = to assign the value of a variable to an
expression
...


Examples: z = 7
...
0 + 4
...
In the case of the last example, the right
side of the expression is first evaluated and the result is assigned to the variable on the
left
...


Example: sin(x = 2
...
5 is assigned to x and then passed to the function as an
argument
...


Example: i = j = 9;
In this case the value 9 is first assigned to j and then to i
...


Examples
...

Compound assignment operators can be composed from any binary arithmetic operator (and, as we will see later, with bit operators)
...

You can modify a variable when evaluating a complex expression by means of an
assignment or the ++, -- operators
...
Avoid
use of side effects if possible, as they often lead to errors and can impair the readability of
your programs
...
7 < 1
...


Example: length == circuit

// false or true

If the variables length and circuit contain the same number, the comparison is
true and the value of the relational expression is true
...

When individual characters are compared, the character codes are compared
...
The following expression
results in the value true when ASCII code is used
...


Example: bool flag = index < max – 1;
In our example, max – 1 is evaluated first, then the result is compared to index, and the
value of the relational expression (false or true) is assigned to the flag variable
...
Since result is an int
type, a numerical value is assigned instead of false or true, i
...
0 for false and 1 for
true
...


Example: (result = length + 1) == limit
Our example stores the result of length + 1 in the variable result and then compares
this expression with limit
...
The compiler will not generate
an error message if the value on the left is a variable
...


90



CHAPTER 5

OPERATORS FOR FUNDAMENTAL TYPES



LOGICAL OPERATORS

“Truth” table for logical operators

A

B

A && B

A || B

true

true

true

true

true

false

false

true

false

true

false

true

false

false

false

false

A

!A

true

false

false

true

Examples for logical expressions
x

Logical Expression

Result

1

-1

x <= y || y >=0

false

0

0

x > -2 && y == 0

true

-1

0

x && !y

true

0



y

1

!(x+1) || y - 1 > 0

false

NOTE
A numeric value, such as x or x+1, is interpreted as “false” if its value is 0
...


LOGICAL OPERATORS



91

The logical operators comprise the boolean operators && (AND), || (OR), and ! (NOT)
...

A logical expression results in a value false or true, depending on whether the logical expression is correct or incorrect, just like a relational expression
...
However, operands of any
type that can be converted to bool can also be used, including any arithmetic types
...
Any other value than 0 is interpreted as true
...
2) || (length > 9
...
2 or greater than 9
...

The AND operator && will return true only if both operands are true, so the logical
expression

Example: (index < max) && (cin >> number)
is true, provided index is less than max and a number is successfully input
...
The left operand is evaluated first and if a result has already been ascertained, the right operand will not be evaluated!
The NOT operator ! will return true only if its operand is false
...


ᮀ Precedence of Boolean Operators
The && operator has higher precedence than ||
...
This is why it was permissible to omit the parentheses in
the examples earlier on in this chapter
...
Refer to the table
of precedence in the Appendix for further details
...

#include
using namespace std;
int main()
{
cout << boolalpha; // Outputs boolean values
// as true or false
bool res = false;
int y =
res = 7
cout <<
<<
cout <<
int

5;
|| (y = 0);
"Result of (7 || (y = 0)): " << res
endl;
"Value of y: " << y << endl;

a, b, c;

a = b = c = 0;
res = ++a || ++b
cout << '\n'
<< " res =
<< ",
a =
<< ",
b =
<< ",
c =
a = b = c = 0;
res = ++a && ++b
cout << " res =
<< ",
a =
<< ",
b =
<< ",
c =
return 0;
}

&& ++c;
"
"
"
"

<<
<<
<<
<<

res
a
b
c << endl;

|| ++c;
" << res
" << a
" << b
" << c << endl;

EXERCISES



Exercise 1
What values do the following arithmetic expressions have?
a
...
3 + 4 % 5

b
...
3 * 7 % 4

c
...
0
f
...
How are operands and operators in the following expression associated?
x = –4 * i++ – 6 % 4;

Insert parentheses to form equivalent expressions
...
What value will be assigned in part a to the variable x if the variable i has a
value of –2?

Exercise 3
The int variable x contains the number 7
...
x < 10 && x >= –1
b
...
x++ == 8 || x == 7

Exercise 4
What screen output does the program on the opposite page generate?

93



CHAPTER 5



solutions

94

OPERATORS FOR FUNDAMENTAL TYPES

SOLUTIONS

Exercise 1
a
...
7

b
...
1

c
...
5
f
...
x = ( ((–4) * (i++)) – (6 % 4) )
b
...


Exercise 3
a
...
false
c
...
These are


loops with while, do-while, and for



selections with if-else, switch, and the conditional operator



jumps with goto, continue, and break
...
cpp
// Computing the average of numbers
#include
using namespace std;
int main()
{
int x, count = 0;
float sum = 0
...
3333

THE WHILE STATEMENT



97

Loops are used to perform a set of instructions repeatedly
...
C++ offers three language elements to formulate iteration
statements: while, do-while, and for
...
In the case of while and for statements this expression is verified before the loop body is executed, whereas a do-while loop is performed
once before testing
...
e
...
If this value is true, the loop body is then executed before the controlling
expression is evaluated once more
...
e
...

It is common practice to place the loop body in a new line of the source code and to
indent the statement to improve the readability of the program
...

However, the controlling expression might be any expression that can be converted to
the bool type including any arithmetic expressions
...


ᮀ Building Blocks
If you need to repeat more than one statement in a program loop, you must place the
statements in a block marked by parentheses { }
...

The program on the opposite page calculates the average of a sequence of integers
input via the keyboard
...

The controlling expression cin >> x is true provided the user inputs an integer
...
Invalid input, if the user types a letter instead
of an integer, for example, terminates the loop and executes the next statement
...
cpp
#include
#include
using namespace std;
int main()
{
double rate = 1
...
95
1
...
85
3
...
75

THE FOR STATEMENT



99

ᮀ Initializing and Reinitializing
A typical loop uses a counter that is initialized, tested by the controlling expression and
reinitialized at the end of the loop
...
loop" << endl;
++count;
// Reinitialization
}

In the case of a for statement the elements that control the loop can be found in the
loop header
...
loop" << endl;

Any expression can be used to initialize and reinitialize the loop
...
expression2 is
the controlling expression, which is always evaluated prior to executing the loop body:



if expression2 is false, the loop is terminated
if expression2 is true, the loop body is executed
...


You can also define the loop counter in expression1
...


Example: for( int i = 0; i < 10; cout << i++ )
;

As this example illustrates, the loop body can be an empty statement
...
However, to improve readability, even the empty statement should occupy a line of its own
...
cpp
// Outputs a table of exchange:

Euro and US-$

#include
#include
using namespace std;
int main()
{
long
euro, maxEuro;
double rate;

// Amount in Euros
// Exchange rate Euro <-> $

cout << "\n* * * TABLE OF EXCHANGE "
<< " Euro – US-$ * * *\n\n";
cout << "\nPlease give the rate of exchange: "
" one Euro in US-$: ";
cin >> rate;
cout << "\nPlease enter the maximum euro: ";
cin >> maxEuro;
//

--- Outputs the table

--// Titles of columns:

cout << '\n'
<< setw(12) << "Euro" << setw(20) << "US-$"
<< "\t\tRate: " << rate << endl;
// Formatting US-$:
cout << fixed << setprecision(2) << endl;
long lower, upper,
step;

// Lower and upper limit
// Step width

// The outer loop determines the actual
// lower limit and the step width:
for( lower=1, step=1; lower <= maxEuro;
step*= 10, lower = 2*step)
// The inner loop outputs a "block":
for( euro = lower, upper = step*10;
euro <= upper && euro <= maxEuro; euro+=step)
cout << setw(12) << euro
<< setw(20) << euro*rate << endl;
return 0;
}

THE FOR STATEMENT (CONTINUED)



101

Any of the three expressions in a for statement can be omitted, however, you must type
at least two semicolons
...
In the following

Example: for( ; expression; )
the loop header is equivalent to while(expression)
...


ᮀ The Comma Operator
You can use the comma operator to include several expressions where a single expression
is syntactically correct
...
The following syntax applies for the comma operator

Syntax:

expression1, expression2 [, expression3
...


Example: int x, i, limit;
for( i=0, limit=8; i < limit; i += 2)
x = i * i, cout << setw(10) << x;

The comma operator separates the assignments for the variables i and limit and is
then used to calculate and output the value of x in a single statement
...
This means you can leave out the parentheses in the above
example
...
The type and value are defined by the last expression
in a statement separated by commas
...


102



CHAPTER 6

CONTROL FLOW



THE do-while STATEMENT

Structogram for do-while

statement

As long as the expression is true

Sample program
// tone
...
e
...
This results in the loop body being performed at least once
...
Only then is the
controlling expression evaluated
...




NOTE
The do-while loop must be followed by a semicolon
...
The ANSI standard
stipulates a maximum depth of 256 nested loops
...

The program contains two loops — one of which is nested in the other
...
The break is caused by the inner
for loop where the variable i is incremented from 0 to the value of delay
...
The tone is generated by outputting the
control character BELL (ASCII code 7), which is represented by the escape sequence
\a
...


104



CHAPTER 6

CONTROL FLOW



SELECTIONS WITH if-else

Structogram for the if-else statement

if (expression)
true

statement1

false

statement2

Sample program
// if_else
...

min = x;
else
min = y;
cout << "\nThe smaller number is: " << min << endl;
}
else
cout << "\nInvalid Input!" << endl;
return 0;
}

Sample output for this program
Enter two different numbers:
7
...
7
The smaller number is: 5
...


Syntax:

if( expression )
statement1
[ else
statement2 ]

When the program is run, expression is first evaluated and the program control
branches accordingly
...
If there is no else and
expression is false, the control jumps to the statement following the if statement
...
But
not every if statement has an else branch
...


Example: if( n > 0 )
if( n%2 == 1 )
cout << " Positive odd number ";
else
cout << "Positive even number";

In this example, the else branch belongs to the second if, as is indicated by the fact
that the statement has been indented
...


Example: if( n > 0 )
{

if( n%2 == 1 )
cout << " Positive odd number \n";

}
else
cout << " Negative number or zero\n";

ᮀ Defining Variables in if Statements
You can define and initialize a variable within an if statement
...
In this case the variable is
available within the if statement
...
}

// Here to work with x
...
If this
value is not 0, the statements in the next block are executed
...


106



CHAPTER 6

CONTROL FLOW



Else-if CHAINS

Structogram for an else-if chain

if(expression)
true

false

statement1

if(expression)
true

false

statement2
if(expression)

...
cpp
// Output the fine for driving too fast
...
Dollars" << endl;
else if( toofast < 30)
cout << "Fine payable: 80,-
...
An elseif chain implies a series of embedded if-else statements whose layout is normally as
follows:
if ( expression1 )
statement1
else if( expression2 )
statement2

...


...
are
evaluated in the order in which they occur
...

If none of the expressions are true, the else branch of the last if statement is executed
...


ᮀ The Sample Program
The program opposite uses an else-if chain to evaluate the penalty for driving too fast
and outputs the fine on screen
...
If the user types 60
as the speed limit and 97
...
This outputs the message "Hand over your
driver's license!" on a new line
...
cpp
#include
using namespace std;
int main()
{
float x, y;
cout << "Type two different numbers:\n";
if( !(cin >> x && cin >> y) ) // If the input was
{
// invalid
...
2
216
...
7

CONDITIONAL EXPRESSIONS



109

ᮀ Conditional Operator
The conditional operator ?: is used to form an expression that produces either of two
values, depending on the value of some condition
...

In contrast to the if-else statement the selection mechanism is based on expressions: one of two possible expressions is selected
...


Syntax:

expression ? expression1 : expression2

expression is evaluated first
...
The value of the conditional expression is therefore either
the value of expression1 or expression2
...
If a has a positive value
of 12, the number 12 is assigned to z
...

Since this sample program stores the value of the conditional expression in the variable z, the statement is equivalent to
if( a > 0 )
z = a;
else
z = -a;

ᮀ Precedence
The conditional operator is the only C++ operator with three operands
...
In other words, you could omit the brackets in the first example
...
In this example, x is printed on screen if x is
greater than y, and y is printed otherwise
...


110



CHAPTER 6

CONTROL FLOW



SELECTING WITH switch

Structogram for the switch statement

switch(expression)
case Const1:
case Const2:

...

int command = menu();

// The function menu() reads
// a command
...


switch( command )
{
case 'a':
case 'A':
action1();
// Carry out 1st action
...

break;
default:
cout << '\a' << flush; // Beep on
}
// invalid input

SELECTING WITH SWITCH



111

ᮀ The switch Statement
Just like the else-if chain, the switch statement allows you to choose between multiple alternatives
...

switch( expression )
{
case const1: [ statement ]
[ break; ]
case const2: [ statement ]
[ break; ]

...


...
It must be an integral
type
...
, in the case
labels
...

If the value of an expression matches one of the case constants, the program
branches to the appropriate case label
...

You can use break to leave the switch statement unconditionally
...

If the value of the expression does not match any of the case constants, the program
branches to the default label, if available
...
The default does not need to be the last label; it can be followed by additional case labels
...
Every selection can
be programmed using an else-if chain
...
In this case (and only this
case), you can use a switch statement
...


112



CHAPTER 6

CONTROL FLOW



JUMPS WITH break, continue, AND goto

Structogram for break within a while statement
As long as expression is true

break;

statement, which follows the loop
...
cpp : To output an ASCII Code Table
#include
#include
using namespace std;
int main()
{
int ac = 32;
// To begin with ASCII Code 32
// without control characters
...
get(answer);
if( answer == 'q' || answer == 'Q' )
break;
cin
...


JUMPS WITH BREAK, CONTINUE, AND GOTO



113

ᮀ break
The break statement exits from a switch or loop immediately
...

The program on the opposite page, which outputs a group of 20 ASCII characters and
their corresponding codes, uses the break keyword in two places
...
} loop when a maximum value of 256 has been
reached
...
The second
break statement is used to terminate the while loop and hence the program
...
In the case of a while or do-while loop
the program jumps to the test expression, whereas a for loop is reinitialized
...
// Processes all integers
...

// Process even
// numbers only
...
This allows you to jump to any given point
marked by a label within a function
...


Example: for(
...
)
if (error) goto errorcheck;

...

// Error handling

A label is a name followed by a colon
...

Any program can do without goto statements
...




CHAPTER 6



exercise s

114

CONTROL FLOW

EXERCISES

Screen output for exercise 2
****** MULTIPLICATION TABLE ******
1

2

3

4

5

6

7

8

9

10

1

1

2

3


...



...



...


10

2

2

4

6

20

3


...



...


4


...



...


5


...



...


10

20

30

6
7
8
9
10


...



...



...


100

Note on exercise 4
Use the function time() to initialize the random number generator:
#include ...
h>

// Prototype of time()
// Prototypes of srand()
// and rand()

long sec;
time( &sec );
// Take the number of seconds and
srand( (unsigned)sec ); // use it to initialize
...
cpp program in this chapter to replace both the for
loops with while loops
...

Exercise 3
Write a C++ program that reads an integer between 0 and 65535 from the
keyboard and uses it to seed a random number generator
...

Exercise 4
Write a program for the following numerical game:
The computer stores a random number between 1 and 15 and the player
(user) attempts to guess it
...
After each
wrong guess, the computer tells the user if the number was too high or too low
...

The player wins if he or she can guess the number within three attempts
...




NOTE
Use the system time to seed the random number generator as shown opposite
...
The long value of the sec variable is converted to
unsigned by unsigned(sec) and then passed to the srand() function
...
cpp are equivalent to the following while
loops:
// The outer loop sets the lower
// limit and the step width used:
lower=1, step=1;
while( lower <= maxEuro)
{
// The inner loop outputs a block:
euro = lower;
upper = step*10;
while( euro <= upper && euro <= maxEuro)
{
cout << setw(12) << euro
<< setw(20) << euro*rate << endl;
euro += step;
}
step *= 10, lower = 2*step;
}

Exercise 2
//
//

MultTable
...


#include
#include
using namespace std;
int main()
{
int factor1, factor2;
cout << "\n\n
<< " ******
<< endl;

"
MULTIPLICATION TABLE

******"

// Outputs the first and second line:
cout << "\n\n\n
";
// 1
...
line
<< "-------------------------------------------"
<< endl;

SOLUTIONS

//

Outputs the remaining lines of the table:

for( factor1 = 1 ; factor1 <= 10 ; ++factor1 )
{
cout << setw(6) << factor1 << " |";
for( factor2 = 1 ; factor2 <= 10 ; ++factor2 )
cout << setw(5) << factor1 * factor2;
cout << endl;
}
cout << "\n\n\n";
// To shift up the table
return 0;
}

Exercise 3
// random
...

#include ...

// Seeds the random
// number generator
...
random number = "
<< setw(3) << (rand() % 100 + 1) << endl;
return 0;
}



117

118



CHAPTER 6

CONTROL FLOW

Exercise 4
// NumGame
...

long sec;
time( &sec);
// Get the time in seconds
...
sync();
// Clear input buffer
cin
...
attempt:
";
cin >> attempt;
if(attempt < number)
cout << "too small!"<< endl;
else if(attempt > number) cout <<"too big!"<< endl;
else
found = true;
}
if( !found)
cout << "\nI won!"
<< " The number in question was: "
<< number << endl;
else
cout << "\nCongratulations! You won!" << endl;
cout << "Repeat —>
Finish —> \n";
do
cin
...
In addition, standard macros
for character handling are introduced
...
cpp
// Creates a sine function table
#include
#include
#include
using namespace std;
#define PI
3
...
0
// Lower limit
#define END
(2
...
0)
// Step width
#define HEADER
(cout << \
" ***** Sine Function Table *****\n\n")
int main()
{
HEADER;

// Title
// Table Head:
cout << setw(16) << "x" << setw(20) << "sin(x)\n"
<< "
-----------------------------------------"
<< fixed << endl;
double x;
for( x = START; x < END + STEP/2; x += STEP)
cout << setw(20) << x << setw(16) << sin(x)
<< endl;
cout << endl << endl;
return 0;

}

Screen output
******

Table for the Sine Function

******

x
sin(x)
-------------------------------------------0
...
000000
0
...
382683
0
...
707107

...


...


...


MACROS



121

C++ has a simple mechanism for naming constants or sequences of commands, that is for
defining macros
...


Syntax:

#define

name

substitutetext

This defines a macro called name
...
For example, in the program on the opposite
page, the name PI is replaced by the number 3
...

There is one exception to this general rule: substitution does not take place within
strings
...


ᮀ Symbolic Constants
Macros that are replaced by constants, such as the PI macro, are also known as symbolic
constants
...

You can use any macros you have previously defined in subsequent #define directives
...


ᮀ More about Working with Macros
Any preprocessor directive, and this includes the #define directive, must be placed in a
line of its own
...

The rules that apply to naming variables also apply to naming macros
...

Using macros makes a C++ program more transparent and flexible
...
good readability: You can name a macro to indicate the use of the macro
2
...


122



CHAPTER 7

SYMBOLIC CONSTANTS AND MACROS



MACROS WITH PARAMETERS

Sample program
// ball1
...
To do so, you must supply the appropriate
parameters when defining the macro
...


Example: #define SQUARE(a)

((a) * (a))

This defines a macro called SQUARE() with a parameter a
...
When the macro is called, for example

Example: z = SQUARE(x+1);
the preprocessor inserts the substitute text with the current arguments, which will be
expanded as follows, in this case
z = ((x+1) * (x+1));

This example also shows that you must be careful when using brackets to indicate parameters for macros
...

The outer brackets in the definition ensure that even when the macro is used in a
complex expression, the square is calculated before the result can be used for any further
calculations
...
Peripheral
devices, such as the screen or printers, can be controlled by special character sequences
that normally begin with the ESC character (decimal 27, octal 033) and are thus known
as escape sequences
...
1 See the appendix on Escape Sequences for Screen Control for an overview of the
most important sequences
...
LOCATE is just one example of a macro with two parameters
...
The values z for the line and s for the column require decimal input with
z = 1, s = 1 representing the top left corner of the screen or window
...
” In direction x (horizontally) the ball has a constant speed of dx = 1 or
-1
...


1These

escape sequences are valid for all standard UNIX terminals
...
sys must be
loaded for DOS or a DOS box in Win95 or Win98
...


124



CHAPTER 7

SYMBOLIC CONSTANTS AND MACROS



WORKING WITH THE #define DIRECTIVE

Using macros in different source files

Header file proj
...
h"

#include "proj
...



...



...



...



...



...
h"

WORKING WITH THE #DEFINE DIRECTIVE



125

You can place the #define directive in any line of a program as long as it is placed prior
to using the macro
...

If you need to use the same macros in different source files, it makes sense to create a
header file
...
This method also
lends itself to large-scale software projects
...
This concept is illustrated opposite using the header file proj
...

Macros with parameters can be called just like functions
...
The substitute text is
inserted and re-compiled each time the macro is called
...
The speed of program execution will, however, improve since
the program does not need to branch to sub-routines in contrast to normal function calls
...

Side effects of macros are possible if the substitute text contains multiple
instances of a parameter
...
The variable x is incremented twice and the product
does not represent the square of the incremented number
...
The linker then links them
into the executable file
...

However, the executable file will be shorter as it contains only one instance of
the function code
...


Inline functions, which are introduced in the chapter on functions, are an alternative to macros
...
h
#ifndef_BASIS_H_
#define_BASIS_H_
//content of basis,
//ex
...

#endif

Header file

Header file

statist
...
h

#include
#include "basis
...
h"


...


Source file

application
...
h"
#include "graph
...

return 0;
}

CONDITIONAL INCLUSION



127

ᮀ Redefining Macros
A macro cannot simply be redefined
...
However, you do not need to supply the parameter list of a
macro with parameters
...

#undef MIN

((a)<(b)? (a) : (b))
// Here MIN can be called

The macro MIN cannot be used after this point, but it can be defined again, possibly with
a different meaning, using the #define directive
...


Syntax:

#ifdef name

...


#endif

In the case of the #ifndef directive, the code block is compiled up to the next #endif
only if the macro name has not been previously defined
...
See Preprocessor Directives in the appendix for further information
...


Example: #define MYHEADER
A symbol without a substitute text is often used to identify header files and avoid multiple inclusion
...
h", you can identify the header by defining a symbol, such as _ARTICLE_, within that file
...

// Content of the header file
#endif

If you have already included the header, _ARTICLE_ will already be defined, and the
contents of the header file need not be compiled
...


128



CHAPTER 7

SYMBOLIC CONSTANTS AND MACROS



STANDARD MACROS FOR CHARACTER MANIPULATION

Sample program
// toupper
...

// --------------------------------------------------#include
#include
using namespace std;
int main()
{
char c;
long nChar = 0,
// Counts all characters
nConv = 0;
// and converted characters
while ( cin
...

if( islower(c))
// Lowercase letter?
{ c = toupper(c);
// Converts the character
++nConv;
// and counts it
...
put(c);
// Outputs the character
...
When reading keyboard input, end-of-file is
simulated by Ctrl+Z (DOS) or Ctrl+D (UNIX)
...
The
macros are defined in the header files ctype
...


ᮀ Case Conversion
You can use the macro toupper to convert lowercase letters to uppercase
...
However if c1 is not a
lowercase letter, toupper(c1) returns the character “as is
...
As toupper only converts the letters
of the English alphabet by default, any national characters, such as accentuated characters in other languages, must be dealt with individually
...
Refer to the next section for details
...


ᮀ Testing Characters
A number of macros, all of which begin with is
...
For example, the macro islower(c) checks whether c contains a lowercase letter
returning the value true, in this case, and false in all other cases
...

cout << "The character is no digit \n";

The following usage of islower() shows a possible definition of the toupper()
macro:

Example: #define toupper(c) \
(islower(c) ? ((c)-'a'+'A') : (c))

This example makes use of the fact that the codes of lower- and uppercase letters differ
by a constant, as is the case for all commonly used character sets such as ASCII and
EBCDIC
...


130



CHAPTER 7

SYMBOLIC CONSTANTS AND MACROS



REDIRECTING STANDARD INPUT AND OUTPUT

Sample program
// lines
...

#include
#include
#include
using namespace std;
int main()
{
string line;
int number = 0;
while( getline( cin, line))
// As long as a line
{
// can be read
...
Redirecting the standard input:
lines < text
...
dat with line numbers
...

2
...
dat

Here the program reads from the keyboard and adds the output to the new file
new
...
Please note, if the file already exists, it will be overwritten!
You can use
lines >> text
...
dat
...
dat does not
already exist, it will be created
...


REDIRECTING STANDARD INPUT AND OUTPUT



131

ᮀ Filter Programs
The previous program, toupper
...
Programs of this type are known as filters
...
cpp, the loop
while( cin
...
}

is repeated while the test expression cin
...
The loop is terminated by end-of-file
or if an error occurs since the test expression cin
...

The program on the opposite page, lines
...
But in this case standard input is read line by
line
...
}

The test expression getline(cin,line) is true while a line can be read
...
This
allows easy data manipulation
...
dat with line numbers on screen, you can
execute the program lines by typing the following command:

Example: lines < text
...
In
other words, the standard input is redirected
...
You can redirect input and output
simultaneously:

Example: lines < text
...
dat



In this example the contents of text
...
dat
...


NOTE
These examples assume that the compiled program lines
...




CHAPTER 7



exercise s

132

SYMBOLIC CONSTANTS AND MACROS

EXERCISES

Hints for Exercise 2
You can use the function kbhit() to test whether the user has pressed a key
...
This avoids
interrupting the program when reading from the keyboard
...
Both functions use operating system routines and are
declared in the header file conio
...

The function kbhit()

Prototype:
Returns:

int kbhit();
0, if no key was pressed, otherwise != 0
...

The function getch()

Prototype:
Returns:

int getch();

The character code
...


In contrast to cin
...
Additionally, control characters, such as
return ( = 13), Ctrl+Z ( = 26), and Esc ( = 27), are passed to the program “as is
...

}



// Key was pressed?
// Yes -> Get character
// character == Esc?

NOTE
When a function key, such as F1, F2,
...
was pressed, the function
getch() initially returns 0
...


EXERCISES



133

Exercise 1
Please write
a
...
the macro MAX, which determines the greater of two numbers
...

Add these macros and other macros from this chapter to the header file
myMacros
...

If your system supports screen control macros, also add some screen control
macros to the header
...


Exercise 2
Modify the program ball1
...
display a white ball on a blue background,
b
...
increase the speed of the ball with the + key and decrease the speed
with the – key
...


Exercise 3
Write a filter program to display the text contained in any given file
...
Control characters are
defined by codes 0 to 31
...

A single character, that is, a character appearing between two control
characters, is not to be output!



NOTE
Since the program must not immediately output a single character following a control character, you will
need to store the predecessor of this character
...




CHAPTER 7



solutions

134

SYMBOLIC CONSTANTS AND MACROS

SOLUTIONS

Exercise 1
// -----------------------------------------------------// myMacros
...

// -----------------------------------------------------#ifndef _MYMACROS_
#define _MYMACROS_
#include
using namespace std;
// -----------------------------------------------------// Macro ABS
// Call: ABS( val)
// Returns the absolute value of val
#define ABS(a) ( (a) >= 0 ? (a) : -(a))
// -----------------------------------------------------// Macro MIN
// Call: MIN(x,y)
// Returns the minimum of x and y
#define MIN(a,b) ( (a) <= (b) ? (a) : (b))
// -----------------------------------------------------// Macro MAX
// Call: MAX(x,y)
// Returns the maximum of x and y
#define MAX(a,b) ( (a) >= (b) ? (a) : (b))
// -----------------------------------------------------// Macros for controlling the screen
// -----------------------------------------------------// Macro CLS
// Call: CLS;
// Clears the screen
#define CLS
(cout << "\033[2J")
// -----------------------------------------------------// Macro LOCATE
// Call: LOCATE(row, column);
// Positions the cursor to (row,column)
...

#define LOCATE(r,c) (cout <<"\033["<< (r) <<';'<<(c)<<'H')

SOLUTIONS

// -----------------------------------------------------// Macro COLOR
// Call: COLOR(foreground, background);
// Sets the foreground and background color
// for the following output
...
: COLOR( WHITE,BLUE);
#define BLACK 0
#define RED
1
#define GREEN
2
#define YELLOW
3
#define BLUE
4
#define MAGENTA 5
#define CYAN
6
#define WHITE
7
// -----------------------------------------------------// Macro INVERS
// Call: INVERS;
// The following output is inverted
...

#define NORMAL (cout << "\033[0m")
#endif

//

_MYMACROS_

Exercise 2
// --------------------------------------------------// ball2
...
h>
#include "myMacros
...
cpp
// Filter to ignore control characters
// To call e
...
: NoCtrl < file
// --------------------------------------------------#include
using namespace std;
#define isCtrl(c)

( c >= 0

int main()
{
char c, prec = 0;
long nCtrl = 0, nChar = 0;

&& c <= 31 \
&& c != '\n' && c != '\t')

//
//
//
//

Character and predecessor
Number of the following
control characters or
other characters

while( cin
...
put(' ');
nCtrl = 0;
}
switch( ++nChar)
{
case 1:
break;
case 2:
cout
...
put(c);
// current character
}
prec = c;
}
}
return 0;
}

137

This page intentionally left blank

chapter

8

Converting Arithmetic
Types
This chapter introduces implicit type conversions, which are performed in
C++ whenever different arithmetic types occur in expressions
...


139

140



CHAPTER 8



CONVERTING ARITHMETIC TYPES

IMPLICIT TYPE CONVERSIONS

Integer promotions

bool
int

char, signed char, unsigned char
short

int

if int equals long

unsigned int

if int equals short

unsigned short

Type hierarchy
long double

double

float

unsigned long

long

unsigned int

not-existent, if int
equals long

int

Example
short size(512); double res, x = 1
...
The compiler automatically performs implicit type conversion, where a common type, which allows the operation in question to be performed, is assigned for the values of both operands
...
The assignment
operator is an exception to this rule and will be discussed separately
...
However, comparison expressions will be bool types no matter what
type of operands are involved
...


This type conversion is performed so as to preserve the original values
...

Thus, C++ will always use int type values or greater when performing calculations
...


ᮀ Usual Arithmetic Type Conversions
If operands of different arithmetic types still occur after integer promotion, further
implicit type conversions along the lines of the hierarchy on the opposite page will be
necessary
...
These type conversions and integer promotions are collectively known as usual
arithmetic type conversions
...
The interim result 50 is then converted to double and multiplied by x
...


142



CHAPTER 8



CONVERTING ARITHMETIC TYPES

PERFORMING USUAL ARITHMETIC TYPE CONVERSIONS

Converting signed integers
a) Converting a positive number
Sign bit(= 0 ↔ not negative)
26

Binary representaion of the integer 10
as value of type signed char (8 bits):

0

25

24

23

22

21

20

0

0

0

1

0

1

0

Extension to int (here 16 bit)
The value 10 is preserved
...

Sign bit(= 1 ↔ negative)
Binary representaion of the integer –10
as value of type signed char (8 bits):

26
1

25

24

23

22

21

20

1

1

1

0

1

1

0

Extension to int (here 16 bit)
The value –10 is preserved
...
The bit pattern
1111 0110 of –10, for example, corresponds to the unsigned char value
246 == 0*20+ 1*21 + 1*22 + 0*23 + 1*24 + 1*25 + 1*26 + 1*27

PERFORMING USUAL ARITHMETIC TYPE CONVERSIONS



143

Usual arithmetic type conversions retain the value of a number provided it can be represented by the new type
...
Conversion of an unsigned type to a larger integral type

Examples: unsigned char to int or unsigned int
Zero extension is performed first
...

2
...
The
value is retained by performing sign extension
...

The new type is unsigned

Examples: char to unsigned int, long to unsigned long
In this case the value of negative numbers is not retained
...
However, the bit pattern will be
interpreted differently
...

If the new type is longer, sign extension is performed first and the new bit
pattern is then interpreted as unsigned
...
Conversion of an integral type to a floating-point type

Examples: int to double, unsigned long to float
The number is converted to an exponential floating-point type and the value
retained
...

4
...


144



CHAPTER 8

CONVERTING ARITHMETIC TYPES



IMPLICIT TYPE CONVERSIONS IN ASSIGNMENTS

Example 1:
int i = 100;
long lg = i + 50;

// Result of type int is
// converted to long
...


Example 3:
int i = –2; unsigned int ui = 2;
i = i * ui;
// First the value contained in i is converted to
// unsigned int (preserving the bit pattern) and
// multiplied by 2 (overflow!)
...
e
...


Example 4:
double db = –4
...

i = db – 0
...

ui = db;
// –4 is incompatible with ui
...
23456789012345;
float f;
f = d;
// 1
...


IMPLICIT TYPE CONVERSIONS IN ASSIGNMENTS



145

Arithmetic types can also be mixed in assignments
...

In the case of compound assignments, calculations using normal arithmetic type conversions are performed first before type conversion is performed following the rule for
simple assignments
...
If the type of the variable is larger than the type of the value to be assigned, the
type of the value must be promoted
...

2
...
” The
following procedures are followed depending on individual circumstances:
a
...
The bit pattern that remains will be interpreted as unsigned, if the
new type is also unsigned, and as signed in all other cases
...




when converting an unsigned type to a signed type of the same scale,
the bit pattern is retained and will be interpreted as signed (see Example
3)
...
Conversion of a floating-point type to an integral type
The decimal part of the floating-point number is removed
...
9
converts to the integer 1
...
5 to a positive floating-point number or subtracting 0
...
This would allow for converting (1
...
5) to 2
...
This particularly applies to converting negative floatingpoint numbers to unsigned integers (see Example 4)
...
Conversion of a floating-point type to a smaller type
If the floating-point number falls within the range of the new type, the value
will be retained, although the accuracy may be compromised
...


146



CHAPTER 8

CONVERTING ARITHMETIC TYPES



MORE TYPE CONVERSIONS

Sample program
// Ellipse
...

// The points (x,y) on an ellipse with center (0,0)
// and axes A and B satisfy:
//
x = A*cos(t), y = B*sint(t) for 0 <= t <= 2*PI
...
1416
40
12
25
10

//
//
//
//

The point
center of
Length of
Length of

(Mx, My) is the
the ellipse
...


CLS;
// 0 <= t <= PI/2 is a 1/4-circle:
for( double t = 0
...
03)
{
x = (int) (A * cos(t) + 0
...
5);
DOT( x+Mx, y+My);
DOT( x+Mx,-y+My);
DOT(-x+Mx, y+My);
DOT(-x+Mx,-y+My);
}
LOCATE(24,0);
return 0;
}

MORE TYPE CONVERSIONS



147

ᮀ Implicit Type Conversions in Function Calls
In the case of function calls, arguments with arithmetic types are converted to the types of
the corresponding parameters, similarly to conversions in assignments
...

func( size, 77);

// Prototype

// Call

The function func() has two parameters belonging to the short and double types
...
This leads to implicit conversion of the value of size to short and the integer 77 to double
...
You can use explicit type conversion to avoid warnings during type conversion
...


Syntax:

(type) expression

This converts the value of an expression to the given type
...

The cast operator (type) is a unary operator and thus has a higher precedence than
the arithmetic operators
...
Following the conventions of usual implicit type conversion, b is also converted to double and a floatingpoint division is performed
...
25, is assigned to the variable x
...

C++ has additional operators for explicit type conversion—the cast operator
dynamic_cast<>, for example
...




CHAPTER 8



exercise s

148

CONVERTING ARITHMETIC TYPES

EXERCISES

Program listing for exercise 3
// Convert
...

#include
#include
using namespace std;
int main()
{
char v_char = 'A';
cout << "v_char:
" << setw(10) << v_char
<< setw(10) << (int)v_char
<< endl;
short v_short = –2;
cout << "v_short:
" << dec << setw(10) << v_short
<< hex << setw(10) << v_short
<< endl;
unsigned short v_ushort = v_short;
cout << "v_ushort:
" << dec << setw(10) << v_ushort
<< hex << setw(10) << v_ushort
<< endl;
unsigned long v_ulong = v_short;
cout << "v_ulong:
" << hex << setw(20) << v_ulong
<< endl;
float v_float = –1
...


Exercise 3
What is output when the program opposite is executed?
Exercise 4
Write a C++ program to output the sine curve on screen as in the graphic
shown on the opposite page
...
Plot one point of the curve in columns 10, 10+1,
...
This leads to a
step value of 2*PI/64 for x
...
Use the following extended ASCII code characters to draw the axes:
Character

Decimal

Octal



196

304

+

197

305

16

020

30

036

Example:

cout << '\020';

// up arrowhead



CHAPTER 8



solutions

150

CONVERTING ARITHMETIC TYPES

SOLUTIONS

Exercise 1
When called, the value –1 is converted to parameter n, i
...
to unsigned int
...

On a 32-bit system, –1 has the bit pattern 0xFFFFFFFF, which, when
interpreted as unsigned, corresponds to the decimal value 4 294 967 295
...


Exercise 3
The screen output of the program
v_char:
v_short:
v_ushort:
v_ulong:
v_float:
(int)v_float:

A
-2
65534

65
fffe
fffe
fffffffe

-1
...
cpp
//
Outputs a sine curve
// ----------------------------------------------------#include
#include
using namespace std;
#define
#define
#define
#define
#define

// Prototypes of sin()

CLS
(cout << "\033[2J")
LOCATE(z,s) (cout <<"\033["<<(z)<<';'<<(s)<<'H')
PI
3
...
0
// Lower limit
END
(2
...
5);
LOCATE( row, column); cout << '*';
}
LOCATE(25,1);
return 0;
}



;

++column)

// Cursor to the last row

151

This page intentionally left blank

chapter

9

The Standard Class
string
This chapter introduces the standard class string, which is used to
represent strings
...
These include inserting and erasing,
searching and replacing, comparing, and concatenating strings
...


Sample program
// string1
...
size()
<< " characters long!" << endl;
// Two new strings:
string copy(text),
// a copy and the
start(text,0,10);
// first 10 characters
// starting with
// position 0
...
During string operations the required memory
space is automatically reserved or modified
...

The string class is defined in the string header file and was mentioned in Chapter 3 as an example for the use of classes
...
This allows for easy copying, concatenation, and comparison
...


ᮀ Initializing Strings
A string, that is, an object belonging to the string class, can be initialized when you
define it using




a predefined string constant
a certain number of characters
a predefined string or part of a string
...

The length of a string, that is, the current number of characters in the string, is stored
internally and can be accessed using the length() method or its equivalent size()
...
length();

// Output: 13

ᮀ String Assignments
When you assign a value to a string, the current contents are replaced by a new character
sequence
...


The memory space required is adjusted automatically
...
In contrast, the >> operator reads only one word, ignoring any leading white space
...


156



CHAPTER 9

THE STANDARD CLASS STRING



CONCATENATING STRINGS

Sample program
// string2
...

#include
#include
using namespace std;
string prompt("Please enter some text!\n"),
line( 50, '-');
int main()
{
prompt+="Terminate the input with an empty line
...
length() == 0) // Empty line?
break;
// Yes ->end of the loop
text = line + '\n' + text;
// Inserts a new
// line at the beginning
...

--------------------------------------Babara, Bobby, and Susan
will go to the movies today
--------------------------------------Your lines of text in reverse order:
--------------------------------------will go to the movies today
Babara, Bobby, and Susan

CONCATENATING STRINGS



157

Within the string class the operators + and += are defined for concatenating, and the
operators ==, !=, <, <=, >, and >= are defined for comparing strings
...


ᮀ Using + to Concatenate Strings
You can use the + operator to concatenate strings, that is, to join those strings together
...
The result, "sunflower" is then
assigned to sum
...
This expression can in turn be used as an operand in a more complex expression
...
Concatenation takes place from left to right
...
The expression "Good morning " +
"mister X" would be invalid!

ᮀ Using += to Concatenate Strings
Strings can also be concatenated by first performing concatenation and then assigning
the result
...
However, you can obtain the same result using the assignment operator += ,
which is far more efficient
...

// Also possible

This adds the content of the second string directly to s1
...


158



CHAPTER 9

THE STANDARD CLASS STRING



COMPARING STRINGS

Sample program
// string3
...

#include
#include
using namespace std;
string prompt = "Please enter two lines of text!\n",
line( 30, '-');
int main()
{
string line1, line2, key = "y";
while( key == "y" || key == "Y")
{
cout << line << '\n' << prompt << line << endl;
getline( cin, line1);
// Read the first
getline( cin, line2);
// and second line
...
length(),
len2 = line2
...
See Chapter 17, Pointers and Arrays, for more information
...
This also
allows you to use strings to formulate the conditions for branches and loops
...


// str1 is less than str2?

ᮀ Results of Comparisons
Strings are compared lexicographically, that is character by character, beginning at the
first character
...
Thus, if you are
using the ASCII character set, the letter 'A' (ASCII code 65) is smaller than the letter
'a' (ASCII code 97)
...
Given two strings s1 and s2:
s1 == s2
s1 < s2

is true only if both strings are identical; this requires that both strings
are exactly the same length
...


All other comparative operations can be deduced from the above rules
...

In an expression comparing strings, one operand can again be a string constant or a
single character
...
}
This example compares the string key with the single character 'y'
...

String comparisons can also be combined to form more complex expressions
...
}

The controlling expression is valid if the string key contains only the letter 'Y' or 'y'
...


160



CHAPTER 9



THE STANDARD CLASS STRING

INSERTING AND ERASING IN STRINGS

ᮀ Inserting a string
string s1("Miss Summer");
s1
...
erase(4,7);
// Start position: 4, Quantity: 7

Effect of the statement:
Position:

0

1

2

3

4

String s
before

'T' 'h'

'e'

' '

String s
afterwards

'T'

'e'

' '

'h'

5

6

7

8

9

10 11 12 13 14

's'

'u' 'm' 'm' 'e'

'r'

'-'

't'

'i'

'm' 'e'

't'

'i'

'm' 'e'

INSERTING AND ERASING IN STRINGS



161

The string class contains numerous methods for performing string manipulations
...

These methods generally allow passing a string constant instead of a second string
...


ᮀ Insertion
The method insert() inserts a string at a certain position of another string
...
The first character in a string occupies position 0, the second character position 1,
and so on
...
insert(5, "Ashley ");

The string "Ashley " is inserted into the string s1 at position 5, that is in front of the
'S' character in "Summer"
...

If you need to insert only part of a string into another string, you can pass two additional arguments to the insert() method, the starting position and the length of the
string
...
insert(12, s2, 0, 12);

This example inserts the first 12 characters from the string s2 at position 13 in string s1
...


ᮀ Erasing
You can use the erase() method to delete a given number of characters from a string
...


Example: string s("The summer-time");
s
...
The erase()
method can also be called without specifying a length and will then delete all the characters in the string up to the end of the string
...
erase(6);

// s now contains "winter"

You can also call erase() without any arguments to delete all the characters in a
string
...
Example “Bob and Bill”
string s1("There they go again!"),
s2("Bob and Bill");
s1
...
Example “my love”
string s1("Here comes Mike!"), s2("my love?");
s1
...
If the string contains the required substring, the position of the substring found by the search is returned
...
Since the npos constant is defined in
the string class, you can reference it as string::npos
...
The method requires the substring to be located as an argument
...
find("young");

The variable first has a value of 11 in this example
...
This initializes the variable last with a value of 21 in our example
...
rfind("young");

ᮀ Replacing
When replacing in strings, a string overwrites a substring
...

You can use the replace() method to perform this operation
...
The
third argument contains the replacement string
...
find("they");
if( pos != string::npos )
s1
...
After this operation s1 contains the string "There Bob and Bill go
again!"
...


Example: string s1("Here comes Mike!"),
s2("my love?");
s1
...


164



CHAPTER 9

THE STANDARD CLASS STRING



ACCESSING CHARACTERS IN STRINGS

Sample program
// string4
...

// (A word is the maximum sequence of characters
// containing no white space characters
...
');
// Reads a text up to
// the first '
...
length(); ++i)
{
if( isspace( text[i]) ) // white space?
{
++nSpace; fSpace = true;
}
else if( fSpace)
// At the beginning of a word?
{
++nWord;
fSpace = false;
}
}
cout << line
// Outputs the result
...
length()
<< "\n
words: " << nWord
<< "\n
white spaces: " << nSpace
<< endl;
return 0;
}

ACCESSING CHARACTERS IN STRINGS



165

When manipulating strings it is often important to access the individual characters that
form the string
...
An
individual character is always identified by its index, also referred to as subscript, that is,
its position in the string
...


ᮀ Subscript Operator
The easiest way to access a single character in the string is to use the subscript operator
[]
...
length() – 1
...


Example: char c = s[0];
This statement copies the first character from s to the variable c
...
length() –1] = 'g';
overwrites the last character in the string s
...


ᮀ Invalid Indices
Any integral expression can be used as an index
...


Example: cout << s[5];

// Error

Your program’s reaction to an invalid index is undefined; this requires careful attention by the programmer! You can call the at() method if you need to perform range
checks
...


Example: s
...
If an
invalid index is found an exception occurs and the program will normally be terminated at
this point
...




CHAPTER 9

THE STANDARD CLASS STRING



exercise s

166

EXERCISES

For exercise 3
// timeStr
...

#include
#include
#include
using namespace std;

// For time(), ctime(),
...

string tm = ctime( &sec);
// Converts the
// seconds to a string
...

string greeting("Have a wonderful ");
if( hr < "10")
// Compares strings
greeting += "Morning!";
else if( hr < "17")
greeting += "Day!";
else
greeting += "Evening!";
cout << greeting << endl;
return 0;

}

EXERCISES



167

Exercise 1
Write a C++ program to






initialize a string s1 with the string "As time by
...


In each case, your program should determine the position of the substring
...


Exercise 2
Write a C++ program that reads a word from the keyboard, stores it in a string,
and checks whether the word is a palindrome
...
The following are examples of
palindromes:“OTTO, ” “deed, ” and “level
...
Modify the program to continually read and
check words
...




NOTE
The function time() returns the current time as the number of seconds since 1/1/1970, 0:0
...

The function ctime() converts the number of seconds to a string with a date and time and returns
this string
...
cpp: Insert, search, and replace in strings
...
",
s2 = "goes ";
int main()
{
int pos = 0;
cout << header << endl;
cout << "s1 : " << s1 << endl;
// To insert:
cout << "\nInserting in string \"" << s2 <<"\""<< endl;
pos = s1
...
insert(pos,s2);
cout << "s1 : " << s1 << endl;

// Result

// To erase:
cout << "\nTo erase remaining characters behind \"by\":"
<< endl;
pos = s1
...
erase(pos + 3);
cout << "s1 : " << s1 << endl;

// Result

// To replace:
cout << "\nTo replace \"time\" by \"Bill\":"
<< endl;
pos = s1
...
replace(pos, 4, "Bill");
cout << "s1 : " << s1 << endl;
return 0;
}

// Result

SOLUTIONS



Exercise 2
// ----------------------------------------------------// palindrome
...

// ----------------------------------------------------#include
#include
using namespace std;
string header = " * * * Testing palindromes * * * ",
prompt = "Enter a word: ",
line( 50, '-');
int main()
{
string word;
char key = 'y';

// Empty string

cout << "\n\t" << header << endl;
while( key == 'y' || key == 'Y')
{
cout << '\n' << line << '\n'
<< prompt;
cin >> word;
// Compares the first and last character,
// the second and the second to last etc
...
length() - 1;
for( ; i <= j ; ++i, --j)
if( word[i] != word[j] )
break;
if( i > j)
// All characters equal?
cout << "\nThe word " << word
<< " is a P A L I N D R O M E !" << endl;
else
cout << "\nThe word " << word
<< " is not a palindrome" << endl;
cout << "\nRepeat? (y/n) ";
do
cin
...
sync();
}
return 0;
}

169

170



CHAPTER 9

THE STANDARD CLASS STRING

Exercise 3
The program outputs the date and time first
...
For example:
Date and time: Thu Nov 28 09:01:37 2001
Have a wonderful morning!

chapter

10

Functions
This chapter describes how to write functions of your own
...


171

172



CHAPTER 10



FUNCTIONS

SIGNIFICANCE OF FUNCTIONS IN C++

Elements of a C++ program

C++ program

Core elements of
C++
(built-in types,
operators,
control structures)

Functions and
classes of the
standard library

Self-defined
functions and
classes and
other libraries

SIGNIFICANCE OF FUNCTIONS IN C++



173

C++ supports efficient software development on the lines of the top-down principle
...
After identifying objects you will need to define classes
that describe these objects
...
In addition, you can make use of inheritance to create specialized classes without needing to
change any existing classes
...
However, not every function is a member function
...
Functions of this type do not belong to any particular class but normally represent algorithms
of a more general nature, such as the search or sort functions of the standard library
...
Many useful global functions and classes are available from the C++ standard library
...
Often a compiler package will offer commercial class
libraries or graphical user interfaces
...


Classes and functions that belong together are normally compounded to form separate
source files, which can be compiled and tested independently
...
You can enhance the reusability of your
source code by compiling your own libraries, but be sure to include comments for ease of
readability
...
If you modify a source file, you
may also need to recompile other files
...
An integrated developer environment will
offer the functionality of this utility when you create a new project
...


174



CHAPTER 10



FUNCTIONS

DEFINING FUNCTIONS

Example of a function definition
// func1
...
\n";
test( 10, -7
...
" << endl;
return 0;
}
void test(int arg1, double arg2 )
// Definition
{
cout << "\nIn function test()
...
argument: " << arg1
<< "\n 2
...


...


...
Chapter 13, Defining
Classes, describes the steps for defining member functions
...

This makes the program easier to understand, since you start reading at the point where
the program starts to execute
...
The example can be read as follows:
type
name
declaration_list

is the function type, that is, the type of the return value
...

contains the names of the parameters and declares their
types
...
A list of declarations that contains only the
word void is equivalent to an empty list
...
They are created
when the function is called and initialized by the values of the arguments
...
5); is called, the parameter
arg1 is initialized with a value of 10 and arg2 with -7
...

The left curved bracket indicates the start of a function block, which contains the statements defining what the function does
...
The only difference when a function is defined is that the name and declaration list
are not followed by a semicolon but by a function code block
...
This means you can omit parameter names from the prototype, whereas compiling a function definition will produce machine code
...
cpp
// Example for a simple function returning a value
...
5, y = 7
...

double area( double width, double len)
{
return (width * len);
// Returns the result
...
50
and length
8
...
70

RETURN VALUE OF FUNCTIONS



177

The program opposite shows how the function area() is defined and called
...
The prototype provides
the compiler with all the information it needs to perform the following actions when a
function is called:



check the number and type of the arguments
correctly process the return value of the function
...
Even though simple examples often define and
call a function within a single source file, this tends to be an exception
...

When a function is called, an argument of the same type as the parameter must be
passed to the function for each parameter
...
The value of the expression is
always copied to the corresponding parameter
...
If the function is any type other than void,
the return statement will also cause the function to return a value to the function that
called it
...
If the
type of this value does not correspond to the function type, the function type is converted, where possible
...

The function area() makes use of the fact that the return statement can contain
any expression
...

If the expression in the return statement, or the return statement itself, is missing, the return value of the function is undefined and the function type must be void
...


178



CHAPTER 10



FUNCTIONS

PASSING ARGUMENTS

Calling function and called function
long func2(int, double);
//
...
1;
double y;

...

}

// Prototype

// Call of func2()
...
2;
long result;

...

// is computed
...

return result;
}

Stack content after calling a function
On call
“push”

On return
“pop”
• • •

further local objects

return address
first parameter
• • •

last parameter
Stack

PASSING ARGUMENTS



179

ᮀ Passing by Value
Passing values to a function when the function is called is referred to as passing by value
...

However, function arguments can also be passed by reference
...

An example of passing by reference was provided in the example containing the function time()
...
We will see how
to create functions of this type later
...
Additional
indirect memory access is unnecessary
...


ᮀ Local Objects
The scope of function parameters and the objects defined within a function applies only
to the function block
...

For example, the program structure opposite contains a variable a in the function
func1() and in the function func2()
...
This also applies to the variables x in func1() and
func2()
...
The stack is an area of memory that is managed according to the LIFO (last in first out) principle
...
The last
plate you put on the stack has to be taken off first
...


180



CHAPTER 10



FUNCTIONS

INLINE FUNCTIONS

Call to a function not defined as inline
Program

Function

Branching

void func()
{

// 1st Call

func();

// 2nd Call

}

func();



HINT
The executable file only contains one instance of the function’s machine code
...


INLINE FUNCTIONS



181

ᮀ Jumping to Sub-Routines
When a function is called, the program jumps to a sub-routine, which is executed as follows:




the function parameters are placed on the stack and initialized with appropriate
arguments
the so-called return address, that is, the place where the function was called, is
stored on the stack and the program flow branches to the function
after executing the function the program uses the return address it stored previously to return to the calling function
...


All this jumping back and forth can affect the run time of your program, especially if the
function contains only a few instructions and is called quite often
...
However, you can define inline functions to avoid this problem
...
The definition of an inline function is
introduced by the inline keyword in the function header
...
This is why
inline functions should contain no more than one or two instructions
...

An inline function must be defined in the source file in which it is called
...
The code containing the instructions must
also be available to the compiler
...
This means the function will be available
in several source files
...
When a macro is called,
the preprocessor simply replaces a block of text
...
The compiler performs a type check, for example
...

// Formula: capital = k0 * (1
...
h>
double capital( double k0, double p, double n)
{
return (k0 * pow(1
...
5, double n=1
...
0, 3
...
5);
endcap = capital( 2222
...
8);
endcap = capital( 3030
...

endcap = capital( 100
...
0);
// No gap!
endcap = capital( , 5
...




// not ok

// not ok

NOTE
A function defined with default arguments is always called with the full number of arguments
...


DEFAULT ARGUMENTS



183

So-called default arguments can be defined for functions
...
The compiler simply uses the default values for any
missing arguments
...

In other words, you need to supply them when you declare the function
...


Example: void moveTo( int = 0, int = 0);
The function moveTo() can then be called with or without one or two arguments
...

It is also possible to define default arguments for only some of the parameters
...
They can also be
supplied when the function is defined, if the definition occurs in the same source
file and before the function is called
if you define a default argument for a parameter, all following parameters must
have default arguments
default arguments must not be redefined within the prototype scope (the next
chapter gives more details on this topic)
...


You can use default arguments to call a function with a different number of arguments
without having to write a new version of the function
...
cpp
// To generate and output random numbers
...


if( !setrand )
{ srand((unsigned int)time(NULL));
setrand = true;
}
}
inline double myRandom()
// Returns random number x
{
// with 0
...
0
init_random();
return (double)rand() / (double)RAND_MAX;
}
inline int myRandom(int start, int end) // Returns the
{
// random number n with
init_random();
// start <= n <= end
return (rand() % (end+1 - start) + start);
}
// Testing myRandom() and myRandom(int,int):
int main()
{
int i;
cout << "5 random numbers between 0
...
0 :"
<< endl;
for( i = 0; i < 5; ++i)
cout << setw(10) << myRandom();
cout << endl;
cout << "\nAnd now 5 integer random numbers "
"between -100 and +100 :" << endl;
for( i = 0; i < 5; ++i)
cout << setw(10) << myRandom(-100, +100);
cout << endl;
return 0;
}

OVERLOADING FUNCTIONS



185

Functions in traditional programming languages, such as C, which perform the same task
but have different arguments, must have different names
...


Example: int

int_max( int x, int y);
double dbl_max( double x, double y);

Of course this is detrimental to efficient naming and the readability of your program—
but luckily, this restriction does not apply to C++
...


Example: int

max( int x, int y);
double max( double x, double y);

In our example two different function share the same name, max
...
The compiler uses a function’s signature to
differentiate between overloaded functions
...
When a function is
called, the compiler compares the arguments to the signature of the overloaded functions
and simply calls the appropriate function
...
9;
maxvalue = max( 1
...

When overloaded functions are called, implicit type conversion takes place
...


Example: maxvalue = max( 1, value);

// Error!

The signature does not contain the function type, since you cannot deduce the type by
calling a function
...


Example: int

search(string key);
string search(string name);

Both functions have the same signature and cannot be overloaded
...
cpp
// Demonstrates the principle of recursion by a
// function, which reads a line from the keyboard
// and outputs it in reverse order
...
get(c)
getput();
cout
...

getput();
}

2nd Execution

3rd Execution

getput()
{

...

// c = 'k'
getput();

cout
...

// c = '\n'
// No call of
// getput()
cout
...
put(c);

RECURSIVE FUNCTIONS



187

ᮀ Recursion
A function that calls itself is said to be recursive
...
But a break criterion is always necessary to avoid having the function call
itself infinitely
...

Recursion requires local objects to be created each time the function is called, and these
objects must not have access to any other local objects from other function calls
...


ᮀ A Sample Program
Let’s look at the principle of recursion by referring to the sample program opposite
...

The function getput() is first called by main() and reads a character from the keyboard, storing it in the local variable c
...

The chain of recursive function calls is terminated by the user pressing the Return
key
...
This outputs the second to last character,
and so on
...


ᮀ Practical Usage
The logic of various solutions to common problems results in a recursive structure, for
example, browsing directory trees, using binary trees for data management, or some sorting algorithms, such as the quick sort algorithm
...
However, always make sure
that sufficient memory is available for the stack
...
This ensures that all the source files
will be compiled and linked automatically
...
cpp

sum
...



...



...



...
Write the function sum() with four parameters that calculates the arguments provided and returns their sum
...

Returns:
The sum of type long
...
Test the function sum() by calling it by all three possible
methods
...

b
...
cpp and sum
...

Exercise 2
a
...
(Use Max instead of max to avoid a collision with other definitions of max
...

Can the function Max() also be called using arguments of the types
char, int, or long?
b
...

Can the function Max() still be called with two arguments of type
int?

Exercise 3
The factorial n! of a positive integer n is defined as
n! = 1*2*3
...

Argument: A number n of type unsigned int
...

Formulate two versions of the function, where the factorial is
a
...
calculated recursively
Test both functions by outputting the factorials of the numbers 0 to 20 as shown
opposite on screen
...

Arguments: The base of type double and the exponent of type int
...

For example, calling pow(2
...
53

=

2
...
5 * 2
...
625

This definition of the function pow()means overloading the standard function
pow(), which is called with two double values
...
Compare the result of your function with the result of the
standard function
...
The power x0 is defined as 1
...

2
...

3
...
0
...
In this case, your function should return the
value HUGE_VAL
...
h and represents a large double
value
...


SOLUTIONS

solutions





SOLUTIONS

Exercise 1
//
//
//
//

----------------------------------------------------sum_t
...

-----------------------------------------------------

#include
#include
#include
#include
using namespace std;
long sum( long a1, long a2, long a3=0, long a4=0);
int main()
// Several calls to function sum()
{
cout << " **** Computing sums ****\n"
<< endl;
srand((unsigned int)time(NULL)); // Initializes the
// random number generator
...
cpp
Defines the function sum()
-----------------------------------------------------

long sum( long a1, long a2, long a3, long a4)
{
return (a1 + a2 + a3 + a4);
}

191

192



CHAPTER 10

FUNCTIONS

Exercise 2
//
//
//
//

----------------------------------------------------max
...

------------------------------------------------------

//
//
//
//

As long as just one function Max() is defined, it can
be called with any arguments that can be converted to
double, i
...
with values of type char, int or long
...


#include
#include
using namespace std;
inline double Max(double x, double y)
{
return (x < y ? y : x);
}
inline char Max(char x, char y)
{
return (x < y ? y : x);
}
string header(
"To use the overloaded function Max()
...
0, x2 = 0
...
sync(); cin
...


SOLUTIONS

cout << line
<< "And once more with characters!"
<< endl;
cout << "Enter two characters:"
<< endl;
char c1, c2;
if( cin >> c1 && cin >> c2)
{
cout << "The greater character is " << Max(c1,c2)
<< endl;
}
else
cout << "Invalid input!" << endl;
cout << "Testing with int arguments
...
cpp
// Computes the factorial of an integer iteratively,
// i
...
using a loop, and recursively
...
get();
//

---

cout <<
<<
<<
<<

Recursive computation of factorial

----

setw(10) << "n" << setw(30) << "Factorial of n"
"
(Recursive solution)\n"
"
-----------------------------------------"
endl;

for( n = 0; n <= N_MAX; ++n)
cout << setw(10) << n << setw(30) << fact2(n)
<< endl;
cout << endl;
return 0;
}
long double fact1(unsigned int n)
// Iterative
{
// solution
...
0;
for( unsigned int i = 2; i <= n; ++i)
result *= i;
return result;
}
long double fact2(unsigned int n)
{
if( n <= 1)
return 1
...


SOLUTIONS

Exercise 4
// ----------------------------------------------------// power
...

// Overloads the standard function pow()
...
0;
int
exponent = 0;
cout << " **** Computing Integer Powers ****\n"
<< endl;
cout << "Enter test values
...
0;
if( base == 0
...
0;
else
return HUGE_VAL;
if( exp < 0)
{
base = 1
...
0;
for( int n = 1; n <= exp; ++n)
power *= base;
return power;
}



195

This page intentionally left blank

chapter

11

Storage Classes and
Namespaces
This chapter begins by describing storage classes for objects and
functions
...
Namespaces can be
used to avoid conflicts when naming global identifiers
...


The following storage class specifiers can be used
extern

static

auto

register

STORAGE CLASSES OF OBJECTS



199

When an object is declared, not only are the object’s type and name defined but also its
storage class
...
In addition, the storage
class delimits the part of the program in which the object can be accessed directly by its
name, the so-called object scope
...
A translation unit, also referred to as module, comprises the source file you are compiling and any header files you have included
...
The object is no longer visible once you have left
the code block
...
Only the
functions within this module can reference the object
...

The object is available throughout the program, providing a
common space in memory that can be referenced by any program function
...


Access to an object as defined by the object’s storage class is independent of any
access controls for the elements of a class
...


ᮀ Lifetime
Objects with block scope are normally created automatically within the code block that
defines them
...
The memory used for these objects is freed after leaving the
code block
...

However, it is possible to define objects with block scope that are available throughout the runtime of a program
...
When the
program flow re-enters a code block, any pre-existing conditions will apply
...
These objects are created when
a program is launched and are available until the program is terminated
...
These storage classes will be discussed individually in the following sections
...
cpp
// A filter to remove white-space characters
// at the ends of lines
...

Shorten the line
...


Source file 2
//
//
//
//
//
//

Cutline2
...

The string line has to be globally defined in another
source file
...
size();

// extern declaration

// Position after the
// last character
...
resize(++i);
}

// If no blank and
// no tab ->
// stop the loop
...


THE STORAGE CLASS extern



201

ᮀ Defining Global Objects
If an object is not defined within a function, it belongs to the extern storage class
...
External objects thus
allow you to exchange information between any functions without passing any arguments
...
The string line, which has a global definition, is used to
exchange data
...
This also applies to objects belonging to class
types, if not otherwise stipulated by the class
...
If you need to use an object before defining it or in another
module, you must first declare the object
...
The declaration makes the name and
type of the object known to the compiler
...


Example: extern long position;

// Declaration

This statement declares position as an external object of type long
...

A global object must be defined once, and once only, in a program
...
You will normally
declare the object before the first function in a source file or in a header file that you can
include when needed
...

Remember, if you declare the object within a code block, the object can only be used
within the same block
...
If you do initialize the object, you are defining that object!



NOTE
Global objects affect the whole program and should be used sparingly
...


202



CHAPTER 11



ST0RAGE CLASSES AND NAMESPACES

THE STORAGE CLASS static

// Passw1
...

// ----------------------------------------------------#include
#include
#include
#include
using namespace std;
long timediff(void);
static string secret = "ISUS";
static long maxcount = 3, maxtime = 60;

// Prototype
// Password
// Limits

bool getPassword()
// Enters and checks a password
...

bool ok_flag = false;
// For return value
string word;
// For input
int count = 0, time = 0;
timediff();
// To start the stop watch
while( ok_flag != true &&
++count <= maxcount)
// Number of attempts
{
cout << "\n\nInput the password: ";
cin
...

static long sec = 0;
// Time of last call
...

time( &sec);
// Reads new time
...

}

THE STORAGE CLASS static



203

ᮀ Static Objects
If an object definition is preceded by the static keyword, the object belongs to the
static storage class
...

Static objects are not placed on the stack, but are stored in the data area of a program
just like external objects
...
Two
conditions apply, depending on where the object is defined:
1
...




NOTE
In contrast to objects with an extern definition, the name of an external static object is unknown to
the linker and thus retains its private nature within a module
...
Definition within a code block
This means that the object is internal static, that is, the object is only visible
within a single block
...
On re-entering the block, you can continue to
work with the original object
...
If the
object is not initialized explicitly, a default value of 0 applies
...
Permission is refused
following three unsuccessful attempts or when 60 seconds have elapsed
...
Its value is zero
only when the function is first called
...


204



CHAPTER 11



ST0RAGE CLASSES AND NAMESPACES

THE SPECIFIERS auto AND register

Sample function with a register variable
//
//
//
//
//
//
//
//
//
//
//
//

StrToL
...

Argument:
A string
...

-------------------------------------------------The digits are interpreted with base 10
...

The conversion terminates when the end of the string is
reached or when a character that cannot be converted is
reached
...

for(i=0; i < str
...
size())
{
if( str[i] == '+' ) { vz = 1; ++i; }
if( str[i] == '-' ) { vz = ---1; ++i; }
}
// Sequence of digits -> convert to integer
for( ; i < str
...
The parameters of a function are also auto objects
...


Example: auto float radius; // Equivalent to:
// float radius;

When the program flow reaches the definition, the object is created on the stack, but in
contrast to a static type object, the object is destroyed on leaving the block
...
However, objects belonging to a class type are normally initialized with default values, which
can be specified in the class definition
...
In this case, the register keyword is used to
declare the object
...
In other words, it only makes sense
to define register variables if the variable is not too large, as in the case of types such
as char, short, int or pointers
...

However, the compiler can ignore the register keyword
...
If a program defines too many register variables in a code block, the
superfluous variables are placed in the auto storage class
...
This is useful if you need to perform calculations with a number contained in a string
...


206



CHAPTER 11



ST0RAGE CLASSES AND NAMESPACES

THE STORAGE CLASSES OF FUNCTIONS

ᮀ Example of a Program Structure
Source file 1
extern bool getPassword(void);

// Prototype

int main()
{
// The function permission(),
// but not the function timediff()
// can be called here
...


...

}

Source file 2
static long timediff(void);

// Prototype

bool getPassword(void)
// Definition
{
// timediff() can be called here
...


...

}
static long timediff(void)
{

...


...
Functions
with block scope are invalid: you cannot define a function within another function
...

External functions have program scope, whereas static functions have file scope
...

In a similar manner to external objects, external functions can be used at any position
in a program
...


Example: extern bool getPassword(void); // Prototype
As previously seen, you can omit the extern keyword, since functions belong to the
extern storage class by default
...


Example: static long timediff()
{


...
They can only be called in the source file that defines
them
...

If you need to call a static function before defining it, you must first declare the
function in the source file
...
The function timediff() is an auxiliary function and not designed to be called externally
...


208



CHAPTER 11



ST0RAGE CLASSES AND NAMESPACES

NAMESPACES

Defining namespaces
// namesp1
...

// ---------------------------------------------------#include
// Class string defined within
// namespace std
namespace MySpace
{
std::string mess = "Within namespace MySpace";
int count = 0;
// Definition: MySpace::count
double f( double);
// Prototype:
MySpace::f()
}
namespace YourSpace
{
std::string mess = "Within namespace YourSpace";
void f( )
// Definition of
{
// YourSpace::f()
mess += '!';
}
}
namespace MySpace
// Back in MySpace
...
0;
}
}
int MySpace::g( )
// Separate definition
{
// of MySpace::g()
return ++count;
}
#include
// cout,
...
2)
<< "\n---------------------" << std::endl;
YourSpace::f();
std::cout << YourSpace::mess << std::endl;
return 0;
}

NAMESPACES



209

Using global names in large-scale software projects can lead to conflicts, especially when
multiple class libraries are in operation
...
Within a namespace, you can use identifiers without needing to check
whether they have been defined previously in an area outside of the namespace
...

A normal namespace is identified by a name preceded by the namespace keyword
...


Example: namespace myLib
{
int count;
double calculate(double, int);
//
...

Elements belonging to a namespace can be referenced directly by name within the
namespace
...
To do so, place the scope resolution operator, ::,
before the element name
...
You can
also use the scope resolution operator :: to reference global names, that is, names
declared outside of any namespaces
...

This technique is useful when you need to access a global name that is hidden by an
identical name defined in the current namespace
...
You can reopen and expand
a namespace you defined previously at any point in the program
namespaces can be nested, that is, you can define a namespace within another
namespace
...


210



CHAPTER 11



ST0RAGE CLASSES AND NAMESPACES

THE KEYWORD using

Sample program
// namesp2
...

// ---------------------------------------------------#include
// Namespace std
void message()
// Global function ::message()
{
std::cout << "Within function ::message()\n";
}
namespace A
{
using namespace std; // Names of std are visible here
void message()
// Function A::message()
{
cout << "Within function A::message()\n";
}
}
namespace B
{
using std::cout;
//
void message(void);
//
}
void B::message(void)
//
{
cout << "Within function
}
int main()
{
using namespace std;
using B::message;

Declaring cout of std
...

cout << "\nCall of::message()" << endl;
::message();
// Global function
return 0;

}

THE KEYWORD using



211

You can simplify access to the elements of a namespace by means of a using declaration or
using directive
...
Just like
normal declarations, using declarations and using directives can occur at any part of
the program
...


Example: using myLib::calculate;

// Declaration

You can then call the function calculate() from the myLib namespace
...
7, 5);

This assumes that you have not previously used the name calculate in the same
scope
...


Example: using namespace myLib;
This statement allows you to reference the identifiers in the myLib namespace directly
...

If identical identifiers occur in the current namespace and an imported namespace,
the using directive does not automatically result in a conflict
...
In this case, you should use the scope resolution operator to resolve the situation
...
The using directive was used in previous examples to
import any required identifiers to the global scope:

Example: #include
using namespace std;

When developing large-scale programs or libraries, it is useful to declare the elements of
any proprietary namespaces in header files
...




CHAPTER 11



exe rc i se s

212

ST0RAGE CLASSES AND NAMESPACES

EXERCISES

Program listing for exercise 1
// scope
...


// 2
...

// 4
...


// 6
...


EXERCISES



213

Exercise 1
In general, you should use different names for different objects
...

The new declaration hides any object using the same name outside of the block
...

The program on the opposite page uses identical variable names in different
blocks
...
The names of types, functions, macros, and so on are
declared in the header files tool1
...
h for users of these libraries
...
In order to use
both libraries, you will need to define namespaces
...
h
...
h
...
h
...

To resolve potential naming conflicts, define the namespaces TOOL1 and
TOOL2 that include the relevant header files
...
cpp
// Tests an internal static variable
// --------------------------------------------------#include
#include
using namespace std;
double x = 0
...
0 )
{
x += fun();
cout << "
Within main(): "
<< setw(5) << x << endl;
}
return 0;
}
double fun()
{
static double x = 0;
cout << "
Within fun():"
<< setw(5) << x++;
return x;
}

EXERCISES



215

Exercise 3
Test your knowledge of external and static variables by reference to the
program on the opposite page
...
The function getPassword(), which checks password input, was introduced previously as an example of the use of static variables
...
cpp, which contains the function getPassword(), by
adding the function changePassword()
...
Save the modified source file as
Passw2
...

b
...

Only authorized users, that is, users that have access to the password, are
allowed to perform bookings
...
cpp
...
If the user enters the
correct password, he or she can change the password
...




NOTE
The modified password is only available during runtime as it is not stored permanently
...
h
Defining first function calculate() inline
...
h
Defining second function calculate() inline
...
cpp
Uses two "libraries" and tests name lookup conflicts
...
h"
}
namespace TOOL2
{
#include "tool2
...
5, y = 10
...
0;
cout << "Calling function of Tool1!" << endl;
res = TOOL1::calculate( x, y);
cout << "Result: " << res
<< "\n---------------------------------" << endl;
cout << "Calling function of Tool2!" << endl;
res = TOOL2::calculate( x, y);
cout << "Result: " << res << endl;
return 0;
}

Exercise 3
Screen output of the program
In
In
In
In

fun():
fun():
fun():
fun():

0
1
2
3

In
In
In
In

main():
main():
main():
main():

1
...
5
6
...
5

217

218



CHAPTER 11

ST0RAGE CLASSES AND NAMESPACES

Exercise 4
// ----------------------------------------------------// Passw2
...

// ----------------------------------------------------#include
#include
#include
#include
using namespace std;
static long timediff(void);
// Prototype
static string secret = "guest";
// Password
static long maxcount = 3, maxtime = 60; // Limits
bool getPassword()
{
// As before
...

}

// Read and verify a password
...

// As before
...

}
bool changePassword()
{
string word1,word2;

// Changes password
...
sync();
// Discards former input
cin >> setw(20) >> word1;

SOLUTIONS



if( word1
...
cpp
// Testing the functions getPassword() and
// changePassword()
...
three
// attempts within 60 seconds), the user can change it
...

bool changePassword(void);
// Change a password
...
sync(); cin
...
get() != '\n')
;
}
inline char getYesOrNo()
// Read character Y or N
...
sync(); cin
...
get(c);
c = toupper(c); // Permitting lower case letters also
...
get(choice);
choice = toupper(choice);
cls();
cout << header << endl; // Header
switch( choice)
{
case 'B':
// Booking
if( !getPassword() )
{
cout << "Access denied!" << endl;
go_on();
}
else
{ cout << "Welcome!\n\n"
<< "Do you want to change the password? (y/n)";
if( getYesOrNo() == 'Y')
{
if( changePassword() )
cout << "Password changed!" << endl;
else
cout << "Password unchanged!" << endl;
go_on();
}
// Place statements for booking here
...
In this
context, passing by reference and read-only access to arguments are
introduced
...
7,

&rx = x;
Object names:

The object in
memory


...
7


...
cpp
// Demonstrates the definition and use of references
...
7F;
int main()
{
float &rx = x;
// double &ref = x;

// Global

// Local reference to x
// Error: different type!

rx *= 2;
cout << "
x = " << x << endl
// x = 21
...
4
const float& cref = x;
// Read-only reference
cout << "cref = " << cref << endl;
// ok!
// ++cref;
// Error: read-only!
const string str = "I am a constant string!";
// str = "That doesn't work!"; // Error: str constant!
// string& text = str;
// Error: str constant!
const string& text = str;
// ok!
cout << text << endl;
// ok! Just reading
...
Defining a reference does not occupy additional memory
...
References are particularly useful as parameters and return values of functions
...
Given that T is a type, T&
denotes a reference to T
...
7;
float& rx = x;

// or:

float &rx = x;

rx is thus a different way of expressing the variable x and belongs to the type “reference
to float”
...
The & character, which indicates a reference,
only occurs in declarations and is not related to the address operator &! The address
operator returns the address of an object
...


Example: &rx

// Address of x, thus is equal to &x

A reference must be initialized when it is declared, and cannot be modified subsequently
...


ᮀ Read-Only References
A reference that addresses a constant object must be a constant itself, that is, it must be
defined using the const keyword to avoid modifying the object by reference
...


Example: int a;

const int& cref = a;

// ok!

The reference cref can be used for read-only access to the variable a, and is said to be a
read-only identifier
...
1415927;
Since the constant does not take up any memory space, the compiler creates a
temporary object which is then referenced
...
cpp
Demonstrating functions with parameters
of reference type
...
It is syntactically simpler to use references, although not always permissible
...
When a function is called,
a reference parameter is initialized with the object supplied as an argument
...


Example: void test( int& a) { ++a; }
Based on this definition, the statement
test( var);

// For an int variable var

increments the variable var
...

If an object is passed as an argument when passing by reference, the object is not
copied
...


ᮀ Comparison to Passing by Value
In contrast to a normal pass by value an expression, such as a+b, cannot be used as an
argument
...

Using references as parameters offers the following benefits:




arguments are not copied
...
Passing by value allows only one result as a return value, unless you
resort to using global variables
...


Example: void display( const string& str);
The function display() contains a string as an argument
...
Instead, str is simply a reference to the argument
...


226



CHAPTER 12



REFERENCES AND POINTERS

REFERENCES AS RETURN VALUE

Sample program
//
//
//
//

Ref3
...

--------------------------------------------------

#include
#include
using namespace std;
// Returns a
// reference to
// the minimum
...
1,

x2 = x1 + 0
...

cout << "x1 = " << x1 << "
"
<< "x2 = " << x2 << endl;
cout << "Minimum: " << y << endl;
++refMin( x1,
cout << "x1 =
<< "x2 =
++refMin( x1,
cout << "x1
<< "x2
refMin( x1,
cout << "x1
<< "x2
refMin( x1,
cout << "x1
<< "x2
return 0;

x2);
// ++x1, as x1 is minimal
" << x1 << "
"
// x1 = 2
...
6
x2);
// ++x2, because x2 is
// the minimum
...
1
= " << x2 << endl;
// x2 = 2
...
1;
// x1 = 10
...

= " << x1 << "
"
// x1 = 10
...
6
x2) += 5
...
0, because
// x2 is the minimum
...
1
= " << x2 << endl;
// x2 = 7
...


NOTE
The expression refMin(x1,x2) represents either the object x1 or the object x2, that is, the object
containing the smaller value
...
The function call then represents an object, and can be used just like an object
...
Pay attention to the following
point when returning references and pointers:
The object referenced by the return value must exist after leaving the function
...
This would destroy the string on leaving the function and the reference would point to an object that no longer existed
...
” Thus, calling
message()

represents a string type object, and the following statements are valid:
message() = "Let's go to the beer garden!";
message() += " Cheers!";
cout << "Length: " << message()
...
Then a new string is appended before the length of the referenced string is output in
the third statement
...


Example: const string& message();

// Read-only!

References are commonly used as return types when overloading operators
...
Refer to the chapters on overloading operators later in this book
for more details
...


228



CHAPTER 12



REFERENCES AND POINTERS

EXPRESSIONS WITH REFERENCE TYPE

Example: Operator << of class ostream
cout << "Good morning" << '!';

cout << "Good morning"

Reference to cout

<<'!';

Sample assignments of class string
// Ref4
...

// -------------------------------------------------#include
#include
#include
// For toupper()
using namespace std;
void strToUpper( string& );
// Prototype
int main()
{
string text("Test with assignments \n");
strToUpper(text);
cout << text << endl;
strToUpper( text = "Flowers");
cout << text << endl;
strToUpper( text += " cheer you up!\n");
cout << text << endl;
return 0;
}
void strToUpper( string& str) // Converts the content
{
// of str to uppercase
...
length();
for( int i=0; i < len; ++i)
str[i] = toupper( str[i]);
}

EXPRESSIONS WITH REFERENCE TYPE



229

Every C++ expression belongs to a certain type and also has a value, if the type is not
void
...


ᮀ The Stream Class Shift Operators
The << and >> operators used for stream input and output are examples of expressions
that return a reference to an object
...
This allows you to repeatedly use the << on the expression:
cout << "Good morning" << '!'

The expression is then equivalent to
(cout << " Good morning ") << '!'

Expressions using the << operator are composed from left to right, as you can see from
the table of precedence contained in the appendix
...
This allows
repeated use of the >> operator
...
These operators return a reference to the
operand on the left
...
In turn, the expression itself represents the object a
...
However, the
class definition stipulates the available operators
...


Example: string name("Jonny ");
name += "Depp";

//Reference to name

Since an expression of this type represents an object, the expression can be passed as
an argument to a function that is called by reference
...


230



CHAPTER 12



REFERENCES AND POINTERS

DEFINING POINTERS

Sample program
// pointer1
...

// -------------------------------------------------#include
using namespace std;
int var, *ptr;

// Definition of variables var and ptr

int main()
{
var = 100;
ptr = &var;

// Outputs the values and addresses
// of the variables var and ptr
...

var

100

456FD4

ptr

456FD4

456FD0


...
Linked lists or trees whose elements are
generated dynamically at runtime are typical examples
...

Using the address operator, &, for a given object creates a pointer to that object
...
A pointer points
to a memory address and simultaneously indicates by its type how the memory address
can be read or written to
...


ᮀ Pointer Variables
An expression such as &var is a constant pointer; however, C++ allows you to define
pointer variables, that is, variables that can store the address of another object
...
ptr can thus store the address of an int variable
...

Pointer types are derived types
...

In the above example T is an int type
...


Example: int a, *p, &r = a;

// Definition of a, p, r

After declaring a pointer variable, you must point the pointer at a memory address
...


ᮀ References and Pointers
References are similar to pointers: both refer to an object in memory
...
A pointer has its own memory address and can be manipulated by
pointing it at a new memory address and thus referencing a different object
...
3;
+= 4
...

Assign the value 12
...
5
...


Address and value of the variables x and px

px

x

Address
of px

Address of x
= value of px

Value of x

&px

&x
px

x
*px

Notes on addresses in a program






Each pointer variable occupies the same amount of space, independent of the
type of object it references
...
On a 32-bit computer, such as a PC, this is four bytes
...
This allows for efficient storage
management and the swapping of currently unused memory blocks to the hard
disk
...
Thus, the special
value 0 is used to indicate an error
...
A pointer containing the value NULL is
also called NULL pointer
...

As a programmer, you must always distinguish between the pointer ptr and the
addressed object *ptr
...

// Let ptr point to a
...
The assignment b = a; would
return the same result
...

The star character * used for defining pointer variables is not an operator but merely
imitates the later use of the pointer in expressions
...

The indirection operator * has high precedence, just like the address operator &
...
This also helps distinguish the
redirection operator from the binary multiplication operator *, which always takes two
operands
...
The
term L-value occurs commonly in compiler error messages and is derived from the assignment
...

Expressions other than an L-value are often referred to as R-values
...
However, a constant or an
expression, such as x + 1, is an R-value
...
Given a pointer variable p, both p and *p are L-values, as
*p designates the object to which p points
...
cpp
// Definition and call of function swap()
...

// ---------------------------------------------------#include
using namespace std;
void swap( float *, float *);

// Prototype of swap()

int main()
{
float x = 11
...
2F;

...


...


...

}
// p1 = &x
void swap( float *p1, float *p2)
{
float temp;
// Temporary variable
temp = *p1;
*p1 = *p2;
*p2 = temp;
}

// At the above call p1 points
// to x and p2 to y
...
The function that is called is then passed a copy of the object (passing by value)
the parameter in question is a reference
...


In the first case, the argument passed to the function cannot be manipulated by the
function
...
However, there is a third way of passing by reference—passing pointers to the function
...

If, for example, the function func() requires the address of an int value as an argument, you can use the following statement

Example: long func( int *iPtr )
{
// Function block
}

to declare the parameter iPtr as an int pointer
...

In the program on the opposite page, the function swap() swaps the values of the
variables x and y in the calling function
...

The parameters p1 and p2 in swap() are thus declared as float pointers
...
When the function
manipulates the expressions *p1 and *p2, it really accesses the variables x and y in the
calling function and exchanges their values
...

// Find the error!
void swap(float *p1, float *p2)
{
float *temp;

// Temporary variable

temp = p1;
p1
= p2;
p2
= temp;
}

Solutions of quadratic equations
The quadratic equation: a*x2 + b*x + c = 0 has real solutions:
x12 = (-b ± √(b2 - 4ac)) / 2a

if the discriminant satisfies: b2 -4ac >= 0
If the value of (b2 - 4ac) is negative, no real solution exists
...
5,
X1 = 3
...
5 = 0
x2 - 6x + 9 = 0
2x2 + 2 = 0

none

x2 = -0
...
0

EXERCISES



237

Exercise 1
What happens if the parameter in the sample function strToUpper() is
declared as a string& instead of a string?
Exercise 2
Write a void type function called circle()to calculate the circumference and
area of a circle
...


NOTE
Given a circle with radius r:
Area = π * r * r and circumference = 2 * π * r where π = 3
...
5, 1
...
5,
...
0
...
The version of the function swap() opposite can be compiled without
producing any error messages
...
What is wrong?
b
...
Then write and test a version of the function swap() that uses
references instead of pointers
...
The formula for calculating quadratic equations is shown opposite
...

false, if no real solution is available, otherwise true
...




CHAPTER 12



solutions

238

REFERENCES AND POINTERS

SOLUTIONS

Exercise 1
The call to function strToUpper() is left unchanged
...
e
...

Thus, only a local copy of the string is changed in the function, but the string in
the calling function remains unchanged
...
cpp
// Defines and calls the function circle()
...
5,
endRadius
= 10
...
5;
string header = "\n
line( 50, '-');

// Start, end and
// step width of
// the table

***** Computing Circles ***** \n",

int main()
{
double rad, circuit, plane;
cout << header << endl;
cout << setw(10) << "Radius"
<< setw(20) << "Circumference"
<< setw(20) << "Area\n" << line << endl;
cout << fixed;
// Floating point presentation
for( rad = startRadius;
rad < endRadius + step/2; rad += step)
{
circle( rad, circuit, plane);
cout << setprecision(1)<< setw(8) << rad
<< setprecision(5)<< setw(22) << circuit
<< setw(20) << plane <}
return 0;
}

SOLUTIONS



// Function circle(): Compute circumference and area
...
1415926536;
u = 2 * pi * r;
f = pi * r * r;
}

Exercise 3
// ---------------------------------------------------// swap
...

// 1
...
version: parameters with reference type
...
1F;
float y = 22
...


cout << "x and y after 1
...


cout << "x and y after 2
...


239

240



CHAPTER 12

REFERENCES AND POINTERS

void swap(float& a, float& b)
{
float temp;
temp = a;
a
= b;
b
= temp;

// Reference version
// Temporary variable

// For above call
// a equals x and b equals y

}

Exercise 4
//
//
//
//
//
//
//
//

---------------------------------------------------quadEqu
...

----------------------------------------------------

#include
#include
#include
#include
using namespace std;

// For the square root sqrt()

string header =
" *** Solutions of Quadratic Equations ***\n",
line( 50, '-');
// ----- Prototypes ----// Computing solutions:
bool quadEquation( double a, double b, double c,
double* x1Ptr, double* x2Ptr);
// Printing the equation and its solutions:
void printQuadEquation( double a, double b, double c);
int main()
{
cout << header << endl;
printQuadEquation( 2
...
0, -1
...
0, -6
...
0);
printQuadEquation( 2
...
0, 2
...
0, x2 = 0
...
\n\n";
cin
...

// Returns: true, if a solution exists,
//
otherwise false
...


*x1Ptr = (-b + help) / (2*a);
*x2Ptr = (-b - help) / (2*a);
return_flag = true;
}
return return_flag;
}

241

This page intentionally left blank

chapter

13

Defining Classes
This chapter describes how classes are defined and how instances of
classes, that is, objects, are used
...


243

244



CHAPTER 13



DEFINING CLASSES

THE CLASS CONCEPT

Real World
A Car

Abstraction

Class CAR

Properties (Data Members):
Date when built
Capacity (PS)
Serial number

...


Instantiation

Objects
car1

car2

Properties:
Date when built = 1990
Capacity = 100
Chassis number = 11111

...


Methods

...


•••

THE CLASS CONCEPT



245

Classes are the language element in C++ most important to the support object-oriented
programming (OOP)
...


ᮀ Data Abstraction
Humans use abstraction in order to manage complex situations
...
Classes allow more direct use of the
results of this type of abstraction in software development
...
In object-oriented programming,
analysis comprises identifying and describing objects and recognizing their mutual relationships
...

In C++, a class is a user-defined type
...
Classes are simply patterns used to instantiate, or create, objects of the class
type
...


ᮀ Data Encapsulation
When you define a class, you also specify the private members, that is, the members that
are not available for external access, and the public members of that class
...

Access to object data is rarely direct, that is, object data is normally declared as private and then read or modified by methods with public declarations to ensure correct
access to the data
...
If needed, the internal structure of the program data can even be modified
...
This
allows you to enhance an application by programming an improved class version without
changing a single byte of the application
...
This describes the concept of data
encapsulation concisely
...
h
// Defining the class Account
...

#define _ACCOUNT_
#include
#include
using namespace std;
class Account
{
private:
string name;
unsigned long nr;
double balance;

// Sheltered members:
// Account holder
// Account number
// Account balance

public:
//Public interface:
bool init( const string&, unsigned long, double);
void display();
};
#endif

//

_ACCOUNT_

DEFINING CLASSES



247

A class definition specifies the name of the class and the names and types of the class
members
...
The data
members and methods are then declared in the subsequent code block
...
At the same time, the class members are divided into:



private members, which cannot be accessed externally
public members, which are available for external access
...

The opposite page shows a schematic definition of a class
...
This provides for data encapsulation
...
The data members, such as the name of the account holder, the account number, and the account balance, are declared as private
...

The labels private: and public: can be used at the programmer’s discretion
within a class:




you can use the labels as often as needed, or not at all, and in any order
...
If you omit both the private
and public labels, all the class members are assumed to be private
...
These rules often reflect the target
platform and the class libraries used
...
Class names
begin with an uppercase letter and member names with a lowercase letter
...
A member of another class
could therefore also be named display()
...
cpp
// Defines methods init() and display()
...
h"
// Class definition
#include
#include
using namespace std;
// The method init() copies the given arguments
// into the private members of the class
...
size() < 1)
// No empty name
return false;
name
= i_name;
nr
= i_nr;
balance = i_balance;
return true;
}
// The method display() outputs private data
...
Only then can the objects
of the class be used
...


Syntax:

type class_name::function_name(parameter_list)
{

...

Within a method, all the members of a class can be designated directly using their
names
...
In particular, methods belonging
to the same class can call each other directly
...
Thus, private members are completely controlled by the class
...
To allocate memory, you must define an object
...


ᮀ Modular Programming
A class is normally defined in several source files
...
If you place the definition of the class Account in the
file Account
...

Methods must always be defined within a source file
...
cpp, for example
...
Separating classes from application programs facilitates re-use of classes
...

When the project is compiled and linked, modified source files are automatically re-compiled and linked to the application program
...
22

current
name

"Dylan, Bob"

nr

87654321

balance

–1300
...
An object is also referred to as an instance of a class
...


Syntax:

class_name object_name1 [, object_name2,
...


Memory is now allocated for the data members of the current object
...


ᮀ Objects in Memory
If multiple objects of the same class type are declared, as in

Example: Account current, savings;
each object has its own data members
...
However, these data members occupy a different position in
memory than the data members belonging to current
...
Only one instance of the machine code
for a method exists in memory—this applies even if no objects have been defined for the
class
...
This results in the memory content as shown on the opposite
page, when the method init() is called for each object with the values shown
...

Each member object is thus defined but not explicitly initialized
...
The initial values of the members nr
and balance are unknown, however
...

You can define exactly how an object is created and destroyed
...
Constructors are specifically responsible for initializing objects—more details are given later
...
cpp
// Uses objects of class Account
...
h"
int main()
{
Account current1, current2;
current1
...
99);
current1
...
balance += 100; // Error: private member
current2 = current1;
current2
...

// ok

// New values for current2
current2
...
40);
current2
...
display();
return 0;
}

//
//
//
//
//

To use a reference:
mtr is an alias name
for object current1
...


USING OBJECTS



253

ᮀ Class Member Access Operator
An application program that manipulates the objects of a class can access only the public members of those objects
...


Syntax:

object
...


Example: Account current;
current
...
99);

The expression current
...
This method is called with three arguments for current
...


Example: current
...
nr
= 1234567;
current
...
99;

// Error:
// private
// members

Access to the private members of an object is not permissible outside the class
...


Example: cout << current
...
display();

// Error
// ok

The method display() displays all the data members of current
...
The statement
display();

would result in an error message, since there is no global function called display()
...

However, the source and target objects must both belong to the same class
...


Example: Account current1, current2;
current2
...
0);
current1 = current2;

This copies the data members of current2 to the corresponding members of
current1
...
cpp
// Uses pointers to objects of class Account
...
h"
// Includes ,
bool getAccount( Account *pAccount);
// Prototype
int main()
{
Account current1, current2, *ptr = ¤t1;
ptr->init("Cheer, Mary",
3512345, 99
...
init(
...
display()
Let ptr point to current2
Input and output a new
account
...

bool getAccount( Account *pAccount )
{
string name, line(50,'-');
// Local variables
unsigned long nr;
double startcapital;
cout << line << '\n'
<< "Enter data for a new account: \n"
<< "Account holder: ";
if( !getline(cin,name) || name
...
You can assign this
address to a suitable pointer
...
5);
Account *ptrAccount = &savings;

This defines the object savings and a pointer variable called ptrAccount
...
This makes
*ptrAccount the object savings itself
...
display();
to call the method display() for the object savings
...
has higher precedence than the * operator
...


Syntax:

objectPointer->member

This expression is equivalent to
(*objectPointer)
...


Example: ptrAccount->display();
This statement calls the method display() for the object referenced by ptrAccount,
that is, for the object savings
...

The difference between the class member access operators
...


ᮀ The Sample Program
Pointers to objects are often used as function parameters
...
The
example on the opposite page illustrates this point
...
When called, the address of the account is passed:
getAccount(ptr) // or: getAccount(¤t1)

The function can then use the pointer ptr and the init() method to write new data
to the referenced object
...
cpp
// Defines and uses a struct
...

double sales;
// Sales per month
...
name
<< right << setw(10) << v
...
name
= "Strom, Rita";
rita
...
37;
john
...
sales = 23001
...
sales += 1700
...
sales + john
...

// Who gets the
if( john
...
sales)
// most sales?
ptr = &rita;
cout << "\nSalesman of the month: "
<< ptr->name << endl;
// Representative's name
// pointed to by ptr
...
Extensive data such as the data for the articles in an automobile manufacturer’s stocks can be organized for ease of viewing and stored in files
...
Thus, you can use the class keyword to
define the structure of a record in C++
...
The above definition of Date with
the members day, month, and year is thus equivalent to:

Example: struct Date { short month, day, year; };

ᮀ The Keywords

class

and

struct

You can also use the keyword struct to define a class, such as the class Account
...


...
In contrast to a
class defined using the class keyword, all the class members are public unless a private label is used
...


Example: Date future;
future
...


Example: Date birthday = { 1, 29, 1987};
The first element in the list initializes the first data member of the object, and so on
...
cpp
// Defines and uses a union
...
word() = 256;
cout << "\nWord:
" << (int)wb
...
lowByte()
<< "\nHigh-byte: " << (int)wb
...
However, a union is a class whose members are stored in the same memory space
...
Of course, a union cannot
store various data members at the same address simultaneously
...


ᮀ Definition
Syntactically speaking, a union is distinguished from a class defined as a class or
struct only by the keyword union
...
The union
Number can be used to store either integral or floating-point numbers
...
This
is similar to the default setting for structures
...


Example: number1
...
n *= 3;
number2
...
77;

// and multiply by 3
...
This is normally achieved using an additional type field that identifies the current
content
...
If we look at our example, the union
Number, this size is defined by the double member, which defaults to 8 ==
sizeof(double) byte
...




CHAPTER 13



exercise

260

DEFINING CLASSES

EXERCISE

Struct tm in header file ctime
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};

//
//
//
//
//
//
//
//
//

0 - 59(60)
0 - 59
0 - 23
Day of month: 1 - 31
Month: 0 - 11 (January == 0)
Years since 1900 (Year - 1900)
Weekday: 0 - 6 (Sunday == 0)
Day of year: 0 - 365
Flag for summer-time

Sample calls to functions time( ) and localtime( )
#include
#include
using namespace std;
struct tm *ptr;
time_t sec;

...

// For seconds
...

To initialize a struct of
type tm and return a
pointer to it
...
day of the year " << ptr->tm_year
<< endl;

...



Define the class Date for this purpose using three integral data members
for day, month, and year
...

Implement the methods for the class Date in a separate source file:
1
...

2
...
A range check is not required
at this stage, but will be added later
...
The method init() without parameters writes the current date to the
corresponding members
...
The type time_t is defined as long in ctime
...
This value can be passed to the function localtime() that
converts the number of seconds to the local type tm date and returns
a pointer to this structure
...
To this end, define two objects for the class and
display the current date
...




CHAPTER 13

DEFINING CLASSES



solution

262

SOLUTION

//
//
//
//

---------------------------------------------------date
...

----------------------------------------------------

#ifndef _DATE_
#define _DATE_
class Date
{
private:
short month, day, year;

// Avoid multiple inclusion
...
cpp
Implementing the methods of class Date
...
h"
#include
#include
using namespace std;
// --------------------------------------------------void Date::init(void)
// Get the present date and
{
// assign it to data members
...

time_t sec;
// For seconds
...

// Initialize a struct of
// type tm and return a
// pointer to it
...
cpp
// Using objects of class Date
...
h"
#include
using namespace std;
int main()
{
Date today, birthday, aDate;
today
...
init( 12, 11, 1997);
cout << "Today's date: ";
today
...
print();
cout << "----------------------------------\n"
"Some testing outputs:" << endl;
aDate = today;
aDate
...
init( 1, 5, 2000);
aDate
...

// Writing to aDate
...
print();

return 0;
}



263

This page intentionally left blank

chapter

14

Methods
This chapter describes


how constructors and destructors are defined to create and
destroy objects



how inline methods, access methods, and read-only methods
can be used



the pointer this, which is available for all methods, and



what you need to pay attention to when passing objects as
arguments or returning objects
...
h
// Defining class Account with two constructors
...
cpp:
Account::Account( const string& a_name,
unsigned long a_nr, double a_state)
{
nr
= a_nr;
name = a_name;
state = a_state;
}
Account::Account( const string& a_name )
{
name = a_name;
nr = 1111111; state = 0
...

The programmer must ensure that the variable is initialized with suitable values
...
Non-initialized objects can lead to
serious runtime errors in your programs
...
This ensures that objects will always have valid data to work on
...


ᮀ Declaration
Constructors can be identified by their names
...


Constructors are normally declared in the public section of a class
...

Constructors can be overloaded, just like other functions
...
This allows for different methods of object initialization
...
The class now has two constructors
...
If the number of arguments is smaller than
the number of data members, the remaining members can be initialized using default values
...


268



CHAPTER 14



METHODS

CONSTRUCTOR CALLS

Sample program
// account2_t
...

// --------------------------------------------------#include "account
...
99 ),
save("Lucky, Luke");
Account depot;

giro
...
display();

// Error: no default constructor
//
defined
...
0);
save = temp;
// ok: Assignment of
//
objects possible
...
display();
// Or by the presently available method init():
save
...
0);
save
...
For this reason,
a constructor does not have a return type
...


ᮀ Initialization
When an object is defined, initial values can follow the object name in parentheses
...
After allocating sufficient memory for the object, the constructor is
called
...


Example: account nomoney("Poor, Charles");
This statement calls the constructor with one parameter for the name
...

If the compiler is unable to locate a constructor with a suitable signature, it will not
create the object but issue an error message
...
0); // Error!
The class Account does not contain a constructor with two parameters
...


Example: account nomoney = "Poor, Charles";
This statement is equivalent to the definition in the example before last
...
For
example, int i(0); is equivalent to int i =0;
...
The default constructor is only called if an object definition does not explicitly initialize the object
...

If a class does not contain a constructor definition, the compiler will create a minimal
version of the default constructor as a public member
...
By contrast, if a class contains at least one constructor, a
default constructor must be defined explicitly, if it is needed
...


270



CHAPTER 14



METHODS

DESTRUCTORS

Sample program
// demo
...

// --------------------------------------------------#include
#include
using namespace std;
int count = 0;
// Number of objects
...
object!\n"
}
Demo:: ~Demo()
// Defining the destructor
{
cout << "I am the destructor of " << name << '\n'
<< "The " << count << "
...
" << endl;
Demo firstLocalObject("the 1
...
local object");
static Demo staticObject("the static object");
cout << "\nLast statement within the inner block"
<< endl;
}
cout << "Last statement in main()
...

The tasks involved in cleaning up include releasing memory and closing files
...


ᮀ Declaration and Definition
Destructors are declared in the public section and follow this syntax:

Syntax:

∼class_name(void);

Just like the constructor, a destructor does not have a return type
...
Each class thus
has one destructor only
...

It is important to define a destructor if certain actions performed by the constructor
need to be undone
...
The destructor in the Account class has no specific tasks to perform
...
The first data member to be created is therefore
cleaned up last
...


ᮀ Calling Destructors
A destructor is called automatically at the end of an object’s lifetime:



for local objects except objects that belong to the static storage class, at the
end of the code block defining the object
for global or static objects, at the end of the program
...


272



CHAPTER 14



METHODS

INLINE METHODS

Sample class Account
// account
...
0)
{
name = a_name; nr = a_nr; state = a_state;
}
~Account(){ } // Dummy destructor: implicit inline
void display();

};
// display() outputs data of class Account
...
This is the only way to ensure data encapsulation and class functionality
...
In
fact, saving a re-entry address and jumping to the called function and back into the calling function can take more time than executing the function itself
...


ᮀ Explicit and Implicit inline Methods
Methods can be explicitly or implicitly defined as inline
...
You simply need to place the
inline keyword before the method name in the function header when defining the
method
...

}

Since the compiler must have access to the code block of an inline function, the
inline function should be defined in the header containing the class definition
...
Methods of this type are known as
implicit inline methods, although the inline keyword is not used
...
This point is illustrated by the new definition of the Account
class opposite
...
The constructor has a default value for each argument, which means that we also have a default
constructor
...


Example: Account temp;
Although we did not explicitly supply values here, the object temp was correctly initialized by the default constructor we defined
...
h
// Class Account with set- and get-methods
...
0)
{ name = a_name; nr = a_nr; state = a_state; }
∼Account(){ }
// Access methods:
const string& getName() { return name; }
bool
setName( const string& s)
{
if( s
...

#endif
// _ACCOUNT_

ACCESS METHODS



275

ᮀ Accessing Private Data Members
An object’s data members are normally found in the private section of a class
...

Access methods offer a far more useful way of accessing the private data members
...
If the
access methods were defined as inline, access is just as efficient as direct access to the
public members
...
You can now use the
getName(), getNr(), getState()

methods to read the individual data members
...
Direct access for write operations could
be possible otherwise
...


This allows you to define a new balance, as follows:

Example: save
...
0);

ᮀ Access Method Benefits
Defining access methods for reading and writing to each data member may seem like a
lot of work—all that typing, reams of source code, and the programmer has to remember
the names and tasks performed by all those methods
...
There are
two important issues:




Access methods can prevent invalid access attempts at the onset by performing
sanity checks
...

Access methods also hide the actual implementation of a class
...
If you detect
that a new data structure will allow more efficient data handling, you can add
this modification to a new version of the class
...
You simply recompile the application program
...
h
// Account class with read-only methods
...
// as before

Sheltered members
before
Public interface
destructor

// Get-methods:
const string& getName() const { return name; }
unsigned long getNr()
const { return nr; }
double
getState() const { return state; }
// Set-methods:

...

inline void Account::display() const
{
cout << fixed << setprecision(2)
<< "--------------------------------------\n"
<< "Account holder:
" << name << '\n'
<< "Account number:
" << nr
<< '\n'
<< "Account state:
" << state << '\n'
<< "--------------------------------------\n"
<< endl;
}
#endif
// _ACCOUNT_

const OBJECTS AND METHODS



277

ᮀ Accessing const Objects
If you define an object as const, the program can only read the object
...


Example: const Account inv("YMCA, FL", 5555, 5000
...
This also means that methods such
as setName() cannot be called for this object
...

The reason for this is that the compiler cannot decide whether a method performs
write operations or only read operations with data members unless additional information is supplied
...
To identify a method as read-only, append the const
keyword in the method declaration and in the function header for the method definition
...


Example: cout << "Account number: " << inv
...

The compiler issues an error message if a read-only method tries to modify a data
member
...


ᮀ const and Non-const Versions of a Method
Since the const keyword is part of the method’s signature, you can define two versions
of the method: a read-only version, which will be called for constant objects by default,
and a normal version, which will be called for non-const objects
...
cpp
// Using standard methods
...

cd4 = cd2;
// Assignment!
string line( 70,'-');
line += '\n';
cout << line << left
<< setw(20) << "Interpreter" << setw(30) << "Title"
<< "Length (Min:Sec)\n" << line << endl;
printLine(cd3);
// Call by value ==>
printLine(cd4);
// Copy constructor!
return 0;
}
void printLine( CD cd)
{
cout << left << setw(20) << cd
...
getTitle()
<< right << setw(5) << cd
...
getSeconds() % 60 << endl;
}

STANDARD METHODS



279

Every class automatically contains four standard methods:





the default constructor
the destructor
the copy constructor and
the assignment
...
As illustrated by
the sample class Account, the compiler only uses the pre-defined default constructor if
no other constructor is available
...


ᮀ Copy Constructor
The copy constructor initializes an object with another object of the same type
...


Example: Account myAccount("Li, Ed", 2345, 124
...
Each member is copied individually, that is, the following
initialization process takes place:
yourAccount
...
name;
yourAccount
...
nr;
yourAccount
...
state;

The copy constructor is also called when an object is passed to a function by value
...


ᮀ Assignment
Assignment has been used in several previous examples
...


Example: hisAccount = yourAccount;
The data members of the yourAccount object are copied to the corresponding members of hisAccount in this case also
...

Later in the book, you will be introduced to situations where you need to define the
copy constructor or an assignment yourself, and the necessary techniques will be discussed
...
h
// The class DayTime represents the time in
// hours, minutes and seconds
...
)
hour = minute = second = 0; // hour is equivalent
}
// to this->hour etc
...
asSeconds();
}
// this->asSeconds() < t
...
A method will always reference the object with which it was called
...

The address of the current object is available to the method via the constant pointer
this
...
As this is a constant pointer, it cannot be redirected
...


ᮀ Using the this Pointer
You can use the this pointer within a method to address an object member as follows:

Example: this->data

// Data member: data
// Calling member function

this->func()

The compiler implicitly creates an expression of this type if only a member of the current
object is supplied
...
However, the above statement would be invalid for a readonly method
...
This point is illustrated by the sample method
setTime() on the opposite page
...
This situation often occurs when the current object needs to be returned as a copy
or by reference
...
h"

...

depart2
...
isLess( depart2) )
cout << "\nThe 1st plane takes off earlier" << endl;

...
h"
// Defines the global function swap():
void swap( DayTime& t1, DayTime& t2)
// Two
{
// parameters!
DayTime temp(t1); t1 = t2; t2 = temp; // To swap
}
// t1 and t2
...
g
...

swap( arrival1, arrival2);
// To swap

...

public:
void swap( DayTime& t)
// One parameter!
{
// To swap *this and t:
DayTime temp(t); t = *this; *this = temp;
}
};
// A call (e
...
in function main()):
#include "DayTime
...

arrival1
...


PASSING OBJECTS AS ARGUMENTS



283

ᮀ Passing by Value
As you already know, passing by value copies an object that was passed as an argument to
the corresponding parameter of a function being called
...


Example: bool isLess( DayTime t) const;
When the method isLess() is called, the copy constructor executes and initializes the
created object, t, with the argument
...
isLess( depart2)

// Copy constructor

The function uses a copy of the object depart2
...


ᮀ Passing by Reference
The overhead caused by creating and cleaning up objects can be avoided by passing arguments by reference
...


Example: bool isLess( const DayTime& t) const;
This new declaration of the isLess() method is preferable to the previous declaration
...
However, isLess() no
longer creates an internal copy, but accesses directly the object being passed
...


ᮀ Methods Versus Global Functions
Of course, it is possible to write a global function that expects one object as an argument
...
Instead, you would normally define a method for the
class and the method would perform the task in hand
...

A different situation occurs where operations with at least two objects need to be performed, such as comparing or swapping
...
However, the function could only
access the public interface of the objects
...

The major advantage of a globally defined function is its symmetry
...
This means that conversion rules
are applied to both arguments when the function is called
...
h"
#include
using namespace std;

// Functions time(), localtime()

const DayTime& currentTime()
// Returns the
{
// present time
...

// Initializes the struct
struct tm *time = localtime(&sec); // tm with it
...
setTime( time->tm_hour, time->tm_min,
time->tm_sec );
return curTime;
}

Sample program
// DayTim_t
...
h"
// Class definition
#include
using namespace std;
const DayTime& currentTime();

// The current time
...
print();
DayTime now(currentTime());
// Copy constructor
cout << "\nThe current time is ";
now
...
isLess( now) )
cout << "already begun!\n" << endl;
else
cout << "not yet begun!\n" << endl;
return 0;
}

RETURNING OBJECTS



285

A function can use the following ways to return an object as a return value: It can create
a copy of the object, or it can return a reference or pointer to that object
...


Example: DayTime startMeeting()
{
DayTime start;

...
setTime( 14, 30);
return( start);
}

On exiting the function, the local object start is destroyed
...


ᮀ Returning a Reference
Of course, it is more efficient to return a reference to an object
...

If this is the case, the object is destroyed on exiting the function and the returned reference becomes invalid
...

The global function currentTime() on the opposite page exploits this option by
returning a reference to the current time that it reads from the system each time the
function is called
...
In order to output the time, an
additional method, print(), was added to the class
...
In this
case too, you must ensure that the object still exists after exiting the function
...
// Unchanged
return &curTime;

}



CHAPTER 14



exercise s

286

METHODS

EXERCISES

Class Article
Private members:
Type
Article number:
Article name:
Sales price:

long
string
double

Public members:
Article(long, const string&, double);
~Article();
void print();
// Formatted output
set- and get-methods for any data member

Output from constructor
An object of type Article
...

This is the
...


Output from destructor
The object of type Article
...

There are still
...


EXERCISES



287

Exercise 1
A warehouse management program needs a class to represent the articles in
stock
...
Store the class definition for Article in a
separate header file
...

Access methods for the data members are to be defined as inline
...
If a negative price is passed as an argument,
the price must be stored as 0
...

Implement the constructor, the destructor, and the method print() in a
separate source file
...

The constructor must use the arguments passed to it to initialize the data
members, additionally increment the global counter, and issue the message
shown opposite
...

The method print() displays a formatted object on screen
...




The application program (again use a separate source file) tests the Article class
...
A global object and a local object in the main function
...
Two local objects in a function test() that is called twice by main()
...
The function test() displays
these objects and outputs a message when it is terminated
...
Additionally, call
the access methods to modify individual data members and display the
objects on screen
...
Note the order in which constructors and destructors are called
...
The counter for the number of objects is negative after
running the program
...
Thus, the operators >>
and << , just as all manipulators, are available
...

#include
// Class stringstream
#include
// Manipulators
double x = 12
...

Add to the stream
...


Notices for exercise 3
■ A year is a leap year if it is divisible by 4 but not by 100
...
February has 29 days in a leap year
...


EXERCISES



289

Exercise 2
In the exercises for chapter 13, an initial version of the Date class containing
members for day, month, and year was defined
...
The methods are shown on the opposite page
...
The default constructor uses default values,
for example, 1
...
1, to initialize the objects in question
...

The constructor and the setDate() method with three parameters do
not need to perform range checking
...

The methods isEqual() and isLess() enable comparisons with a date
passed to them
...
g
...
You will therefore need
to convert any numerical values into their corresponding decimal strings
...
In addition to the cin
and cout streams, with which you are already familiar, so-called string
streams with the same functionality also exist
...
Instead, the target, or source, is a buffer in main memory
...

Use an application program that calls all the methods defined in the class
to test the Date class
...
To avoid
this issue, add range checking functionality to the class
...







First, write a function called isLeapYear() that belongs to the bool
type and checks whether the year passed to it is a leap year
...
h
...
The constructor can call setDate()
...
To do so, and to test setDate(
...




CHAPTER 14



solutions

290

METHODS

SOLUTIONS

Exercise 1
// ---------------------------------------------------// article
...

// ---------------------------------------------------#ifndef _ARTICLE_
#define _ARTICLE_
#include
using namespace std;
class Article
{
private:
long nr;
string name;
double sp;

// Article number
// Article name
// Selling price

public:
Article( long nr=0, const string& name="noname",
double sp=0
...
size() < 1)
return false;
name = s;
return true;
}
void setNr( long n) { nr = n; }
void setSP(double v)
{
sp = v > 0
...
0;
}
};
#endif

// _ARTICLE_

// No empty name

// No negative price

SOLUTIONS

// -----------------------------------------------------// article
...

// Screen output for constructor and destructor calls
...
h"
// Definition of the class
#include
#include
using namespace std;
// Global counter for the objects:
int count = 0;
// -----------------------------------------------------// Define constructor and destructor:
Article::Article( long nr, const string& name, double sp)
{
setNr(nr);
setName(name);
setSP(sp);
++count;
cout << "Created object for the article " << name
<< "
...
article!\n"
}
Article::~Article()
{
cout << "Cleaned up object for the article " << name
<< "
...

void Article::print()
{
long savedFlags = cout
...

cout << fixed << setprecision(2)
<< "-----------------------------------------\n"
<< "Article data:\n"
<< " Number
...
: " << name << '\n'
<< " Sales price: " << sp
<< '\n'
<< "-----------------------------------------"
<< endl;
cout
...

cout << " --- Go on with return --- ";
cin
...
cpp
// Tests the Article class
...
h"
// Definition of the class
#include
#include
using namespace std;
void test();
// -- Creates and destroys objects of Article class -Article Article1( 1111,"volley ball", 59
...
\n" << endl;
Article Article2( 2222,"gym-shoes", 199
...
print();
Article2
...
setNr( 2233);
shoes
...
setSP( shoes
...
0);
cout << "\nThe
shoes
...
" << endl;
second call to test()
...
\n" << endl;

}
void test()
{
Article shirt( 3333, "T-Shirt", 29
...
print();
static Article net( 4444, "volley ball net", 99
...
print();
cout << "\nLast statement in function test()"
<< endl;
}

SOLUTIONS



293

Answer to the supplementary question:
The copy constructor is called on each “passing by value,” although this
constructor has not been defined explicitly
...

However, the explicitly defined destructor, which decrements the counter, is still
called for each object
...
h
// Defining class Date with optimized
// functionality, e
...
range check
...

#define _DATE_
#include
using namespace std;
class Date
{
private:
short month, day, year;
public:
Date()
{ month = day = year = 1;

// Default constructor
}

Date( int month, int day, int year)
{
if( !setDate( month, day, year) )
month = day = year = 1; // If date is invalid
}
void setDate();
// Sets the current date
bool setDate( int month, int day, int year);
int getMonth() const { return month; }
int getDay()
const { return day;
}
int getYear() const { return year; }
bool isEqual( const Date& d) const
{
return month == d
...
day
&& year == d
...
year)
return
else if( month != d
...
year;
month < d
...
day;

inline bool isLeapYear( int year)
{
return (year%4 == 0 && year%100 != 0) || year%400 == 0;
}
#endif
// _DATE_

// -----------------------------------------------------// Date
...

// -----------------------------------------------------#include "Date
...

struct tm *dur;
// Pointer to struct tm
...

time(&sec);
dur = localtime(&sec);

// Get the present time
...

day
= (short) dur->tm_mday;
month = (short) dur->tm_mon + 1;
year = (short) dur->tm_year + 1900;
}

SOLUTIONS



// ----------------------------------------------------bool Date::setDate( int mn, int da, int yr)
{
if( mn < 1 || mn > 12 ) return false;
if( da < 1 || da > 31 ) return false;
switch(mn)
// Month with less than 31 days
{
case 2: if( isLeapYear(yr))
{
if( da > 29)
return false;
}
else if( da > 28)
return false;
break;
case 4:
case 6:
case 9:
case 11:
if( da > 30) return false;
}
month = (short) mn;
day
= (short) da;
year = (short) yr;
return true;
}
// ----------------------------------------------------void Date::print() const
// Output a date
{
cout << asString() << endl;
}
// ----------------------------------------------------const string& Date::asString() const
// Return a date
{
// as string
...

<< setw(2) << month << '-'
<< setw(2) << day
<< '-' << year;
iostream >> dateString;
return dateString;
}

295

296



CHAPTER 14

METHODS

// -----------------------------------------------------// date_t
...

// -----------------------------------------------------#include "Date
...
asString() << endl;
today
...
asString()
<< endl;;
if( today
...
setDate( month, day, year))
cerr << "Invalid date!\n" << endl;
else
{
cout << "\nYour first vacation: ";
holiday
...
getYear() < holiday
...


In addition, this chapter describes constant members and enumerated
types
...
h
// Class Result to represent a measurement
// and the time of measurement
...
h"
// Class DayTime
class Result
{
private:
double val;
DayTime time;
public:
Result();
// Default constructor
Result(double w, const DayTime& z = currentTime());
Result(double w, int hr, int min, int sec);
double getVal() const { return val; }
void
setVal( double w ) { val = w; }
const DayTime& getTime() const { return time; }
void setTime( const DayTime& z) { time = z; }
bool setTime(int hr, int min, int sec)
{ return time
...

};
#endif // _RESULT_

A first implementation of constructors
#include "result
...
0; }
Result::Result( double w, const DayTime& z)
{
val = w;
time = z;
}
Result::Result( double w, int hr, int min, int sec)
{ val = w;
time = DayTime(hr, min, sec); // Assign a temporary
// object of type
}
// DayTime to time
...
In our example,
the Account class, we already made use of this feature
...
An object of the Account class therefore has a
string type member sub-object, or member object for short
...


ᮀ Calling Constructors
When an object containing member objects is initialized, multiple constructor calls are
to be executed
...
The order of the constructor calls is significant in
this case
...
Unless otherwise stated, the default constructor will
be called for each member object
...
In addition to a
double type measurement, the time of each measurement is recorded
...

The default constructor only sets the value of the measurement to 0
...


Example: Result current;
The default constructor for the member object time first sets the hours, minutes and
seconds to 0
...
0 is
assigned to val
...


Example: Result temperature1(15
...
7, 14, 30, 35);

Since the compiler has no information on the relation of initial values and member
objects, it first calls the default constructor for the member object time
...


300



CHAPTER 15



MEMBER OBJECTS AND STATIC MEMBERS

MEMBER INITIALIZERS

New implementation of constructors
#include "result
...
0) { /*
...
*/ }
Result::Result( double w, int hr, int min, int sec)
: val(w), time(hr, min, sec)
{
/*
...
*/ with statements, if needed
...


Sample program
// result_t
...
h"
#include
using namespace std;
int main()
// Some air temperature measurements
{
DayTime morning(6,30);
Result t1,
// Default constructor
t2( 12
...
2, 12,0,0),
t4(17
...
print();

cout << "\n Temperature
Time \n"
<< "-------------------------" << endl;
t2
...
print();
t4
...
Correct values are
assigned later
...

Constant objects or references cannot be declared as member objects since it is
impossible to assign values to them later
...


When defining a constructor, you can use member initializers to ensure general and
efficient use of member objects
...


Example: time(hr,min,sec)

// Member initializer

Multiple member initializers are separated by commas
...


Example: Result::Result( /* Parameters */ )
: val(w), time(hr, min, sec)
{ /* Function block */ }

This ensures that a suitable constructor will be called for data members with member initializers and avoids calls to the default constructor with subsequent assignments
...

The argument names of the member initializers are normally constructor parameters
...




NOTE
Member initializers can only be stated in a constructor definition
...


302



CHAPTER 15



MEMBER OBJECTS AND STATIC MEMBERS

CONSTANT MEMBER OBJECTS

New version of class Result
// result2
...

// --------------------------------------------------#ifndef _RESULT_
#define _RESULT_
#include "DayTime
...
cpp :
Tests the new class Result
...
h"
#include
using namespace std;
int main()
{
DayTime start(10,15);
Result m1( 101
...
9);
// At current time
...

m2
...
9);
// Corrected value for m2
cout << "\n Result
Time \n"
<< "-------------------------" << endl;
m1
...
print();
m3
...
For example, you could set the time for a measurement once
and not change this time subsequently
...
In this case, the member object time can be
declared as follows:

Example: const DayTime time;
Since the const member object time cannot be modified by a later assignment, the correct constructor must be called to initialize the object
...


ᮀ The Sample Class Result
If the member object time is const, the first version of the constructors are invalid
since they modify time by means of a later assignment
...
The member initializer ensures
that the desired initial values are used to create the member object time
...
)
methods can no longer be applied
...
This means that a programmer cannot accidentally overwrite a member declared
as a const
...


ᮀ Example with Fundamental Type
Data members with fundamental types can also be defined as const
...
Since the client number
never changes, it makes sense to define the number as const
...
*/ ) : nr(++id)
{ /*
...


304



CHAPTER 15



MEMBER OBJECTS AND STATIC MEMBERS

STATIC DATA MEMBERS

Class Result with static members
// result3
...

// --------------------------------------------------#ifndef _RESULT_
#define _RESULT_
#include "DayTime
...

void setMinMax(double w); // private function
public:
Result(double w, const DayTime& z = currentTime());
Result(double w, int hr, int min, int sec);
//
...
cpp
// Defining static data members and
// methods, which are not defined inline
...
h"
double Result::min = 0
...
0;
bool
Result::first = true;
void Result::setMinMax(double w)
// Help function
{ if(first) { min = max = w;
first = false; }
else if( w < min) min = w;
else if( w > max) max = w;
}
// Constructors with member initializer
...


STATIC DATA MEMBERS



305

ᮀ Class-Specific Data
Every object has its own characteristics
...

However, sometimes it is useful to keep some common data that can be accessed by all
the objects belonging to a class, for example:



figures such as exchange rates, interest rates or time limits which have the same
value for every object
status information, such as the number of objects, current minimum or maximum
threshold values, or pointers to some objects; for example, a pointer to an active
window in a window class
...

Since a programmer will also need to manage the data from within the class, it should be
represented within the class rather than globally
...
In contrast to normal data members, static data members occur only once in
memory
...
On the opposite page, the following statement

Example: static double min, max;

// Declaration

defines two static data members called min and max that record the minimum and maximum values for the measurements
...
Just like member functions, which occur only once, static data members must be defined and initialized in an external source file
...


Example: double Result::min = 0
...
Static
data members and member functions belonging to the same class are normally defined in
one source file
...
Member functions as before, plus:
static double getMin() { return min; }
static double getMax() { return max; }
};

Application program
// result3_t
...

// --------------------------------------------------#include "result3
...
45, morning),
temp2( 11
...
0;
cout << "\nWhat is the air temperature now? ";
cin >> temp;
Result temp3(temp);
// At current time
...
print(); temp2
...
print();
cout
<< "\n Minimum Temperature: " << Result::getMin()
<< "\n Maximum Temperature: " << Result::getMax()
<< endl;
return 0;
}

ACCESSING STATIC DATA MEMBERS



307

ᮀ Static Data Members and Encapsulation
The normal rules for data encapsulation also apply to static data members
...

If the static data members min and max in the Result class are declared public
rather than private, and given that temperature is an object belonging to the class,
the following statement

Example: cout << temperature
...
You can also use the range operator:

Example: cout << Result::max;
This syntax is preferable to the previous example, since it clearly shows that a static data
member exists independently of any objects
...
However, normal methods can be used for class objects only
...
Static member functions are used for this purpose
...

The static keyword is used to define static member functions
...


As the Result class, which was modified to include the static member functions
getMin(), setMin(), etc
...
Definitions outside of the class do not need to repeat the static keyword
...


Example: temperature
...
4);
Result::setMax(42
...


Calling a static member function does not bind the function to any class object
...
This also

means that static member functions cannot access data members and methods that are
not static themselves
...
cpp
// Uses enum-constants within a class
...
getState();
if( as == Lights::red)
{
A1
...
setState( Lights::amber);
}
cout << endl;
return 0;
}

Lights

break;
break;
break;
break;

ENUMERATION



309

ᮀ Definition
An enumeration is a user-definable, integral type
...
A range of values and a name for these values are also defined at the
same time
...
The names quoted in the list identify integral constants
...
The first constant
has a value of 0, and each subsequent constant has a value that is one higher than its
predecessor
...
A Shape type variable can only assume one of these values
...

switch(shape)
{
case Line:

// Variable shape

// To evaluate shape
//
...


However, you can also define the values of the constants explicitly
...


Example: enum { OFF, OUT=0, ON, IN=1 };
This statement defines the constants OFF and OUT, setting their value to 0, and the constants ON and IN with a value of 1
...


ᮀ Class-Specific Constants
Enumeration can be used to define integral symbolic constants in a simple way
...
This allows you to define constants that are
visible within a namespace or class only
...
This means that the type and enum constant are only
available for direct use within the class
...


Example: if(Lights
...




CHAPTER 15



exercise s

310

MEMBER OBJECTS AND STATIC MEMBERS

EXERCISES

Copy constructor of class Article
The copy constructor creates a copy of an existing object
...
The copy
constructor in the Article class is thus declared as follows:
Declaration of copy constructor:
Article( const Article& );

The default copy constructor simply transfers the data members to the new
object
...

Public Methods
Constructor with one parameter for each data member
Access methods for each data member
...

A method for formatted screen output of all data members

EXERCISES



311

Exercise 1
In the first exercise of the last chapter you defined a simple class called
Article
...
Improve and extend the Article class as follows:








Use a static data member instead of a global variable to count the current
number of objects
...

The method returns the current number of objects
...
This ensures that the counter will always be accurate
...

Test the new version of the class
...


Exercise 2
A sports club needs a program to manage its members
...












Define the Member class using the data members shown opposite
...
Since a
member’s birthday will not change, the data member for birthdays must
be defined as a const
...

Implement the necessary methods
...

Add a static member called ptrBoss to the class
...
If no chairperson
has been appointed, the pointer should point to NULL
...

Use a pointer to set and return the object in question
...


312



CHAPTER 15

MEMBER OBJECTS AND STATIC MEMBERS

Sample output
Simulation of two traffic lights!
Terminate this program with +!
1
...
Light
--------------------------RED
AMBER
GREEN
AMBER
AMBER
RED
GREEN
AMBER
RED
AMBER
GREEN
//
...
The function time() is declared in the header file ctime
...
1
...
The type time_t is defined as long
...
Instead of calling the function time() in a loop, you can use the function
Sleep() for Windows or the function sleep() for Unix
...


EXERCISES



313

Exercise 3
Create a program to simulate the signal positions for two sets of traffic lights at
a junction
...







Each set of lights is switched through the phases red, amber, green, amber,
red, and so on
...

The lights operate in an infinite loop that can be terminated by interrupting the program
...
e
...

The status of the lights is constant for a certain number of seconds
...
These values can be different for each set of lights
...
To do so,
you can call the standard function time() in a loop
...




CHAPTER 15



solutions

314

MEMBER OBJECTS AND STATIC MEMBERS

SOLUTIONS

Exercise 1
// ---------------------------------------------------// article
...

// ---------------------------------------------------#ifndef _ARTICLE_H_
#define _ARTICLE_H_
#include
using namespace std;
class Article
{
private:
long nr;
string name;
double sp;
// Static data member:
static int countObj;

// Article number
// Article name
// Sales price
// Number of objects

public:
Article( long nr=0, const string& name="noname",
double sp=0
...
size() < 1)
// No empty Name
return false;
name = s;
return true;
}
void setNr( long n) { nr = n; }
void setSP(double v)
{
// No negative price
sp = v > 0
...
0;
}
};
#endif

// _ARTICLE_

SOLUTIONS

//
//
//
//
//



--------------------------------------------------article
...

Constructor and destructor output when called
...
h"

// Definition of the class

#include
#include
using namespace std;
// Defining the static data member:
int Article::countObj = 0;
// Number of objects
// Defining the constructor and destructor:
Article::Article( long nr, const string& name, double sp)
{
setNr(nr);
setName(name);
setSP(sp);
++countObj;
cout << "An article \"" << name
<< "\" is created
...
article!"
<< endl;
}
// Defining the copy constructor:
Article::Article( const Article& art)
:nr(art
...
name), sp(art
...
\n"
<< "This is the " << countObj << "
...
\n"
<< "There are still " << --countObj << " articles!"
<< endl;
}
// The method print() outputs an article
...

}

315

316



CHAPTER 15

//
//
//
//

MEMBER OBJECTS AND STATIC MEMBERS

-----------------------------------------------------article_t
...

------------------------------------------------------

#include "article
...
9);

// Global

int main()
{
cout << "\nThe first statement in main()
...
99);
cout << "\nThe first call of test()
...
" << endl;
test(article2);
// Passing by Value
cout << "\nThe last statement in main()
...
print();
static Article bike( 3333, "bicycle", 999
...
print();
cout << "\nThe last statement in function test()"
<< endl;
}

SOLUTIONS



317

Exercise 2
The Date class from the last chapter ( see files Date
...
cpp ) can be
left unchanged
...

The other files:
// -----------------------------------------------------// member
...

// -----------------------------------------------------#ifndef _MEMBER_H_
#define _MEMBER_H_
#include "Date
...
more data
static Member *ptrBoss;

// Member number
// Name
// Birthday

// Pointer to boss,
// NULL = no boss
...
size() < 1)
// No empty name
return false;
name = s;
return true;
}
void display() const;
// static methods:
static Member* getBoss()
{
return ptrBoss;
}
static void setBoss( Member* ptrMem)
{
ptrBoss = ptrMem;
}
};
#endif
//
//
//
//

// _MEMBER_H_

--------------------------------------------------member
...

---------------------------------------------------

#include "member
...
asString()
<< '\n' << line << endl;
}

SOLUTIONS

// ---------------------------------------------------// member_t
...

// ---------------------------------------------------#include "member
...
setDate();
cout << "Date: " << today
...
setNr(1111);
cout << "\nTwo members of the sports club:\n" << endl;
fran
...
display();
cout << "\nSomething changed!" << endl;
fran
...
display();
Member benny( 1122,"Rush, Benny", 1,1,2000);
cout << "The youngest member of the sports club: \n";
benny
...
getNr())
ptr = &fran;
else if( nr == kurt
...

// ----------------------------------------------------// Lights_t
...

// ----------------------------------------------------#include "lights
...

{ time_t end = time(NULL) + sec;
while( time(NULL) < end)
;
}
// Alternative for Windows:
// #include ...

greenTime2 = 14 , amberTime2 = 2 };
int main()
{ cout << "Simulating two traffic lights!\n\n"
<< "Terminate this program with +!\n"
<< endl;
cout << " 1
...
Light\n"
<< "---------------------------" << endl;
while(true)
{ A1
...
setState( Lights::amber);
cout << endl;
wait( amberTime2);
cout << "
";
A2
...
setState( Lights::amber);
cout << endl;
wait(amberTime2);
A1
...
setState( Lights::red);
cout << endl;
wait(amberTime1);
A1
...
setState( Lights::amber);
cout << endl;
wait(amberTime1);
}
return 0;
}

chapter

16

Arrays
This chapter describes how to define and use arrays, illustrating onedimensional and multidimensional arrays, C strings and class arrays
...



...



...



...
cpp
// To input numbers into an array and output after
...
variable
// Index, quantity

cout << "Enter up to 10 numbers \n"
<< "(Quit with a letter):" << endl;
for( i = 0; i < MAXCNT && cin >> x; ++i)
arr[i] = x;
cnt = i;
cout << "The given numbers:\n" << endl;
for( i = 0; i < cnt; ++i)
cout << setw(10) << arr[i];
cout << endl;
return 0;
}

DEFINING ARRAYS



323

An array contains multiple objects of identical types stored sequentially in memory
...
An array is also referred to as a vector
...
The definition includes the array
name and the type and number of array elements
...


Example: float arr[10];

// Array arr

This statement defines the array arr with 10 elements of float type
...

An array always occupies a contiguous memory space
...


ᮀ Index for Array Elements
The subscript operator [] is used to access individual array elements
...
The elements belonging to the array arr are thus
arr[0], arr[1] , arr[2],
...

Any int expression can be used as an index
...
and ->
...
As a programmer, you need to be particularly careful to avoid this error! However, you can define a
class to perform range checking for indices
...
Class arrays are discussed later
...
, 190 to the elements
...
cpp
// The program computes the first 20 Fibonacci
// numbers and the corresponding Fibonacci quotients
...
0 + sqrt(5
...
0;

// Limit

// Title and the first two Fibonacci numbers:
cout << header << endl;
cout << setw(5) << 0 << setw(15) << fib[0] << endl;
cout << setw(5) << 1 << setw(15) << fib[1] << endl;
// Rest of the table:
for( i=2; i <= COUNT; i++ )
{
// Quotient:
q = (double)fib[i] / (double)fib[i-1];
cout << setw(5) << i << setw(15) << fib[i]
<< setw(20) << fixed << setprecision(10) << q
<< setw(20) << scientific << setprecision(3)
<< lim - q << endl;
}
return 0;
}

INITIALIZING ARRAYS



325

ᮀ Initialization List
Arrays can be initialized when you define them
...
If you initialize
an array when you define it, you do not need to state its length
...
If the array
length is explicitly stated in the definition and is larger than the number of initial values,
any remaining array elements are set to zero
...

Locally defined arrays are created on the stack at program runtime
...
g
...

Unless they are initialized, the elements of a local array will not necessarily have
a definite value
...


You cannot assign a vector to another vector
...
This topic will be discussed in
depth later
...
Fibonacci numbers are useful for representing natural growth
...

Their definition is as follows:



the first Fibonacci number is 0, the second is 1
each subsequent Fibonacci number is the sum of its two immediate predecessors
...

The quotient of a Fibonacci number and its predecessor is referred to as a Fibonacci
quotient
...
, converges towards
the threshold value (1 + √5)/2
...



...


Sample program
// C-string
...

// ----------------------------------------------------#include
#include
#include
using namespace std;
char header[] = "\n
*** C Strings ***\n\n";
int main()
{
char hello[30] = "Hello ", name[20], message[80];
cout << header << "Your first name: ";
cin >> setw(20) >> name;
// Enter a word
...

cout << hello << endl;
cin
...

cout << "\nWhat is the message for today?"
<< endl;
cin
...

if( strlen( message) > 0)
// If string length is
{
// longer than 0
...

}
return 0;
}

C STRINGS



327

ᮀ char Arrays
Arrays whose elements are of char type are often used as data communication buffers
...
One way of representing a
string is to store the string and the terminating null character '\0' in a char array
...


Example: char name[] = "Hugo";
This definition is equivalent to
char name[] = { 'H','u','g','o','\0' };

As you can see, the string name occupies five bytes, including an additional byte for the
null character
...

In the C language, strings are usually represented as char vectors with a terminating
null character
...


ᮀ C Strings and the

string

Class

C strings are simple char arrays, which means that the functionality of the string
class is not available for them
...


Example: char str1[20], str2[20] = "A string";
str1 = str2;
strcpy( str1, str2);

// Error!
// ok!

The standard functions of the C language, such as strlen(), strcpy(), strcmp(),
and others, are available for C strings
...

As the program on the opposite page shows, I/O streams are overloaded for char
arrays, too
...
However, the program must make sure not to overrun the end of the char array when reading data into the array
...


Example: cin >> setw(20) >> name; // 19 characters
C strings are preferable to the string class if only a few operations are needed and
you want to avoid unnecessary overheads
...
cpp
// An array containing objects of class Account
...
h"
#include
using namespace std;

// Definition of class Account

Account giro("Lucky, Peter", 1234567, -1200
...
0),
Account("Smith, John", 543001),
Account(),
// Default constructor
"Li, Zhang",
// Account("Li, Zhang"),
giro
// Account(giro)
};
int cnt = sizeof(accountTab) / sizeof(Account);
int main()
{
// To set some values:
accountTab[1]
...
00);
// Assignment ok:
accountTab[2] = Account("Pit, Dave", 727003, 200
...
display();
if( i % 3 == 2)
{
cout << "Press return to go on!\n";
cin
...
The array is known as a class array in
this case
...


Example: Result temperatureTab[24];
This statement defines the class array temperatureTab that stores 24 objects of type
Result
...

As the statement does not initialize the array explicitly, the default constructor is
automatically called for each array element
...


Thus, the previous example is only valid for the first version of the Result class as
this class contains a default constructor
...
The list contains a constructor
call for each array element
...
5, 0,30,30),
Result( 3
...
5,
// Just so
Result( temp1),
// Copy constructor
temp2
// Just so
};

The first five array elements are initialized by the constructor calls implicitly contained
in these statements
...
The default constructor is then called for the remaining elements
...

The public interface of the objects in the array is available for use as usual
...
setTime( 2,30,21);
No additional parentheses are needed in this statement since the subscript operator []
and the class member operator
...


330



CHAPTER 16



ARRAYS

MULTIDIMENSIONAL ARRAYS

Sample program
// multidim
...

// ---------------------------------------------------#include
#include
using namespace std;
char representative[2][20] = {"Armstrong, Wendy",
"Beauty, Eve"};
// Each representative has five different
// articles available, having sold the following:
int articleCount[2][5] = { { 20, 51, 30, 17, 44},
{150, 120, 90, 110, 88}
};
int main()
{
for( int i=0; i < 2; i++ )
{
cout <<"\nRepresentative: " << representative[i];
cout << "\nNumber of items sold: ";
for( int j = 0; j < 5; j++ )
cout << setw(6) << articleCount[i][j];
cout << endl;
}
return 0;
}

Screen output:
Representative: Armstrong, Wendy
Items sold:
20
51
30
17
Representative: Beauty, Eve
Items sold:
150 120
90

110

44

88

MULTIDIMENSIONAL ARRAYS



331

ᮀ Defining Multidimensional Arrays
In C++ you can define multidimensional arrays with any number of dimensions
...

The most common multidimensional array type is the two-dimensional array, the socalled matrix
...
Each of the 30
(3 ϫ 10) elements is a float type
...
2;

// Row 0, column 9

stores the value 7
...


ᮀ Arrays as Array Elements
C++ does not need any special syntax to define multidimensional arrays
...

The array number thus contains the following three elements:
number[0]

number[1]

number[2]
...

This means that the same rules apply to multidimensional arrays as to one-dimensional arrays
...


Examples: int arr[2][3] = { {5, 0, 0}, {7, 0, 0} };
int arr[][3]

= { {5}, {7} };

These two definitions are equivalent
...
It is necessary to define any other dimensions since they
define the size of array elements
...
The representative[i] rows are
char arrays used for storing the names of the representatives
...


Example: string representative[2] = {"La
...
"};

332



CHAPTER 16



ARRAYS

MEMBER ARRAYS

Class TelList
// telList
...

// ---------------------------------------------------#ifndef _TelList_
#define _TelList_
#include
using namespace std;
#define PSEUDO -1
#define MAX 100

// Pseudo position
// Maximal number of elements

// Type of a list element:
struct Element { string name, telNr; };
class TelList
{
private:
Element v[MAX];
int count;

// The array and the current
// number of elements

public:
TelList(){ count = 0;}
int getCount() const { return count; }
Element *retrieve( int i )
{
return (i >= 0 && i < count)? &v[i] : NULL;
}
bool append( const Element& el )
{
return append( el
...
telNr);
}
bool append( const string& name,
const string& telNr);
bool erase( const string& name);
int search( const string& name);
void print();
int print( const string& name);
int getNewEntries();
};
#endif

// _TelList_

MEMBER ARRAYS



333

ᮀ Encapsulating Arrays
A programmer often needs to handle objects of the same type, such as company employees, bank accounts, or the articles in stock
...
An array allows you to access individual objects
directly and perform searches
...
When you design a class of this type, one aim will
be to perform automatic range checking
...
The resulting class will contain a comfortable and safe interface for object data management
...

Each entry in the list contains a dataset containing a name and a phone number
...
The array v
can store up to MAX entries of the Element type
...
When a phone list is created, this number will initially be 0
...

The TelList class uses a single default constructor that sets the counter, count, to
zero
...

The tasks performed by the other methods are easily deduced from their names
...

Using a pointer makes it possible to return a NULL pointer if the index is invalid
...
The data passed to a method is
copied to the next free array element and the counter is incremented
...
In this
case, the method returns false instead of true
...
You can
implement the methods for the TelList yourself and go on to test them
...
To eliminate a number n you simply set the nth element in the array
to false
...


...

The screen control characters make it possible to locate the cursor, and that
independent of the current compiler (see appendix)
...
Input can be terminated by any invalid input, such as a letter
...
This algorithm repeatedly accesses the array, comparing
neighboring array elements and swapping them if needed
...
You use a flag to indicate that no elements have been
swapped
...

Define and initialize an array with four DayTime class objects
...
Finally, find the largest and smallest elements and output them on
screen
...
The program
should also count the number of prime numbers less than 1000
...
Use the
Sieve of Eratosthenes:
To find primary numbers simply eliminate multiples of any primary numbers
you have already found, i
...
:
first eliminate any multiples of 2 ( 4, 6, 8,
...
),
then eliminate any multiples of 5 ( 10, 15, 20,
...


Exercise 4
Write a C++ program to create the screen output shown opposite
...
You can scroll
the banner by beginning string output with the first character, then the second,
and so on
...

You can use a wait loop to modify the speed of the banner after each string is
output
...



Implement the TelList class methods shown opposite
...
This means the append()
method can only be used to append an entry provided the name is neither blank nor already in use
...
The position of the element to be deleted is first located using the search() method
...
In any other case,
the last element in the array is used to overwrite the element that is to
be deleted and the counter count is decremented
...
If the search operation is unsuccessful, the value PSEUDO is
returned
...
You
can pass the first letter or letters of a name to the second method to
output any entries beginning with these letters
...

Example:





str1
...

The getNewEntries() method is used to read new phone list entries
from the keyboard
...
Reading should be terminated if the user types an empty string
...

Write an application program that creates a phone list of type TelList
and displays the menu shown on the opposite page
...
The menu must be called in the main loop of the program
...
If the menu item “Erase” or “Search”
is chosen, you must also read a name or the first letters of a name from
the keyboard
...
This is just one of the enhancements (another
would be variable length) that will be added at a later stage
...
cpp
// Inputs integers into an array,
// sorts in ascending order, and outputs them
...

long help;
// Swap
...

while( !sorted)
//
{
//
sorted = true;
--end;
for( i = 0; i < end; ++i)
//
{
//
if( number[i] > number[i+1])
{
sorted = false;
//
help
= number[i];
//
number[i] = number[i+1];
number[i+1]= help;
}
}
}

As long as not
yet sorted
...


Not yet sorted
...


SOLUTIONS



// Outputs the numbers
cout << "The sorted numbers:\n" << endl;
for( i = 0; i < cnt; ++i)
cout << setw(10) << number[i];
cout << endl;
return 0;
}

Exercise 2
// ---------------------------------------------------// DayTime
...

// ---------------------------------------------------#ifndef _DAYTIME_
#define _DAYTIME_
#include
#include
using namespace std;
class DayTime
{
private:
short hour, minute, second;
bool overflow;
public:
DayTime( int h = 0, int m = 0, int s = 0)
{
overflow = false;
if( !setTime( h, m, s))
// this->setTime(
...


{
}

return asSeconds() < t
...
asSeconds();

void print() const
{
cout << setfill('0')
<< setw(2) << hour
<<
<< setw(2) << minute <<
<< setw(2) << second <<
cout << setfill(' ');
}
void swap( DayTime& t)
//
{
//
DayTime temp(t); t = *this;
}

':'
':'
" Uhr" << endl;

Just one parameter!
Swaps *this and t:
*this = temp;

};
#endif

// _DAYTIME_

// ----------------------------------------------------// TimeTab
...

// ----------------------------------------------------#include "DayTime
...
setTime( 8,40,50);
// Last element
...
print();
cout << endl;
}
// To compute shortest and longest time:
int i_min = 0, i_max = 0;
// Indices for shortest
// and longest elements
...
isLess( timeTab[i_min]) )
i_min = i;
if( timeTab[i_max]
...
print();

cout << "\nLongest time: ";

timeTab[i_max]
...
cpp
// Identifies prime numbers using the Sieve of
// Eratosthenes
...

for( j = i+i; j < LIMIT; j += i)
flags[j] = false;
}
}
// To count:
int count = 0;
// Counter
for( i = 2; i < LIMIT; ++i)
if(flags[i])
// If i is a prime number
++count;
// -> count
// Output:
cout << "There are"<< count <<" prime numbers less than"
<< LIMIT << endl;
cout << "\nTo output prime numbers? (y/n) ";
char reply; cin
...

cout
...
cpp
// Scrolling a message
...
h
The class TelList representing a list
with names and telephone numbers
...


// ---------------------------------------------------// telList
...

// ----------------------------------------------------#include "telList
...
length() > 1
// 2 characters at least
&& search(name) == PSEUDO) // not yet existing
{
v[count]
...
telNr = telNr;
++count;
return true;
}
return false;
}
bool TelList::erase( const string& key )
{
int i = search(key);
if( i != PSEUDO )
{
// Copies the last
v[i] = v[count-1]; --count; // element to position i
return true;
}
return false;
}

SOLUTIONS

int TelList::search(const string& key )
{
for( int i = 0; i < count; i++ )
if( v[i]
...

// Found

return PSEUDO;
// Not found
}
// Functions to support the output:
inline void tabHeader()
// Title of the table
{
cout << "\n Name
Telephone #\n"
"----------------------------------------------"
<< endl;
}
inline void printline( const Element& el)
{
cout << left << setw(30) << el
...
c_str()
<< left << setw(20) << el
...
c_str()
<< endl;
}
void TelList::print()
// Outputs all entries
{
if( count == 0)
cout << "\nThe telephone list is empty!" << endl;
else
{
tabHeader();
for( int i = 0; i < count; ++i)
printline( v[i]);
}
}
int TelList::print( const string& name) const // Entries
{
// beginning with name
...
length();
for( int i = 0; i < count; ++i)
{
if( v[i]
...
compare(0, len, name) == 0)
{
if( matches == 0) tabHeader(); // Title before
// first output
...
sync(); getline( cin, el
...
name
...
sync(); getline( cin, el
...
name) != PSEUDO)
cout << "Name already exists!" << endl;
}
else
{
++inputCount;
cout << "A new element has been inserted!"
<< endl;
}
}
return inputCount;
}
// -------------------------------------------------------// telList_t
...

// -------------------------------------------------------#include "telList
...


SOLUTIONS



inline void go_on()
{
cout << "\n\nGo on with return! ";
cin
...
clear();
while( cin
...
append("Lucky, Peter", "0203-1234567");
while( action != 'B')
{
action = menu();
cls();
cout << header << endl;
switch( action)
{
case 'D':
myFriends
...
empty())
{
myFriends
...
getNewEntries();
break;

347

348



CHAPTER 16

ARRAYS

case 'E':

// Delete
cout <<
"\n--- To delete a telephone entry
...
empty())
{
if( !myFriends
...
sync(); cin
...
get(choice))
choice = 'B';
else
choice = toupper(choice);
cin
...
This
includes:


pointer arithmetic



pointer version of functions



pointers as return values and read-only pointers



pointer arrays

Operations that use C strings illustrate how to use pointers for efficient
programming
...


349

350



CHAPTER 17



ARRAYS AND POINTERS

ARRAYS AND POINTERS (1)

Sample program
// textPtr
...
\n"
<< endl;
char text[] = "Good morning!",
name[] = "Bill!";
char *cPtr = "Hello ";

// Let cPtr point
// to "Hello "
...
e
...

Hello Bill!
Good morning!
The text "Good morning!" starts at address 00451E40
morning!
This is the B of Bill!
Bill can not kill!

ARRAYS AND POINTERS (1)



351

ᮀ Name and Address of an Array
In C++ the name of an array is also the starting address for that array
...


Example: char town[] = "Beijing";
In this case, town is a char pointer to town[0], that is, a pointer to the memory
address that stores the 'B' character
...


Example: cout << town; // or:

cout << &town[0];

A pointer to the first character of the string town is passed
...


ᮀ Pointer Variables and Arrays
An array name is not a pointer variable but a constant that cannot be modified
...


Example: char *cPtr;
cPtr = town;
cout << cPtr;

// or: cPtr = &town[0];
// To output "Beijing"

Now cPtr points to the array element town[0] just like town
...


Example: cPtr = "Hello!";
After this statement, cPtr points to the ‘H' character
...


ᮀ Typeless Pointers
If you need to display the address rather than the string, you should pass a void* type
pointer rather than a char pointer
...
The << operator belongs to the ostream class and is overloaded for void * types for this purpose
...

void * pointers are also referred to as typeless pointers for this reason
...


352



CHAPTER 17



ARRAYS AND POINTERS

ARRAYS AND POINTERS (2)

Sample program
// arrPtr
...

// --------------------------------------------------#include
using namespace std;
int arr[4] = { 0, 10, 20, 30 };
int main()
{
cout << "\nAddress and value of array elements:\n"
<< endl;
for( int i
cout <<
<<
<<

= 0; i < 4; i++ )
"Address: " << (void*)(arr+i)
"
Value: " << *(arr+i)
endl;

// &arr[i]
// arr[i]

return 0;
}

Interrelation between pointers and array elements

arr

0

arr[0]

arr + 1

10

arr[1]

arr + 2

20

arr[0]

arr + 3

30

arr[3]

ARRAYS AND POINTERS (2)



353

ᮀ Addressing Array Elements
Access to individual array elements in C++ is very closely related to pointer arithmetic
...


Example: int arr[4] = { 0, 10, 20, 30 };
As you already know, the name of the array arr is an int pointer to arr[0]
...
The size of the
object referenced by the pointer is automatically taken into consideration
...
e
...
The memory
space between the two entries will be two or four bytes, depending on the size of the type
int
...
Thus,
arr - 1 addresses the word that precedes arr[0]
...


ᮀ Addressing with Pointer Variables
Array elements can also be addressed using pointer variables
...
Thus,
ptr + 1, ptr + 2,
...

For any given integer, i, the following expressions are thus equivalent:
&arr[i]

arr + i

ptr + i

The following thus represent equivalent values:
arr[i]

*(arr + i)

*(ptr + i)

ptr[i]

At first it might seem surprising that you can use the array notation ptr[i] for pointers
...


354



CHAPTER 17



ARRAYS AND POINTERS

POINTER ARITHMETIC

Examples for arithmetic with pointers
float v[6] = { 0
...
1, 0
...
3, 0
...
5 },
*pv, x;
pv = v + 4;
*pv = 1
...

Assign 1
...

Reset pv to v[2]
...


x = *pv++;

//
//
//
//
//

Assign v[3] to x and
increment pv
...

Reset pv to v[2]
...

// -------------------------------------------------#include "account
...

Account accountTab[100]; // Table containing accounts
...

Account *aPtr;
// Pointer to Account-objects
...

// To search for the account number 1234567:
bool found = false;
for( aPtr = accountTab; aPtr < accountTab+cnt;++aPtr)
if( aPtr->getNr() == 1234567 )
{ found = true;
break;
}
if( found)
// Found?
aPtr->display();
// Yes -> display
...
This primarily means that the pointer must always point to the elements of an array
...
You can use a statement such as pv = pv + i; to store the pointer in the variable pv
...

You can also use the operators ++, --, and += or -= with pointer variables
...
Please note that the indirection operator, *, and the operators ++ and -- have the same precedence
...

Operations of this type are not possible using the pointer v since v is a constant
...
However, it does make sense to perform a subtraction with two pointers,
resulting in an int value that represents the number of array elements between the
pointers
...
To do so, you simply subtract the starting address of the array
...


ᮀ Comparing Pointers
Finally, comparisons can be performed with two pointers of the same type
...
In the example on the
opposite page, the pointer aPtr walks through the first cnt elements of the array
accountTab, as long as aPtr < accountTab + cnt
...
cpp
Defines and calls the function reverse()
...

-----------------------------------------------------

#include
using namespace std;
#include ...

void reverse( char str[], char umstr[]); // Prototype
int main()
// Read a word and
{
// output in reversed order
...
width(CNT);
// maximal CNT-1 characters
cin >> word;
reverse( word, revword);

// Call

cout << "\nThe \"reversed\" word:
<< endl ;

" << revword

return 0;
}
void reverse( char s1[], char s2[])
// Copies the
{
// reversed C string s1 to s2
int j = 0;
for( int i = strlen(s1)-1; i >= 0; i--, j++)
s2[j] = s1[i];
s2[j] = '\0';

// Terminating character

}

Sample output:
Enter a word: REGAL
The "reversed" word:

LAGER

ARRAYS AS ARGUMENTS



357

If an array name is passed as an argument when calling a function, the function actually
receives the address of the first array element
...


ᮀ Declaring Parameters
If the argument is an array, there are two equivalent methods of declaring parameters
...
For example, calling strlen("REGAL") returns a value of 5
...
You can declare the parameter as an array
...

str[i] != '\0'; ++i)

}

2
...


Example: int strlen( char *str)
{

/*

as above

*/

}

In both cases the parameter str is a pointer that stores the starting address of the
array
...
Calling strlen("REGAL"); leads to the following situation:
'R'

'E'

'G'

'A'

'L'

'\0'

str[0]

str[1]

str[2]

str[3]

str[4]

str[5]

As you can see, the length of a C string is equal to the index of the element containing
the terminating null character
...


ᮀ Array Length
A function to which an array is passed initially knows only the starting address of the
array but not its length
...
In most other cases the length must be supplied explicitly
...


Example: char dest[30], source[] = "A string";
strcpy( dest, source);

Here the string source is copied to dest “from left to right” just like an assignment
...


Index Version of strcpy()
void strcpy( char s1[], char s2[])
// Copies s2 to s1
{
int i;
// Index
for( i = 0; s2[i] != '\0'; ++i) // Copy
...


Pointer version 1 of strcpy()
void strcpy( char *s1, char *s2)
// Copies s2 to s1
{
for( ; *s2 != '\0'; ++s1, ++s2) // Copy
*s1 = *s2;
*s1 = '\0';
// Append terminating
}
// character
...

// Copy and append
// terminating
// character
...
When declaring parameters for a given type T:
T name[]

is always equivalent to

T *name
...

However, it is possible to use pointers instead of indices
...

char* p = str;
for( p = str; *p != '\0'; ++p) // Search
;
// for \0
return (p - str);
}

In this case, the difference between two pointers results in the string length
...
Both versions produce the same results: the string s2 is
copied to s1
...

As the parameters s1 and s2 are pointer variables, they can be shifted
...

Generally, pointer versions are preferable to index versions as they are quicker
...


ᮀ Multidimensional Arrays as Parameters
In a parameter declaration for multidimensional arrays, you need to state every dimension
with the exception of the first
...


Example: long func( int num[][10] );
long func( int *num[10] );

// ok
...


360



CHAPTER 17



ARRAYS AND POINTERS

READ-ONLY POINTERS

Sample program
// accountFct
...

// -------------------------------------------------#include "account
...

Account accountTab[] =
// Table with Account-objects
...
30),
Account("Crusoe, Robinson", 200000, 0
...
70),
Account("Valentin, Carl", 543002, -1111
...
0;
cout << "Output the overdrawn accounts!\n"
<< "These are the accounts, which fell below \n"
<< "the limit, ex
...
00
...

++count;
}
return count;
}

READ-ONLY POINTERS



361

ᮀ Pointers to const Objects
You can use a normal pointer for both read and write access to an object
...
In fact, a read-only pointer is obligatory if you need to point to a constant object
...


Example: const int a = 5, b = 10,

*p = &a;

This statement defines the constants a and b, and a pointer p to a constant object of
type int
...


Example: cout << *p;
*p = 1;

// To read is ok
...
In other words, a read-only
pointer can also point to a non-constant object
...
90);
const Account* ptr = &depo;
ptr->display();
prt->setState( 7777
...


ᮀ Read-Only Pointers as Parameters
Read-only pointers are most commonly found in parameter lists
...


Example: int strlen( const char *s);
In this example, the parameter s is a read-only pointer
...
You cannot remove the “write protection”
by assigning the read-only pointer s to a normal pointer
...


362



CHAPTER 17



ARRAYS AND POINTERS

RETURNING POINTERS

Sample program
// search1
...
The function strstr() is called
...
dat ]
// ---------------------------------------------------#include
using namespace std;
#define MAXL 200
// Maximum length of line
namespace MyScope
{
// Self-defined version of function strstr():
char *strstr( const char *str, const char *patt);
}
char line[500],
// For a line of text
...

int main()
{ int lineNr = 0; // As long as a line is left over:
while( cin
...
width(3);
cout << lineNr << ": "
// Output the line
<< line << endl;
// number and the line
}
}
return 0;
}

// strstr
...
h>
// For strlen() and strncmp()
namespace MyScope
{
char *strstr( const char *s1, const char *s2)
{
// To search for the string s2 within s1
...

}
}

RETURNING POINTERS



363

A function can return a pointer to an object
...
Such a function will return either a pointer
to the required object or a NULL pointer if the object cannot be found
...
For example, the
functions strcpy(), strcat(), and strstr() each return a pointer to the first character in a C string
...
The function returns its first argument, that
is, a pointer to the target string and leads to the following:

Prototype: char* strcpy( char* s1, const char* s2);
The second parameter is a read-only pointer, since the source string is read-only
...
When you call this function, make
sure that the char array for the first string is large enough to store both strings
...
The following example shows one possible implementation
...
This version was placed in the MyScope namespace to distinguish it from
the standard function
...
The
standard function strncmp() is used to compare two strings
...

The program uses the strstr() function to display all the lines in the text containing the letters “is" with line numbers
...
cpp where you can supply a search pattern
...
",

accPtr[1]

"Davis,
...

// -------------------------------------------------#include
using namespace std;
void displayError ( int errorNr)
{
static char* errorMsg[] = {
"Invalid error number",
"Error 1: Too much data ",
"Error 2: Not enough memory ",
"Error 3: No data available " };
if( errorNr < 1 || errorNr > 3)
errorNr = 0;
cerr << errorMsg[errorNr] << endl;
}



NOTE
A string literal, such as “Error
...
Thus, such a
pointer can be used to initialize another char pointer
...


ARRAYS OF POINTERS



365

Pointers offer various possibilities for simple and efficient handling of large amounts of
data
...


ᮀ Defining Arrays of Pointers
Whenever you need a large number of pointers, you can define an array whose elements
are pointers
...


Example: Account* accPtr[5];
The array accPtr contains five Account pointers accPtr[0], accPtr[1],
...
The individual pointers in the array can now be assigned object addresses
...


Example: Account save("Novack, Kim", 1111, 9999
...
);
accPtr[0] = &save;
accPtr[1] = &depo;
for( int i=2; i<5; ++i) accPtr[i] = NULL;

ᮀ Initialization
As usual, an initialization list is used to initialize the array
...


Example: Account* accPtr[5] = { &depo, &save, NULL};
The value NULL is automatically assigned to any objects for which the list does not contain a value
...


ᮀ Usage
The individual objects addressed by the pointers in an array do not need to occupy a
contiguous memory space
...
This allows for
extremely flexible object handling
...


Example: for( int i=0; i<5; ++i)
if( accPtr[i] != NULL)
accPtr[i]->display();

// To output

The function displayError() opposite displays the error message for a corresponding error number, using an array of char pointers to the error messages
...
cpp
// Demonstrates the command line arguments
...
\HELLO
...
These command line arguments are typically
used to govern how a program is executed or to supply the data a program will work with
...
The
individual arguments are separated by spaces
...
If an argument contains space or redirection characters, you must
place it in double quotes
...
However, if you
intend to process command line arguments, you must define parameters for main()
...
// Function block

}

argc contains the number of arguments passed via the command line
...

The parameter argv is an array of char pointers:
argv[0]
argv[1]
argv[2]

points to the program name (and path)
points to the first real argument, that is, the word after the program name
points to the second argument


...

Various operating systems, for example WINDOWS 98/00/NT and UNIX, allow you
to declare a third parameter for main()
...
The exercises for this chapter contain a program that displays the
program environment
...

// Return value:
< 0, if str1 < str2
//
= 0, if str1 == str2
//
> 0, if str1 > str2
...

This procedure is repeated while i > 0 for the remainder of an array
containing array elements with an initial index of i
...
for( pv = v;

pv <= v + 3;

cout << "

*pv = "

b
...
for( pv = v + 3;
cout << "

<<

pv[i] = "

c
...
The line is then output in reverse order
...

Exercise 3
The standard function strcmp() performs a lexicographical comparison of two
C strings
...
The return
value is the difference between two character codes
...
Call this function
str_cmp() to distinguish it from the standard function
...
The loop should terminate when both strings are
empty
...
The principle of the selection sort algorithm is shown
opposite
...
Test the functions with
random numbers between -10000 and +10000
...

COMSPEC=C:\COMMAND
...


Frequency table for exercise 7

Bloodpressure

<120

120–129 130–139

140–149

>= 160

Age
20–29

25

34

26

12

8

30–39

19

27

24

11

4

40–49

6

15

35

36

18

EXERCISES



371

Exercise 5
a
...

b
...
The environment is a memory area containing strings in the format
NAME=String

A third parameter for the function main() allows access to the environment
...
The array elements are
char pointers to the environment strings, the last element being a NULL
pointer
...

Modify the program to produce a useful tool called search, to which you can
pass any search pattern via the command line
...
Use the standard function strstr()
...
txt

Exercise 7
The following frequency was observed during an examination of the relationship
between age and blood pressure for 300 males
...
Store the sums of the rows and
columns separately in a one-dimensional row or column array
...

The sum of all the matrix elements
...




CHAPTER 17



solutions

372

ARRAYS AND POINTERS

SOLUTIONS

Exercise 1
Screen Output:
a
...

c
...


*pv = 10

*pv = 20

*pv = 30

pv[i] = 20

pv[i] = 30

pv[i] = 40

*(pv+i) = 10

*(pv+i) = 30

v[3] = 40

v[2] = 30

v[1] = 20

*pv = 40

v[0] = 10

Exercise 2
// ------------------------------------------------------// reverse
...

// ------------------------------------------------------#include
using namespace std;
#define MAXLEN 80
int main()
{
char line[MAXLEN], *p;
cout << "Enter a line of text: " << endl;
// Input
for( p =
p <
++p
;

a line:
line;
line+MAXLEN
)

&&

cin
...
cpp
// Define and test the pointer version str_cmp()
// of the standard function strcmp()
...
\n" << endl;
cout << "1
...
sync(); cin
...
get(text1,MAXLEN);
cout << "2
...
sync(); cin
...
get(text2,MAXLEN);
if( text1[0] == '\0' && text2[0] == '\0')
break;
// Both lines empty
...

// -----------------------------------------------------int str_cmp( const char* str1, const char* str2)
{
for( ; *str1 == *str2 && *str1 != '\0'; ++str1, ++str2)
;
return (*str1 - *str2);
}

373

374



CHAPTER 17

ARRAYS AND POINTERS

Exercise 4
//
//
//
//
//

------------------------------------------------------selSort
...

-------------------------------------------------------

#include
#include
#include
#include
using namespace std;

// For srand(), rand()
// For time()

// Prototype:
void selectionSort( int arr[], int len);
const int len = 200;
int intArr[len];
int main()
{
cout << "\n
<< endl;

***

// int-array

Selection Sort Algorithm

***\n"

// To initialize an int-array with random numbers:
srand( (unsigned int)time(NULL)); // Initialize the
// random number generator
...

if( arr[mini] > arr[j])
mini = j;
swap( arr[i], arr[mini]);

// Swap
...


375

376



CHAPTER 17

ARRAYS AND POINTERS

Exercise 5
//
//
//
//
//

------------------------------------------------------args
...

-------------------------------------------------------

#include
using namespace std;
int main( int argc, char *argv[], char *env[])
{
cout << "Program: " << argv[0] << endl;
cout << "\nCommand line arguments:" << endl;
int i;
for( i = 1; i < argc; ++i)
cout << argv[i] << endl;

// Arguments

cout << "Type to go on";
cin
...
cpp
// A filter that outputs all lines containing a certain
// pattern
...

//
// Call:
search pattern [ < text
...
In this case end input with +
...


SOLUTIONS



int main( int argc, char *argv[])
{
if( argc != 2)
{
cerr << "Call: search pattern [ < text
...
getline( line, MAXL))
{
++lineNr;
if( strstr( line, argv[1]) != NULL)
{
// If the pattern was found:
cout
...
cpp
To compute the sums of rows and columns in a matrix
...
\n"
<< endl;
// Compute sums:
int totalsum =
matrixsum( matrix, 3, rowsum, colsum);
// Output matrix and sums:
cout << "The matrix with the sums "
<< "of rows and columns:\n"
<< endl;
int i,j;
for( i = 0 ; i < 3 ; ++i)
// Output rows of the
{
// matrix with row sums
...


chapter

18

Fundamentals of File
Input and Output
This chapter describes sequential file access using file streams
...


379

380



CHAPTER 18



FUNDAMENTALS OF FILE INPUT AND OUTPUT

FILES

File operations

Main Memory

File Buffer

External Memory

Write
File
Read

FILES



381

When a program is terminated, the program data stored in main memory is lost
...


ᮀ File Operations
Single characters or character strings can be written to text files just like they can be output on screen
...
A record contains
data that forms a logical unit, such as the human resource information for a person
...
When you read a record, this record is taken from the file and
copied to the data structure of a program
...
However, this
normally involves more than just storing an object’s data
...

External mass storage media, such as hard disks, are normally block-oriented—that is,
data is transferred in blocks whose size is a multiple of 512 bytes
...


ᮀ File Positions
From the viewpoint of a C++ program, a file is simply a long byte array
...

Every character in a file occupies a byte position
...
The current file position is the position of the byte
that will be read or written next
...

In the case of sequential access, the data is read or written byte by byte in a fixed order
...
If you need access to some
piece of information in a file, you must read the file content from start to finish
...

Easy access to given data in a file implies being able to set the current file position as
required
...


382



CHAPTER 18



FUNDAMENTALS OF FILE INPUT AND OUTPUT

FILE STREAMS

Stream classes for file access

ios

istream

ostream

iostream

ifstream

ofstream

fstream

FILE STREAMS



383

C++ provides various standard classes for file management
...
As a programmer you will not need to concern yourself with file buffer management or system specifics
...
One program can thus process files on a Windows NT or UNIX
platform
...


ᮀ The File Stream Classes in the iostream Library
The class hierarchy on the opposite page shows that the file stream classes contain the
stream classes, with which you are already familiar, as base classes:




the ifstream class derives from the istream class and allows file reading
the ofstream class derives from the ostream stream class and supports writing
to files
the fstream class derives from the iostream stream class
...


The file stream classes are declared in the fstream header file
...


ᮀ Functionality
The file stream classes inherit the functionality of their base classes
...
Thus every file stream has:





methods for non-formatted writing and reading of single characters and/or data
blocks
the operators << or >> for formatted reading and writing from or to files
methods and manipulators for formatting character sequences
methods for state queries
...


384



CHAPTER 18



FUNDAMENTALS OF FILE INPUT AND OUTPUT

CREATING FILE STREAMS

Sample program
// showfile
...
e
...

// Call: showfile filename
// ---------------------------------------------------#include
#include
using namespace std;
int main( int argc, char *argv[])
{
if( argc != 2 )
// File declared?
{
cerr << "Use: showfile filename" << endl;
return 1;
}
ifstream file( argv[1]);
// Create a file stream
// and open for reading
...

{
cerr << "An error occurred when opening the file "
<< argv[1] << endl;
return 2;
}
char line[80];
int cnt = 0;
while( file
...

if( ++cnt == 20)
{
cnt = 0;
cout << "\n\t ---- to continue ---- "
<< endl;
cin
...
get();
}
}
if( !file
...
To do so, you can



state the file name, which can also contain a path
define a so-called file access mode
...
The file
access mode specifically defines whether read and/or write access to the file is permitted
...


ᮀ File Stream Definition
You can open a file when you create a file stream—you simply state the file name to do
so
...


Example: ifstream myfile("test
...
fle is passed to the constructor of the ifstream class, which
opens the file for reading
...
When a file is opened, the current file position is the beginning of the file
...
In
this case a new file is created
...
fle");
This statement creates a new file called new
...
But be
careful! If the file already exists, it will be truncated to a length of zero bytes, or in other
words deleted
...


Example: ofstream yourfile;
yourfile
...
fle");

This example has the same effect as the previous example
...

It rarely makes sense to use fixed file names
...
If no file name is supplied, the program issues an error message and terminates
...


386



CHAPTER 18



FUNDAMENTALS OF FILE INPUT AND OUTPUT

OPEN MODES

Flags for the open mode of a file
Flag

Effects

ios::in
ios::out

Opens a file for output
...


ios::app

Opens a file for output at the end-of-file
...


ios::ate

Open and seek to end immediately after opening
...


ios::binary



Opens an existing file for input
...


NOTE
1
...

2
...
When you read from or
write to a text file, control characters to indicate newlines or the end-of-file are interpreted separately and adapted to the current platform (so-called “cooked mode”)
...


Default settings when opening a file
The constructor and the method open() of all stream classes use the following default
values:

Class

Flags

ifstream

ios::in

ofstream

ios::out | ios::trunc

fstream

ios::in | ios::out

OPEN MODES



387

To open a file in any but the default mode, you must supply both the file name and the
open mode
...


ᮀ Open Mode Flags
In addition to the file name, you can pass a second argument for the open mode to the
constructors and the open() method
...
A
flag represents a single bit in a computer word
...

You can use the bit operator, |, to combine various flags
...
If the flag ios::in is raised, the file must already
exist
...


Example: fstream addresses("Address
...
The file is created, if it does not already exist
...

You can use the default mode for the fstream class, that is, ios::in | ios::out,
to open an existing file for reading and writing
...


ᮀ Error Handling
Errors can occur when opening a file
...
The state flag failbit of the ios base class
is raised in this case
...


Example: if( !myfile)

// or: if( myfile
...
If a read operation fails, the end
of the current file may have been reached
...
eof())

// At end-of-file?

The eof bit is set if you try to carry on reading at the end of a file
...


388



CHAPTER 18



FUNDAMENTALS OF FILE INPUT AND OUTPUT

CLOSING FILES

Sample program
// fcopy1
...

// Call: fcopy1 source [ destination ]
// ---------------------------------------------------#include
#include
using namespace std;
inline void openerror( const char *file)
{
cerr << "Error on opening the file " << file << endl;
exit(1);
// Ends program closing
}
// all opened files
...
is_open())
openerror( argv[1]);
if( argc == 2)
// Just one sourcefile
...
is_open() )
openerror( argv[2]);
copy( infile, outfile);
outfile
...

}
infile
...

return 0;
}
void copy( istream& is, ostream& os) // Copy it to os
...
get(c) )
os
...


A program that terminates correctly will automatically close any open files before exiting
...
However, if the
file is no longer in use before this point, you should close the file explicitly
...


Example: myfile
...
It is therefore possible to use the stream
to open and manipulate another file
...
In the case of the myfile file stream, the
test is as follows:

Example: if( myfile
...
*/ }

// File is open

ᮀ The exit() Function
Open files are also closed when you call the global function exit()
...


Prototype: void exit( int status );
The calling process, to which the status error code is passed for evaluation, will
often be the command interpreter—a Unix shell, for example
...
The statement return n; is thus equivalent
to the statement exit(n); when used in the main() function
...
If the user
forgets to state a second (target) file, the source file is copied to standard output
...


390



CHAPTER 18



FUNDAMENTALS OF FILE INPUT AND OUTPUT

READING AND WRITING BLOCKS

Sample program
// Pizza_W
...

// --------------------------------------------------#include
#include
using namespace std;
char header[] =
"
* * * P I Z Z A P R O N T O * * *\n\n";
// Record structure:
struct Pizza { char name[32]; float price; };
const int MAXCNT = 10;
Pizza pizzaMenu[MAXCNT] =
{
{ "Pepperoni", 9
...
90F },
{ "Ham Pizza", 12
...
90F } };
int cnt = 4;
char pizzaFile[256] = "pizza
...

<< endl;

// To write data into the file:
int exitCode = 0;
ofstream outFile( pizzaFile, ios::out|ios::binary );
if( !outFile)
{
cerr << "Error opening the file!" << endl;
exitCode = 1;
}
else
{
for( int i = 0; i < cnt; ++i)
if( !outFile
...

This means you can write formatted or unformatted data to a file or read that data from
the file block by block or character by character
...
Formatted input and output of
numerical values, for example, requires the >> and << operators and appropriate manipulators or formatting methods
...
34;
ofstream textFile("Test
...
txt will contain a line of text, such as "Price
...

Converting binary data to legible text is not practicable if you are dealing with large
amounts of data
...
To do so, you simply open the file
in binary mode and write the data to the file, or read it from the file, block by block
...


Prototype: ostream& write( const char *buf, int n);
Since write() returns a reference to the stream, you can check to ensure that the write
operation was successful
...
write("An example ", 2) )
cerr << "Error in writing!" << endl;

A warning is issued if an error occurs while writing the characters "An"
...
The method transfers a data block
from a file to a program buffer
...

The block that needs to be transferred can contain one or more records
...
You need to cast the address of this memory area to (char *) as shown
in the example opposite
...

// Constructors, destructor,
// access methods,
...

// Returns: The given stream
...
write((char*)&nr, sizeof(nr) );
os
...

// read() inputs an account from the stream is
// and writes it into the members of the current object
istream& Account::read(istream& is)
{
getline( is, name, '\0');
// Read a string
is
...
read( (char*)&balance, sizeof(balance));
return is;
}

OBJECT PERSISTENCE



393

ᮀ Storing Objects
Objects are created during program runtime and cleaned up before the program terminates
...
However, you must ensure that the object can be reconstructed, as it
was, when read
...
You will generally not know how to store a
member object
...
However, it does not make sense
to store pointer values in a file, as the memory addresses will change each time
you re-launch the program
...
As string type objects are used to handle variable
length strings, the object just contains a reference to the string
...
Instead, you should write the string itself to a file
...
Another solution involves providing methods to
allow the objects to write their own data members to files or read them from files
...


ᮀ Storing Account Class Objects
The opposite page shows the Account class, with which you are already familiar
...
A file stream that references a
file opened in binary mode is passed as an argument to the methods read() and
write()
...


Example: if( ! anAccount
...


Example: if( ! anAccount
...
The << operator and the function getline() are available for this
task
...
If file2 already exists, it is overwritten
...

fcopy

For calls without arguments, the source and destination files are entered
in a user dialog
...
read(buf, 1024);

transfers the next 1024 bytes from file to the buffer buf
...
In this case the fail and eof bits are set
...
The method
gcount() returns the number of bytes transferred by the last read
operation
...
gcount();

// Number of bytes
// in last read op
...
Write a program named fcopy to enhance
fcopy1 as follows:








If the program is launched without any arguments, it does not issue an
error message and terminate but requests user input for the names of the
source and target files
...

If the command line or the user dialog contains valid source and target
file names, a binary copy operation is performed
...

The default block size is 1024 bytes
...


Also refer to the notes on the opposite page
...
Modify the sample program Pizza_w
...

b
...
cpp, which displays the pizza
menu, that is, outputs the contents of the pizza file
...
To do so, write a
program called Account_rw
...


Use binary mode for read or write access to the file
...


New methods:
const string& getFilename() const;
bool setFilename( const string& fn);
bool isDirty() const;
bool load();
bool save();
bool saveAs();

// Read data from the file
// Save data
...


Extended menu of the application program
* * * * *

Telephone List

* * * * *

S = Show all entries
F = Find a telephone number
A = Append an entry
D = Delete an entry
----------------------------------------O = Open a file
W = Save in the file
U = Save as
...

To allow this, first add the data members and methods detailed on the
opposite page to TelList
...
The dirty flag is raised to indicate that the phone list has been
changed but not saved
...

The strings in the phone list must be saved as C strings in a binary file,
allowing for entries that contain several lines
...

W = Save

Save the current phone list in a file
...


Save the current phone list in a new file
...
These methods return true for a
successful action and false otherwise
...

If the phone list has been modified but not saved, the user should be
prompted to save the current phone list before opening another file or
terminating the program
...
cpp
// Copy files
// Call: fcopy [ source [ destination ] ]
// ---------------------------------------------------#include
#include
using namespace std;
char usage[] = "Call: fcopy [source [destination]}";
inline void openerror( const char *file)
{
cerr << "Error opening the file " << file << endl;
exit(1);
}
bool copy( istream& is, ostream& os),
ok = true;

// Prototype,
// ok flag
...

cout << "Copying source file to "
"destination file!\n"
"Source file: ";
cin
...
sync();
// No previous input
cout << "Destination file: ";
cin
...

strcpy( source, argv[1]);
break;
case 3:
// Source and destination files are declared
...

cerr << usage << endl;
return 2;
// or: exit(2);
}
if( strlen(dest) == 0)
// Only source file?
{
// yes ==> output to cout
...

}
else
// Copy source to destination
{
// file in binary mode
...

const int BufSize = 1024;
char buf[BufSize];
do
{
is
...
gcount() > 0)
os
...
gcount());
}
while( !is
...
fail() && !os
...
eof() ) return false;
else
return true;
}

399

400



CHAPTER 18

FUNDAMENTALS OF FILE INPUT AND OUTPUT

Exercise 2
// ---------------------------------------------------// Pizza
...
cpp and Pizza_R
...

// ---------------------------------------------------#include
#include
#include
using namespace std;
// Structure of a record:
struct Pizza { char name[32]; float price; };
#define MAXCNT
20
// Maximum number of pizzas
#define FILENAME "pizza
...
cpp
// Demonstrating blockwise writing of records
...
h"
Pizza pizzaMenu[MAXCNT] =
{
{ "Pepperoni", 9
...
90F },
{ "Ham Pizza", 12
...
90F } };
int cnt = 4;
char pizzaFile[256] = FILENAME;
int main()
// Write records
...
name
<< setw(10) << pizzaMenu[i]
...
sync(); cin
...
getline( pizzaMenu[cnt]
...
name[0] == '\0')
break;
cout << "Price: ";
cin >> pizzaMenu[cnt]
...
and the next pizza!\n"
<< "Stop with
...
write( (char*)&pizzaMenu[i],
sizeof(Pizza)) )
{
cerr << "Error writing to file!"
<< endl;
exitCode = 2;
}
}
if( exitCode == 0)
cout << "\nData added to file " << pizzaFile
<< "
...
cpp
Demonstrating block by block reading of records
...
h"
char pizzaFile[256] = FILENAME;
int main()
{
header();

// Read and display records
...
read( (char*)&onePizza, sizeof(Pizza)) )
break;
else
{
cout << setw(20) << onePizza
...
price << endl;
++cnt;
}
cout << "\n------------------------------------------\n"
<< endl;
if( !inFile
...
cpp
Writes an array with objects of class Account to
a file and feed the array into another array
...
h"
#include
#include
using namespace std;

// Definition of the class Account

Account AccTab1[3] =
{
Account("Lucky, Luke", 707070, -1200
...
0),
Account("Snoopy, Dog\n"
// String can contain more
"Cell #: 01771234567", 543001) // than one line
...
fle";
int main()
{
int i = 0;
// --- Write accounts to file --ofstream outFile( file, ios::out | ios::binary );
if( ! outFile)
{
cerr << "Error opening file " << file
<< endl;
return 1;
}
for( i = 0; i < cnt; ++i)
if( !AccTab1[i]
...
close();

403

404



CHAPTER 18

FUNDAMENTALS OF FILE INPUT AND OUTPUT

// --- Reads accounts from file --ifstream inFile( file, ios::out | ios::binary );
if( ! inFile)
{
cerr << "Error opening file " << file
<< endl;
return 3;
}
for( i = 0; i < cnt; ++i)
if( !AccTab2[i]
...
close();
// --- Displays the accounts read --cout << "The file " << file << " contains the "
<< "following accounts:" << endl;
for( i = 0; i < cnt; ++i)
AccTab2[i]
...
h
A class TelList to represent a list
containing names and telephone numbers
...

--------- ---------------------------------------------

#ifndef _TelList_
#define _TelList_
#include
using namespace std;
#define PSEUDO -1
#define MAX 100

// Pseudo position
// Maximum number of elements

SOLUTIONS



// Type of a list element:
struct Element { string name, telNr; };
class TelList
{
private:
Element v[MAX];
int count;
string filename;
bool dirty;

// The array and the actual
// number of elements
...


public:
TelList() : count(0), filename(""), dirty(false)
{}
int getCount() { return count; }
Element *retrieve( int i )
{
return (i >= 0 && i < count)? &v[i] : NULL;
}
bool append( const Element& el )
{
return append( el
...
telNr);
}
bool append( const string& name, const string& telNr);
bool erase( const string& name);
int search( const string& name) const;
void print() const;
int print( const string& name) const;
int getNewEntries();
const string& getFilename() const { return filename; }
bool setFilename( const string& fn)
{ if( fn
...
cpp
// Implements the methods of class TelList
...
h"
// Definition of class TelList
#include
#include
#include
using namespace std;

405

406



CHAPTER 18

FUNDAMENTALS OF FILE INPUT AND OUTPUT

bool TelList::append( const string&
const string&
{
if( count < MAX
&& name
...
name = name;
v[count]
...

--count;
dirty = true;
return true;
}
return false;
}
// -------------------------------------------------// Methods search(), print(), getNewEntries()
// are unchanged (refer to solutions of chapter 16)
...

bool TelList::load()
{
cout << "\n--- Load the telephone list "
<< "from a file
...

cin
...
clear();
// No previous input
getline( cin, file);
if( file
...
c_str(), ios::in | ios::binary);
if( !infile )
{
cerr << "File " << file
<< " could not be opened!" << endl;
return false;
}
int i = 0;
while( i < MAX)
{
getline( infile, v[i]
...
telNr, '\0');
if( !infile)
break;
else
++i;
}
if( i == MAX)
cerr << "Max capacity " << MAX
<< " has been reached!" << endl;
else if( !infile
...
--"
<< "\nFile: ";
string file;
// Input file name
...
sync(); cin
...
empty())
return saveAs();
if( !dirty)
return true;

// Save the telephone list
...
c_str(),
ios::out | ios::binary);
if( !outfile )
{
cerr << "File " << filename
<< " could not be opened!" << endl;
return false;
}
int i = 0;
while( i < count)
{
outfile << v[i]
...
telNr << '\0';
if( !outfile)
break;
else
++i;
}
if( i < count)
{
cerr << "Error writing to file " << filename << endl;
return false;
}
dirty = false;
return true;
}
// ------------------------------------------------------// TelList_
...

// ------------------------------------------------------#include "telList
...


SOLUTIONS



inline void go_on()
{
cout << "\n\nGo on with return! ";
cin
...
clear();
// No previous input
while( cin
...

char header[] =
"\n\n
* * * * * Telephone List * * * * *\n\n";
TelList myFriends;
// A telephone list
int main()
{
int action = 0;
// Command
string name;
// Read a name
while( action != 'Q')
{
action = menu();
cls(); cout << header << endl;
switch( action)
{
// --------------------------------------------------//
case 'S': case 'F': case 'A': case 'D':
//
unchanged (refer to the solutions of chapter 16)
...
isDirty() && askForSave() == 'y')
myFriends
...
load())
cout << "Telephone list read from file "
<< myFriends
...

if( myFriends
...
getFilename() << " !" <else
cerr << "Telephone list not saved!" << endl;
go_on();
break;

409

410



CHAPTER 18

FUNDAMENTALS OF FILE INPUT AND OUTPUT

case 'W':
// Save
if( myFriends
...
getFilename() << endl;
else
cerr << "Telephone list not saved!"
<< endl;
go_on();
break;
case 'Q':
if( myFriends
...
save();
cls();
break;
}
} // End of while
return 0;

&&

// Quit
askForSave() == 'Y')

}
int menu()
{
static char menuStr[] =
//
...
"
"\n
-------------------------------------"
"\n
Q = Quit the program"
"\n\n Your choice: ";
// --------------------------------------------------// everything else unchanged (cf
...
get(c);
c = toupper(c);
}while( c != 'Y' && c != 'N');
return c;
}

chapter

19

Overloading Operators
Overloading operators allows you to apply existing operators to objects
of class type
...

This chapter describes various uses of overloaded operators
...

The concept of friend functions, which is introduced in this context, is
particularly important for overloading operators
...
This meaning can be changed for classes by a definition of your own
...
The definition scope of an
operator is simply extended—the characteristics of the operator remain unchanged
...

You cannot redefine the operators for fundamental types
...
A binary operator will always be
binary and a unary operator will always be unary
...


GENERALS



413

ᮀ Overloading
An operator is said to be overloaded if it is defined for multiple types
...

Most operators are already overloaded for fundamental types
...
If both operands are integral types, an integral division is performed; in all
other cases floating-point division occurs
...


ᮀ Operators for Classes
In addition to defining methods, C++ offers the interesting possibility of defining the
functionality of a class by means of operators
...
For the objects x and y in this
class:
is equivalent to x
...
Expressions using operators are often more intuitive, and thus
easier to understand than expressions containing function calls
...

This applies to the string class, with which you are already familiar
...

cout << str1;
str2[2] = 'i';

//
//
//
//

Operator +=
Operator <
Operator <<
Operators [] and =

The tables on the opposite page show those operators that can be overloaded
...
::
?:


...


414



CHAPTER 19



OVERLOADING OPERATORS

OPERATOR FUNCTIONS (1)

Operators < and ++ for class DayTime
// DayTime
...

// --------------------------------------------------#ifndef _DAYTIME_
#define _DAYTIME_
class DayTime
{
private:
short hour, minute, second;
bool overflow;
public:
DayTime( int h = 0, int m = 0, int s = 0);
bool setTime(int hour, int minute, int second = 0);
int getHour()
const { return hour;
}
int getMinute() const { return minute; }
int getSecond() const { return second; }
int asSeconds() const
// Daytime in seconds
{ return (60*60*hour + 60*minute + second); }
bool operator<( const DayTime& t) const // compare
{
// *this and t
return asSeconds() < t
...

return *this;
}
void print() const;
};
#endif
// _DAYTIME_

Calling the Operator <
#include "DayTime
...

DayTime depart1( 11, 11, 11), depart2(12,0,0);

...


OPERATOR FUNCTIONS (1)



415

ᮀ Naming Operator Functions
To overload an operator, you just define an appropriate operator function
...
The name of an operator
function must begin with the operator keyword followed by the operator symbol
...

An operator function can be defined as a global function or as a class method
...

However, it can make sense to define an operator function globally
...


ᮀ Operator Functions as Methods
If you define the operator function of a binary operator as a method, the left operand will
always be an object of the class in question
...
The second, right operand is passed as an argument to the method
...


Example: bool operator<( const DayTime& t) const;
In this case the lesser than operator is overloaded to compare two DayTime objects
...

The prefix operator ++ has been overloaded in the example on the opposite page to
illustrate overloading unary operators
...
The function is called if the object a in the expression ++a is an
object of class DayTime
...
The expression is thus equivalent to
depart1
...
The previous function call is therefore technically correct
...
However, you should be
aware of the fact that an operator function should perform a similar operation to the corresponding operator for the fundamental type
...


416



CHAPTER 19



OVERLOADING OPERATORS

OPERATOR FUNCTIONS(2)

Class Euro
// Euro1
...

// -------------------------------------------------------#ifndef _EURO_H_
#define _EURO_H_
#include
// The class stringstream
#include
using namespace std;
class Euro
{
private:
long data;
// Euros * 100 + Cents
public:
Euro( int euro = 0, int cents = 0)
{
data = 100L * (long)euro + cents;
}
Euro( double x)
{
x *= 100
...
0 ? x+0
...
5); //ex
...
7 -> 10
}
long getWholePart() const { return data/100; }
int getCents() const { return (int)(data%100); }
double asDouble() const { return (double)data/100
...

void print( ostream& os) const // Output to stream os
...
data = -data;
return temp;
}
Euro operator+( const Euro& e2) const
// Addition
...
data = data + e2
...

{ /* Analog just as operator + */ }
Euro& operator+=( const Euro& e2)
// Add Euros
...
data;
return *this;
}
Euro& operator-=( const Euro& e2); // Subtract euros
...


OPERATOR FUNCTIONS(2)



417

ᮀ Notes on the Sample Class Euro
The opposite page shows the Euro class, which represents the new European currency
...


Thus data/100 returns the number of euros and data%100 the number of cents
...

In addition to a constructor that is passed whole euros and cents as arguments, there is
a constructor that can process a double value of euros and a standard copy constructor
...
07), e3(-e1);

ᮀ Negation, Addition, and Subtraction
The unary operator - does not change its operand
...
The operator function is
thus a const method that creates and returns a temporary object
...
Thus, the operator
functions also create temporary objects and return them with the correct values
...
operator+(e2)
...


ᮀ The += and -= Operators
Although the operators + and - were overloaded for the Euro class, this does not automatically mean that the operators += and -= are overloaded
...
Of course, you should overload the operators to ensure
that the statements

Example: sum += e3;

and

sum = sum + e3;

produce the same results
...
A
temporary object is not required! The expression sum += e3 represents the current
object after modification
...


418



CHAPTER 19



OVERLOADING OPERATORS

USING OVERLOADED OPERATORS

File Euro1
...
h
// -------------------------------------------------------inline string Euro::asString() const // Euro as string
{
stringstream strStream;
// Stream for conversion
long temp = data;
if( temp < 0) { strStream << '-'; temp = -temp; }
strStream << temp/100 << ','
<< setfill('0') << setw(2) << temp%100;
return strStream
...
cpp
// Tests the operators of class Euro
...
h"
// Definition of the class
#include
using namespace std;
int main()
{
cout << "* * * Testing the class Euro * * *\n" << endl;
Euro wholesale( 20,50), retail;
retail = wholesale;
// Standard assignment
retail += 9
...
49
cout << "Wholesale price: ";
wholesale
...
print(cout);
Euro discount( 2
...
print(cout);
wholesale = 34
...
print(cout);
Euro profit( retail - wholesale);
// Subtraction and
// copy constructor
cout << "\nThe profit: ";
profit
...


Example: Euro

wholesale(15,30), retail,
profit(7,50), discount(1,75);
retail = wholesale + profit;
// Call: wholesale
...
operator-=( discount)
retail += Euro( 1
...
operator+=( Euro(1
...
However, you can also add or subtract int or double types
...
This allows a function that expects a Euro value as argument to process int or
double values
...
49;
is valid
...
Since there is no operator function with
these characteristics, the compiler converts the double value to Euro and calls the
existing operator function for euros
...


Example: retail = wholesale + 10;

// ok
// ok

wholesale = retail - 7
...
operator+( Euro(10));

But the following statement is invalid!

Example: retail = 10 + wholesale;

// wrong!

Since the operator function was defined as a method, the left operand must be a class
object
...
However, if
you want to convert both operands, you will need global definitions for the operator
functions
...
The
overloaded operator -> enables the use of objects in the same way as pointers
...
h
// The class Euro represents a Euro with
// global operator functions implemented for + and -
...

class Euro
{
// Without operator functions for + and -
...

};
// ---------------------------------------------------// Global operator functions (inline)
// Addition:
inline Euro operator+( const Euro& e1, const Euro& e2)
{
Euro temp(e1);
temp += e2;
return temp;
}
// Subtraction:
inline Euro operator-( const Euro& e1, const Euro& e2)
{
Euro temp(e1);
temp -= e2;
return temp;
}
#endif
// _EURO_H_

GLOBAL OPERATOR FUNCTIONS



421

ᮀ Operator Functions: Global or Method?
You can define an operator function as a global function instead of a method
...

+=

-=

*=

/=

%=

These operators always require a so-called l-value as their left operand, that is, they
require an object with an address in memory
...
g
...
g
...


ᮀ Defining Global Operator Functions
The operands for a global operator function are passed as arguments to that function
...

The Euro class has been modified to provide a global definition of the operator functions for the operators + and -
...
More specifically, conversion of int or double to Euro
is performed for both operands now
...
20

and

1
...
20)
operator+( 1
...
The function operator+() shown opposite therefore uses the += operator, whose operator
function is defined as a method
...


422



CHAPTER 19



OVERLOADING OPERATORS

FRIEND FUNCTIONS

Class Euro with friend functions
// Euro
...

// --------------------------------------------------#ifndef _EURO_H_
#define _EURO_H_
//
...

// Operators -(unary), +=, -= as before
...
0/x));
}
// Global friend functions
friend Euro operator+( const Euro& e1, const Euro& e2);
friend Euro operator-( const Euro& e1, const Euro& e2);
friend Euro operator*( const Euro& e, double x)
{
Euro temp( ((double)e
...
0) * x) ;
return temp;
}
friend Euro operator*( double x, const Euro& e)
{
return e * x;
}
};
// Addition:
inline Euro operator+( const Euro& e1, const Euro& e2)
{
Euro temp;
temp
...
data + e2
...
data = e1
...
data;
return temp;
}
#endif
// _EURO_H_

FRIEND FUNCTIONS



423

ᮀ The Friend Concept
If functions or individual classes are used in conjunction with another class, you may
want to grant them access to the private members of that class
...

Imagine you need to write a global function that accesses the elements of a numerical
array class
...
However, special permission to access the private data members of the class can dramatically
improve the function’s response
...

This is achieved by declaring the function as a friend
...


Example: class A
{ //
...
This allows them direct access to the private
members of class A
...
To resolve this issue, you will generally pass the object the function needs to process as an argument
...
If this were
not so, data encapsulation could easily be undermined
...

In order to compute interest, it is necessary to multiply and divide euros by double
values
...
As the example shows, friend functions can also be defined inline in a class
...
h
// The class Result to represent a measurement
// and the time the measurement was taken
...
h"
// Class DayTime
class Result
{
private:
double val;
DayTime time;
public:
// Constructor and access methods
friend class ControlPoint; // All methods of
};
// ControlPoint are friends
...
h
class ControlPoint
{
private:
string name;
// Name of control point
Result measure[100];
// Table with results
//
...

// Compute static values of measurement results
// (average, deviation from mean,
...

};

FRIEND CLASSES



425

ᮀ Declaring Friend Classes
In addition to declaring individual friend functions, you can also make entire classes
“friends” of another class
...

This technique is useful if a class is used in such close conjunction with another class
that all the methods in that class need access to the private members of the other class
...
Calculations with individual measurements are performed repeatedly
...


Example: class Result
{
//
...
The Result class itself decides who its friends are and
who has access to its private members
...
However, you can regard a friend declaration as an extension of the
public interface
...


ᮀ Using Friend Functions and Classes
Using friend functions and friend classes helps you to create efficient programs
...
Some common uses are global operator functions declared as friend
functions
...
Allowing external functions to manipulate internal data can lead to inconsistency,
especially if a class is modified or extended in a later version
...


426



CHAPTER 19



OVERLOADING OPERATORS

OVERLOADING SUBSCRIPT OPERATORS

A class representing arrays
// Array_t
...

// -------------------------------------------------#include
#include
// For exit()
using namespace std;
#define MAX 100
class FloatArr
{
private:
float v[MAX];
// The array
public:
float& operator[](int i);
static int MaxIndex(){ return MAX-1; }
};
float& FloatArr::operator[]( int i )
{
if( i < 0 || i >= MAX )
{ cerr << "\nFloatArr: Outside of range!" << endl;
exit(1);
}
return v[i];
// Reference to i-th element
...

int i;
// An index
...
0F;
cout << "\nEnter indices between 0 and "
<< FloatArr::MaxIndex() << "!"
<< "\n (Quit by entering invalid input)"
<< endl;
while( cout << "\nIndex: " && cin >> i )
cout << i << "
...
It is a binary
operator and thus has two operands
...

The subscript operator for arrays implies background pointer arithmetic, for example,
v[i] is equivalent to *(v+i)
...


ᮀ Usage in Classes
These restrictions do not apply if the index operator is overloaded for a class
...
The following therefore applies:




the left operand must be a class object
the right operand can be any valid type
the result type is not defined
...
However, your overloading should always reflect
the normal use of arrays
...

Since an index can be of any valid type, the possibilities are unlimited
...


ᮀ Notes on the Sample Program
Range checking is not performed when you access the elements of a normal array
...
However, you can address this issue by defining your own array classes, although this may
impact the speed of your programs
...
The subscript operator [] has been overloaded to return a reference to the i-th array element
...
If an invalid index is found, the program issues an
error message and terminates
...
As we will see, variable lengths are possible using dynamic memory allocation
...
h : Class Euro to represent an Euro
// --------------------------------------------------#ifndef _EURO_H_
#define _EURO_H_
//
...

// The print() method is now superfluous
...
cpp
// Overload the shift operators
// for input/output of Euro type objects
...
h"
#include
using namespace std;
// Output to stream os
...
asString() << " Euro";
return os;
}
// Input from stream is
...
x,xx): ";
int euro = 0, cents = 0; char c = 0;
if( !(is >> euro >> c >> cents)) // Input
...
')
|| cents>=100)
// Error?
is
...

e = Euro( euro, cents);
// No => Accept
return is;
// value
...

However, the compiler can process the previous statement if it can locate a suitable
operator function, operator<<()
...


ᮀ Overloading the << Operator
In the previous example, the left operand of << is the object cout, which belongs to the
ostream class
...
The right operand is a Euro
class object
...
This allows for normal concatenation of operators
...


Example: cout << "Enter the price in Euros: "
cin >> price;

The second statement causes the following call:
operator>>( cin, price);

As cin is an object of the standard istream class, the first parameter of the operator
function is declared as a reference to istream
...

The header file Euro
...
To allow these
functions to access the private members of the Euro class, you can add a friend declaration within the class
...




CHAPTER 19



exercise s

430

OVERLOADING OPERATORS

EXERCISES

Prefix and postfix increment
To distinguish the postfix increment operator from the prefix increment
operator, the postfix operator function has an additional parameter of type int
...
operator++()

obj++



(Prefix)
(Postfix)

obj
...

The prefix and postfix decrement operators -- are distinguished in the same
manner
...
Now modify the class as follows:






Overload the relational operators
< > <= >= == and !=
and the shift operators
>> and << for input and output
using global operator functions
...

Then overload both the prefix and postfix versions of the ++ and -operators
...
The -- operator decrements the time by one second
...

Write a main function that executes all the overloaded operators and displays their results
...







Use a header file called fraction
...
The constructor has two
parameters of type long: the first parameter (numerator) contains the
default value 0, and the second parameter (denominator) contains the
value 1
...
The operator functions of the binary
operators +, -, *, / and the input / output operators <<, >> are to be
declared as friend functions of the Fraction class
...
If the denominator assumes a value
of 0, issue an error message and terminate the program
...
The formulae for arithmetic operations are shown
opposite
...
Output both the operands and the results
...
h
Class DayTime with all relational operators,
the operators ++ and -- (prefix and postfix),
such as the operators << and >> for input/output
...

second = 0, ++minute;
if( minute >= 60)
minute = 0, ++hour;
if( hour >= 24)
hour = 0, overflow = true;
}
void dec()
// private function for -{
--second;
if( second < 0)
// handle underflow
...
asSeconds() < t2
...
asSeconds() <= t2
...
asSeconds() == t2
...
getHour()
<< ':'
<< setw(2) << t
...
getSecond() << " Time";
os << setfill(' ');
return os;
}
istream& operator>>( istream& is, DayTime& t)
{
cout << "Enter daytime in hh:mm:ss format: ";
int hr = 0, min = 0, sec = 0;
char c1 = 0, c2 = 0;
if( !(is >> hr >> c1 >> min >> c2 >> sec))
return is;
if( c1 != ':' || c2 != ':' || ! t
...
setstate( ios::failbit);
// Error!
// => Set fail bit
...
cpp
// Testing the operators of class DayTime
...
h"
// Definition of the class
#include
using namespace std;
int main()
{
DayTime cinema( 20,30);
cout << "\nThe movie starts at " << cinema << endl;
DayTime now;
cout << "What time is it now?" << endl;
if( !(cin >> now) )
cerr << "Invalid input!" << endl;
else
cout << "\nThe time is now" << now << endl;
cout << "\nThe movie has ";
if( cinema < now)
cout << "already begun!\n" << endl;
else
cout << "not yet begun!\n" << endl;
cout << "Now it is
" << now++ << endl;
cout << "After 2 seconds: " << ++now << endl;
DayTime depart(16,0);
cout << "Let's go at " << --depart << endl;
if( depart >= now )
cout << "You can ride with us!" << endl;
else
cout << "We don't have room!" << endl;
return 0;
}



435

436



CHAPTER 19

OVERLOADING OPERATORS

Exercise 2
// -----------------------------------------------------// Fraction
...
numerator * denominator
+ numerator * a
...
denominator;
return *this;
}
Fraction& operator-=(const Fraction& a)
{
*this += (-a);
return *this;
}
Fraction& operator++()
{
numerator += denominator;
return *this;
}
Fraction& operator--()
{
numerator -= denominator;
return *this;
}

SOLUTIONS

friend
friend
friend
friend
friend
friend
};
#endif

Fraction
Fraction
Fraction
Fraction
ostream&
istream&



437

operator+(const Fraction&, const Fraction&);
operator-(const Fraction&, const Fraction&);
operator*(const Fraction&, const Fraction&);
operator/(const Fraction&, const Fraction&);
operator<< (ostream& os, const Fraction& a);
operator>> (istream& is, Fraction& a);

// ------------------------------------------------------// Fraction
...

// ------------------------------------------------------#include "Fraction
...
denominator = a
...
denominator;
temp
...
numerator*b
...
numerator * a
...
numerator = a
...
numerator;
temp
...
denominator * b
...
numerator == 0)
{
cerr << "\nError: Division by zero!\n";
exit(1);
}
// To multiply a by the inverse of b:
Fraction temp;
temp
...
numerator * b
...
denominator = a
...
numerator;
if( temp
...
numerator = -temp
...
denominator = -temp
...
numerator << "/" << a
...
numerator;
cout << " Denominator != 0: ";
is >> a
...
denominator == 0)
{
cout << "\nError: The denominator is 0\n"
" New denominator != 0: ";
is >> a
...
denominator == 0)
{
cerr << "\nError: Division by zero!\n"; exit(1);
}
}
if( a
...
numerator = -a
...
denominator= -a
...
cpp
Testing the class Fraction
...
cpp Fraction
...
h"
int main()
{
Fraction a(1,3), b(4);
cout << "\nSome test results:\n\n";
cout << " a = " << a << endl;
cout << " b = " << b << endl;
cout
cout
cout
cout

<<
<<
<<
<<

"
"
"
"

cout << "
cout << "

a
a
a
a

+
*
/

b
b
b
b

=
=
=
=

"
"
"
"

<<
<<
<<
<<

--a = " <<
++a = " <<

(a
(a
(a
(a

+
*
/

b)
b)
b)
b)

<<
<<
<<
<<

endl;
endl;
endl;
endl;

--a << endl;
++a << endl;

a += Fraction(1,2);
cout << " a+= 1/2; a = " << a << endl;
a -= Fraction(1,2);
cout << " a-= 1/2; a = " << a << endl;
cout << "-b = " << -b << endl;
cout << "\nAnd now an input\n";
cin >> a;
cout << "\nYour input: " << a << endl;
return 0;
}



439

This page intentionally left blank

chapter

20

Type Conversion for
Classes
Implicit type conversion occurs in C++ when an expression cannot be
compiled directly but can be compiled after applying a conversion rule
...

Finally, we discuss ambiguity occurring due to type conversion and
how to avoid it
...
41);
// double -> Euro
...
12;

// Implicit conversion:
// double -> Euro

your += 20;

// Implicit conversion:
// int -> Euro

your = Euro(999
...
45;

// Explicit conversion
// (cast style)

your = my;



// No conversion

NOTE
When the copy constructor performs a type conversion, a temporary object is first created and this
object is used in the assignment
...


CONVERSION CONSTRUCTORS



443

ᮀ Possible Type Conversions
Implicit and explicit type conversion is also performed for classes in C++
...
You can allow type conversion
between different classes or between classes and fundamental types
...


A conversion constructor performs type conversion by converting any given type to the
type of the current class
...


ᮀ Conversion Constructors
A constructor with a single parameter determines how to form an object of the new class
from the argument passed to it
...
The copy constructor is an exception to this rule: it
creates an object of the same class and does not perform type conversion
...
The standard string class contains a constructor that creates a string object
from a C string, for example
...


ᮀ Calling a Conversion Constructor
Conversion constructors have already been used in several examples; for example, in the
Euro class
...


Examples: Euro salary(8765
...
1;
salary += 897
...
Addition is not defined for a euro
and a double value
...
This object is then added to
the value of the salary object
...
h : The class Euro represents a euro
...

class Euro
{
private:
long data;
// Euros * 100 + Cents
public:
Euro( int euro = 0, int cents = 0);
Euro( double x);
// For conversion from Euro to double:
operator double() const { return (double)data/100
...
other methods as before
...
cpp : Testing conversions of class Euro
...
h"
// Definition of the class
#include
using namespace std;
int main()
{
cout << " * * * Testing Conversions * * * \n" << endl;
Euro salary( 8888,80);
double x(0
...
10;
// implicit double -> Euro
x = salary;
// implicit Euro -> double
x = (double)salary;
// explicit Euro -> double
x = salary
...
9
cout << "
i = " << i << endl;
// 9888
return 0;
}

CONVERSION FUNCTIONS



445

If you need to convert an object of the current class to another type, you must define a
conversion function to do so
...
Conversion functions are also automatically used by the compiler to perform
implicit and explicit type conversion
...
Its name
is made up of the operator keyword and the target type to convert to
...
You
may have noticed that the declaration of a conversion function does not contain a return
type
...
The target type can contain multiple keywords, such as
unsigned short or const float*
...

The Euro shown opposite contains a conversion function with a double target type
...


Example: double x = oneEuro;

// implicit

ᮀ Conversion Function versus Conversion Constructor
The target type of a conversion function can also be a class
...

If you do not want to modify the target class—perhaps because it is a standard class—
a conversion function will perform the task well
...
In the previous example, an int variable is assigned to a euro object by this
method
...


446



CHAPTER 20



TYPE CONVERSION FOR CLASSES

AMBIGUITIES OF TYPE CONVERSIONS

Explicit type conversion for class Euro
// Euro
...

// ----------------------------------------------------//
...
0;}
// No conversion function operator double(),
// or as previously seen
...
cpp
// Tests explicit conversion of class Euro
...
h"
// Class definition
#include
using namespace std;
int main()
{
Euro salary( 8888
...
0);
/* Now impossible:
salary += 1000;
salary += 0
...
77;
x = salary;
x = (double)salary;

// double constructor

// implicit int -> Euro
// implicit double -> Euro

// implicit Euro -> double
// There is no method
// operator double()
...
77);
// explicit double -> Euro
salary += Euro(1000
...
asDouble();
// explicit by method
// Euro -> double
int i = salary
...

The Euro class contains a conversion constructor that converts a double value to
euros
...


Example: retail = wholesale + 46
...
Since both conversion types double -> Euro and Euro -> double are
defined, two possible conversions could be performed:
prov2 + Euro(546
...
9;

// To add values
// of type double

However, the compiler can only perform implicit type conversion if the technique is not
ambiguous
...


ᮀ Avoiding Implicit Type Conversion
You can prevent ambiguities by stating any desired conversions explicitly
...
Moreover, undesirable type conversion, which can occur when classes are extended at a later date, can be
avoided
...
As the
example on the opposite page shows, only explicit calls to the constructor are
possible in this case
...
9)


// ok

implicit type conversions by conversion functions can be prevented by not defining the function, of course
...
Type conversion can only be performed by calling this
function explicitly
...
cpp
//
...

if( numerator == 0)
{
denominator = 1;
return;
}
// Calculating the greatest common divisor
// using an algorithm by Euclid
...
In addition,
fractions should be rounded after arithmetic operations
...
The method
computes the largest common divisor of numerator and denominator
...

Add an appropriate call to the simplify() function to all operator functions (except ++ and --)
...

Example: Fraction b(0
...
The following technique should suffice for numbers below
one million
...
5 for rounding
...
Set the value of the denominator to
1000
...

You now have a conversion constructor for long and double types
...
Define the appropriate conversion function inline
...
More specifically, use
assignments and arithmetic functions to do so
...

Output the operands and the results on screen
...
h
// A numerical class to represent fractions
...

// ------------------------------------------------------#ifndef _FRACTION_
#define _FRACTION_
#include ...
h>
class Fraction
{
private: long numerator, denominator;
public:
Fraction(long z, long n);
Fraction(double x);
// double-constructor
// Default long- and int-constructor:
Fraction(long z=0) : numerator(z), denominator(1) {}
Fraction(int z)
: numerator(z), denominator(1) {}
void simplify();
operator double()
// Fraction -> double
{
return (double)numerator / (double)denominator;
}
Fraction operator-() const
{ return Fraction(-numerator, denominator);
}
Fraction& operator+=(const Fraction& a)
{
numerator = a
...
denominator;
denominator *= a
...

};
#endif

SOLUTION

//
//
//
//
//



-------------------------------------------------------Fraction
...

--------------------------------------------------------

#include ...
h>
#include "Fraction
...

}
Fraction::Fraction( double x)
{
x *= 1000
...
0) ? 0
...
5;
numerator = (long)x;
denominator = 1000;
simplify();
}

// Round the 4th digit
...
denominator = a
...
denominator;
temp
...
numerator*b
...
numerator * a
...
simplify();
return temp;
}
// The functions
// operator-()
operator<<()
// are left unchanged
...
simplify()
// just like the function operator+()
...


451

452



CHAPTER 20

TYPE CONVERSION FOR CLASSES

// ------------------------------------------------------// Fract_t
...

// ------------------------------------------------------#include ...
h"
int main()
{
Fraction a, b(-1,5), c(2
...
5, y;
a = x;
// double -> Fraction
cout << "\nSome test results:\n" << endl;
cout << " a = " << a << endl;
cout << " b = " << b << endl;
cout << " c = " << c << endl;
cout << "\nThe fractions as double values:\n" << endl;
// Fraction -> double:
cout << " a = " << (double)a << endl;
cout << " b = " << (double)b << endl;
cout << " c = " << (double)c << endl;
cout
cout
cout
cout
cout

<<
<<
<<
<<
<<

"\nAnd calculate with:\n"
" a + b = " << (a + b) <<
" a - b = " << (a - b) <<
" a * b = " << (a * b) <<
" a / b = " << (a / b) <<

<< endl;
endl;
endl;
endl;
endl;

cin >> a;
// Enter a fraction
...
simplify();
cout << "\nSimplified:
" << a << endl;
cout << "\nAs double value: " << (double)a << endl;
cout << "\nEnter a floating point value: "; cin >> x;
cout << "\nThis is in fraction form:
"
<< (Fraction)x << endl;
// To calculate the sum b + x :
cout << " b = " << b << endl;
cout << " x = " << x << endl;
// a = b + x;
// Error: ambiguous!
a = b + Fraction(x);
// ok! To compute fractions
...

cout << " b + x as fraction:
" << a << endl;
cout << " b + x as double:
" << y << endl;
return 0;
}

chapter

21

Dynamic Memory
Allocation
This chapter describes how a program can allocate and release memory
dynamically in line with current memory requirements
...


453

454



CHAPTER 21



DYNAMIC MEMORY ALLOCATION

THE OPERATOR new

Sample calls to new
// Dynamic objects of type long and double
// -----------------------------------------------------long *ptr_long;
ptr_long = new long;
// No initialization
// of the long object
...
9;
ptr_double = new double(z);

// With initialization

++(*ptr_double);
*ptr_double += *ptr_long;

// Increment the value
// ok to add long value

ptr_long = new double(2
...
9

THE OPERATOR new



455

ᮀ Dynamic Memory Allocation
When a program is compiled, the size of the data the program will need to handle is
often an unknown factor; in other words there is no way to estimate the memory requirements of the program
...

Dynamically allocated memory can be released to continually optimize memory usage
with respect to current requirements
...

Programs can access a large space of free memory known as the heap
...

C++ uses the new and delete operators to allocate and release memory, and this
means that objects of any type can be created and destroyed
...


ᮀ Calling new for Fundamental Types
The new operator is an operator that expects the type of object to be created as an argument
...
The new operator creates an object of the specified
type and returns the address of that object
...
If the pointer belongs to a wrong type, the compiler will issue an error message
...

The previous call to new does not define an initial value for the new object, however,
you can supply a value in parentheses to initialize the object
...
99);
Following this statement pld points to a memory address containing a long double
type with a value of 10000
...
The statement
cout << *pld << endl;

will output this value
...
cpp
// The operators new and delete for built-in types
...

// --------------------------------------------------#include
using namespace std;
int main()
{
cout << "\nTesting dynamic storage allocation! "
<< endl;
// To allocate storage:
double width = 23
...
54);
double* ptrArea = new double;
// To work with ptrWidth, ptrLength, and ptrArea:
*ptrArea = *ptrWidth * *ptrLength;
delete ptrLength;
// Error: The object is still
// in use!
cout << "\nWidth
: " << *ptrWidth
<< "\nLength
: " << *ptrLength
<< "\nArea
: " << *ptrArea << endl;
// To free storage:
delete ptrWidth;
delete ptrLength;
delete ptrArea;
delete ptrLength;

//
//
//
//

Error: The object has not
been dynamically reserved
ok
ok

// Error: Pointer doesn't
// address any object
...
45);
// ok
// To give a name to a dynamic object:
double& length = *ptrLength;
// Reference
cout << "\nNew length
: " << length
<< "\nCircumference
: " << 2 * width * length
<< endl;
return 0;
// On terminating the program
}
// allocated storage will be freed
...
Failure to do so can impact the performance of your computer system
...


ᮀ Calling

delete

Memory that has been allocated by a call to new can be released using the delete operator
...
But make sure that this
memory space was dynamically allocated by a call to new!

Example: long *pl = new long(2000000);

...


If you do not call delete, the dynamically allocated memory space is not released until
the program terminates
...
In this case
nothing happens and delete just returns, so you do not need to check for NULL pointers when releasing memory
...

As the sample program illustrates, misuse of delete can be disastrous
...


ᮀ Error Handling for new
If there is not enough memory available, the so-called new handler is called
...
Thus, you do not need to design
your own error handling routines each time you call new
...
Exceptions can be
caught by the program, allowing the error condition to be remedied (refer to Chapter 28,
Exception Handling)
...

If you are working with an older compiler, please note that new returns a NULL
pointer if not enough memory is available
...
cpp
// The operators new and delete for classes
...
h"
#include
using namespace std;
Account *clone( const Account* pK);

// Create a copy
// dynamically
...
\n" << endl;
// To allocate storage:
Account *ptrA1, *ptrA2, *ptrA3;
ptrA1 = new Account;
ptrA1->display();

// With default constructor
// Show default values
...
87);
ptrA1->display();

//
//
//
//

Set the other
values by access
methods
...


// Use the constructor with three arguments:
ptrA2 = new Account("Xiang, Zhang", 7531357, 999
...

ptrA3 = clone( ptrA1);

// Pointer to a dyna// mically created copy
...

delete ptrA1;
delete ptrA2;
delete ptrA3;

// Release memory

return 0;
}
Account *clone( const Account* pK)
{
return new Account(*pK);
}

// Create a copy
// dynamically
...
In this case, in addition to allocating memory, a suitable constructor must
be called
...
However, the operators new and delete ensure that this happens
...
Unless
explicitly initialized, the default constructor is called for each new object, but you must
make sure that a default constructor exists!

Example: Euro* pEuro = new Euro;
This statement allocates memory for an object of the Euro class
...


ᮀ Explicit Initialization
To initialize an object explicitly, you can state its initial values in parentheses when you
call new
...
If the
compiler is unable to locate a suitable constructor, an error message occurs
...
The
object is initialized using the supplied values
...


Example: *pE += 200;

// To add 200 euros
...


Example: cout << pE->getCents() << endl;

// 33

ᮀ Releasing Memory
When an object that was created dynamically is destroyed, the delete operator makes
sure that the object is cleaned up
...

As previously discussed in the section on fundamental types, when you call delete
you must ensure that the pointer is addressing a dynamic object or that you are dealing
with a NULL pointer
...
cpp
// Operators new[] and delete[] for dynamic arrays
...
\n" << endl;
int size = 0, cnt = 0, step = 10,
i;
float x, *pArr = NULL;
cout << "Enter some numbers!\n"
"End with q or another character " << endl;
while( cin >> x)
{
if( cnt >= size)
// Array too small?
{
// => enlarge it
...
0;
cout << "Your input: " << endl;
for( i = 0; i < cnt; i++)
// To output and
{
// add
...
Your best option is to let the program create the array dynamically
...


ᮀ The new[ ] Operator
The new[ ] operator is available for creating dynamic arrays
...


Syntax:

vekPtr = new Type[cnt];

The pointer vekPtr will then reference the first of a total of cnt array elements
...
Of course, Type can also be a class
...
Those objects are
pk[0],

pk[1],


...
, *(pk + 255)
...
Starting values for the array elements cannot be assigned until later
...
To do so, simply call the delete[] operator
...


Example: delete[] pk;
The operand for delete[]—the pointer pk in this case—must reference the place in
memory that was allocated by a call to new[]! The destructor belonging to the current
class is called for each array element
...
e
...

The program on the opposite page stores numbers in a dynamic array
...
To do so, a newer bigger array is created, the data is copied
to the new array, and the memory occupied by the old array is released
...
A linked list is a dynamic data
structure that allows easy insertion and deletion of data
...

The type of data structure you choose has a far-reaching effect on the amount of
memory you need, the speed of access to the data involved, and the complexity (or simplicity) of the algorithms (data operations) you need
...
One
example of this is an array whose size can be changed during runtime
...
The first element in the list has no predecessor and the last
element no successor
...


ᮀ Advantages
The storage used for the list elements need not be contiguous
...


When an array element is inserted or deleted, the other array elements have to be moved
to make room or fill up the “gap” in the array
...


464



CHAPTER 21



DYNAMIC MEMORY ALLOCATION

REPRESENTING A LINKED LIST

Classes of header file List
...
h
// Defines the classes ListEl and List
...
h"
// Class Date from Chapter 14
#include
#include
using namespace std;
class ListEl
{
private:
Date date;
double amount;
ListEl* next;

// A list element
...
0,
ListEl* p = NULL)
: date(d), amount(b), next(p) {}
// Access methods:
// getDate(), setDate(), getAmount(), setAmount()
ListEl* getNext() const { return next; }
friend class List;
};
// ---------------------------------------------------// Defining the class List
class List
{
private:
ListEl* first, *last;
public:
List(){ first = last = NULL; } // Constructor
~List();
// Destructor
// Access to the first and last elements:
ListEl* front() const { return first; }
ListEl* back() const { return last; }
// Append a new element at the end of the list:
void pushBack(const Date& d, double b);
// Delete an element at the beginning of the list
void popFront();
};
#endif // _LIST_H_

REPRESENTING A LINKED LIST



465

ᮀ Representing List Elements
You can use a recursive data structure to represent a linked list
...
Of course,
the data structure cannot contain itself—that would be impossible—but it does contain a
pointer to itself
...
A
transaction is characterized by a date, a sum of money, and the reason for the transaction
...

The class shown on the opposite page, ListEl, was designed to represent list elements
...

The public declaration includes a constructor and access methods for the live data
...

It is common practice to let the pointer for the last element in the list point to NULL
...


ᮀ Representing a List
To identify a linked list, you just point a pointer at the first element in the list
...

A pointer to the last element in the list is useful for appending new elements
...
The private section
comprises two pointers, which reference the first and last list elements respectively
...
The destructor has a more complex task: it has to release the memory occupied
by the remaining list elements
...
To
do so, memory is allocated dynamically and the new element becomes the successor of
what was previously the last element and the last pointer is updated
...

The popFront() method deletes the first element in the list
...
The special case with an empty list also applies
...


Arguments:
Return value:

The two int arrays, their length, and the position at which
they are to be spliced
...

Arguments:
Return value:

The two int arrays and their length
...


Exercise 3
Complete and test the implementation of a linked list found in this chapter
...
Then overload the <<
operator for the class ListEl to allow formatted output of the data in
the list elements
...

Then implement the destructor for the List class
...
Make sure that
you read the pointer to the successor of each element before destroying
it!
Implement the methods pushBack() and popFront() used for appending and deleting list elements
...

Test the List class by inserting and deleting several list elements and
repeatedly outputting the list
...
cpp
// Implements the splice algorithm
...

using namespace std;
// Prototype:
int *splice( int v1[], int len1,
int v2[], int len2, int pos);
int main()
{
cout << "\n * * * Testing the splice function * * *\n"
<< endl;
int i, len1 = 10, len2 = 5;
int *a1 = new int[len1],
*a2 = new int[len2];
// Initialize the random number generator
// with the current time:
srand( (unsigned)time(NULL));
for( i=0; i < len1; ++i)
a1[i] = rand();
for( i=0; i < len2; ++i)
a2[i] = -rand();

// Initialize the arrays:
// with positive and
// negative numbers
...
array: " << endl;
for( i = 0; i < len1; ++i)
cout << setw(12) << a1[i];
cout << endl;
cout << "2
...
, " << len1
<< " : ";
int pos;

cin >> pos;

SOLUTIONS



int *a3, len3 = len1 + len2;
a3
= splice( a1, len1, a2, len2, pos);
if( a3 == NULL)
cerr << "\n Invalid position!\n" << endl;
else
{
cout << " The new spliced array: " << endl;
for( i = 0; i < len3; ++i)
cout << setw(12) << a3[i];
cout << endl;
}
delete[] a1;
delete[] a2;
delete[] a3;
return 0;
}
// ------------------------------------------------------// Function splice() inserts the array v2 into v1
// starting at position pos
...
cpp
// Implements the merge algorithm
...

selectionSort( a2, len2);
// To sort array a2
...

inline void swap( int& a, int& b)
// To swap
...

minp = p;
swap( *arr, *minp);
// To swap
...

int *merge( int v1[], int len1, int v2[], int len2)
{
int i = 0, i1 = 0, i2 = 0;
int *v = new int[len1+len2];
// New int array
...

while( i1 < len1)
v[i++] = v1[i1++];
else
while( i2 < len2)
v[i++] = v2[i2++];
return v;
}

471

472



CHAPTER 21

DYNAMIC MEMORY ALLOCATION

Exercise 3
//
//
//
//
//
//
//
//
//
//
//

---------------------------------------------------date
...

---------------------------------------------------date
...

---------------------------------------------------These files are left unchanged
from Chapter 14 (solutions)
...
h
// Defines the classes ListEl and List
// to represent a linked list
...
h"
#include
#include
using namespace std;
class ListEl
{
private:
Date date;
double amount;
ListEl* next;

// Date
// Amount of money
// Pointer to successor

public:
ListEl( Date
d = Date(1,1,1),
double b = 0
...
setDate();
}
bool setDate( int day, int month, int year)
{
return setDate( day, month, year);
}

SOLUTIONS

double getAmount() const { return amount; }
void
setAmount(double a) { amount = a; }
ListEl* getNext() const { return next; }
friend class List;
};
// Output an element
ostream& operator<<( ostream& os, const ListEl& le);
// -----------------------------------------------------// Defines the List class
class List
{
private:
ListEl* first, *last;
public:
List(){ first = last = NULL; } // Constructor
~List();
// Destructor
// Access first and last elements:
ListEl* front() const { return first; }
ListEl* back() const { return last; }
// Appends a new element at the end of the list:
void pushBack(const Date& d, double b);
// Deletes an element at the beginning of the list
...
cpp
// Implements the methods of class List,
// which are not previously defined inline
...
h"
// Destructor of the list:
List::~List()
{
ListEl *pEl = first, *next = NULL;
for( ; pEl != NULL; pEl = next)
{
next = pEl->next;
delete pEl;
}
}



473

474



CHAPTER 21

DYNAMIC MEMORY ALLOCATION

// Appends a new element at the end of the list:
void List::pushBack(const Date& d, double b)
{
ListEl *pEl = new ListEl( d, b);
if( last == NULL)
// List empty?
first = last = pEl;
else
last->next = pEl, last = pEl;
}
// Deletes an element from the beginning of the list
...

first = first->next;
// Move to the next element
...
getDate()
...
getAmount();
return os;
}
// Outputs the list:
ostream& operator<<( ostream& os, const List& List)
{
ListEl *pEl = List
...
cpp
// Tests the List class
...
h"
int main()
{
cout << "\n * * *
<< endl;
List

Testing the class list

aList;

cout << aList << endl;

* * *\n"

// A list
// List is still empty
...
g
...
setDate( month, day, year) )
break;
// Invalid date
...
pushBack( date, amount);
}
cout << "\nContent of the list:\n";
cout << aList << endl;
cout << "\nRemoving the first element of the list:\n";
ListEl *ptrEl = ptrEl = aList
...
popFront();
}
cout << "\nContent of the list:\n";
cout << aList << endl;
return 0;
}

475

This page intentionally left blank

chapter

22

Dynamic Members
This chapter describes how to implement classes containing pointers to
dynamically allocated memory
...


A class designed to represent arrays of any given length is used as a
sample application
...
1 6
...
2 2
...


4

Data members of class FloatArr
// A class representing dynamic arrays of floats
...

int cnt;
// Number of present elements
public:
// Public methods here
};

MEMBERS OF VARYING LENGTH



479

ᮀ Dynamic Members
You can exploit the potential of dynamic memory allocation to leverage existing classes
and create data members of variable length
...
In order to do this the class needs a pointer to the dynamically allocated
memory that contains the actual data
...

When compiling a program that contains arrays, you will probably not know how
many elements the array will need to store
...


ᮀ Requirements
In the following section you will be developing a new version of the FloatArr class to
meet these requirements and additionally allow you to manipulate arrays as easy as fundamental types
...


Example: v2 = v1;
The object v2 itself—and not the programmer—will ensure that enough memory is
available to accommodate the array v1
...


Example: FloatArr v3(v2);
Here the object v3 ensures that enough memory is available to accommodate the array
elements of v2
...
The statement

Example: FloatArr fArr(100);
allocates memory for a maximum of 100 array elements
...
In addition to this, two int variables are required to store
the maximum and current number of array elements
...
h : Dynamic array of floats
...

int cnt;
// Number of array elements
public:
FloatArr( int n = 256 );
// Constructor
FloatArr( int n, float val);
~FloatArr();
// Destructor
int length() const { return cnt; }
float& operator[](int i);
// Subscript operator
...

bool remove(int pos);
// Delete position pos
...
h"
#include
using namespace std;
int main()
{
FloatArr v(10);
FloatArr w(20, 1
...
0
...
append( 0
...
length() << endl;
//
cout << " Current number of elements in w: "
<< w
...
You can enhance FloatArr class step by step by optimizing existing methods or adding new methods
...


ᮀ Constructors
It should be possible to create an object of the FloatArr class with a given length and
store a float value in the object, if needed
...

FloatArr(int n = 256);

The number 256 is the default argument for the length of the array
...

An additional constructor
FloatArr( int n, int val );

allows you to define an array where the given value is stored in each array element
...


Example: FloatArr arr( 100, 0
...
0
...

arr
...

You can overload the subscript operator [] to access individual array elements
...
0F;
The index i must lie within the range 0 to cnt-1
...
The number of
elements is then incremented by one
...
This reduces the current count by one, provided a valid position was stated
...
0F );
First, memory is allocated for the data members:
Object
fArr

arrPtr

max:

10

cnt:

10

Then storage is allocated for 10 array elements and the variables max and cnt are set to
10:
Object
fArr
?

arrPtr

max:

?

?

?

?

?

?

?

?

10

cnt:

?

10

Finally, a value of 1
...
0 1
...
0 1
...
0 1
...
0 1
...
0 1
...
The object itself only occupies the memory
required for the data members arrPtr, max, and cnt
...

The additional dynamic memory allocation may need to be adjusted to meet new
requirements, for example, if an assignment is made
...


ᮀ Constructing an Object
The first constructor in the FloatArr class is defined as follows:
FloatArr::FloatArr( int n )
{
max = n;
cnt = 0;
arrPtr = new float[max];
}

This allocates memory for n array elements
...

The second constructor fills the array with the supplied value and is therefore defined
as follows:
FloatArr::FloatArr(int n, float val)
{
max = cnt = n;
arrPtr = new float[max];
for( int i=0; i < cnt; ++i)
arrPtr[i] = val;
}

The opposite page shows how memory is allocated for the object fArr and how this
object is initialized
...

Classes with dynamic members will always need a destructor to perform this task
...

FloatArr::~FloatArr()
{
delete[] arrPtr;
}

484



CHAPTER 22



DYNAMIC MEMBERS

IMPLEMENTING METHODS

New version of class FloatArr
// FloatArr
...

// ----------------------------------------------------#include "floatArr
...

// Subscript operator for objects that are not const:
float& FloatArr::operator[]( int i )
{
if( i < 0 || i >= cnt )
// Range checking
{
cerr << "\n class FloatArr: Out of range! ";
exit(1);
}
return arrPtr[i];
}
float FloatArr::operator[]( int i ) const
{
// Else as before
...


Example: FloatArr v(5, 0
...
2F;
for( int i=0; i < v
...
However, you will need to support read-only access
to constant objects
...
The first version returns a reference to the i-th array element and thus
supports write access
...

The implementation of these versions is identical
...
If the index lies within the valid boundaries, an array element—
or simply a value in the case of the read-only version—is returned
...

In the first version, the append() only works if there is at least one empty slot in the
array
...
This also
applies for a new method, insert(), which you will write as an exercise in this chapter
...
The current count
is decremented by one
...

Another technique would be to copy the last element to the position of the element
that needs to be deleted, simply overwriting that element
...


486



CHAPTER 22



DYNAMIC MEMBERS

COPY CONSTRUCTOR

Effect of the standard copy constructor
FloatArr b(a);

// Creates a copy of a
...
1 6
...
2 2
...
cpp: Implementing the methods
...
max;
cnt = src
...
arrPtr[i];
}

COPY CONSTRUCTOR



487

ᮀ Initializing with an Object
The next step is to ensure that an existing object can be used to initialize a new object
...

The FloatArr class needs a copy constructor to perform this task
...


Prototype: FloatArr( const FloatArr& );

ᮀ Standard Copy Constructor
If a class does not contain a copy constructor, the compiler will automatically create a
minimal version, known as the standard copy constructor
...

A standard copy constructor is normally sufficient for a class
...
This would merely copy the pointers, meaning that the pointers of several different objects would reference the same place in memory
...

This scenario would obviously mean trouble
...
The pointer for the second object would reference a memory area
that no longer existed!

ᮀ Proprietary Version of the Copy Constructor
Clearly you will need to write a new copy constructor for classes with dynamic members,
ensuring that the live data and not just the pointers are copied from the dynamically
allocated memory
...
Calling new[] creates a new array and the array elements of the
object passed to the method are then copied to that array
...
h : Dynamic arrays of floats
...
Data members as before
public:
//
...
cpp
// The operator function implementing "="
...
max;
cnt = src
...

arrPtr[i] = src
...
h"
int main()
{
FloatArr v;
FloatArr w(20, 1
...

// Array w - 20 float values
// with initial value 1
...

// Use copy constructor
// to create an object
...


ASSIGNMENT



489

Each class comprises four implicitly defined default methods, which you can replace with
your own definitions:



the default constructor and the destructor
the copy constructor and the standard assignment

In contrast to initialization by means of the copy constructor, which takes place when an
object is defined, an assignment always requires an existing object
...


ᮀ Default Assignment
Given that v1 and v2 are two FloatArr class objects, the following assignment is
valid:

Example:

v1 = v2;

// Possible, but ok?

Default assignment is performed member by member
...
However, this technique is not suitable for classes with dynamic members
...
In addition, memory previously addressed by a pointer of the target object
will be unreferenced after the assignment
...
Generally speaking, if you need to define a copy constructor, you will
also need to define an assignment
...


The operator function is implemented as a class method and returns a reference to the
target object allowing multiple assignments
...




CHAPTER 22



exercise s

490

DYNAMIC MEMBERS

EXERCISES

New methods of class List
// Copy constructor:
List::List(const List&);
// Assignment:
List& List::operator=( const List&);

New methods of class FloatArr
// Methods to append a float or an
// array of floats:
void append( float val);
void append( const FloatArr& v);
FloatArr& operator+=( float val);
FloatArr& operator+=( const FloatArr& v);
// Methods to insert a float or an
// array of floats:
bool insert( float val, int pos);
bool insert( const FloatArr& v, int pos );
// In any case, more memory space must be allocated
// to the array if the current capacity is
// insufficient
...

First, modify your test program to create a copy of a list
...
Note how your program reacts
...
Since the class
contains dynamic members, the following tasks must be performed:



Define a copy constructor for the List class
...


Exercise 2
Add the methods shown opposite to the FloatArr class
...
As this
could also be necessary for other methods, write a private auxiliary function for
this purpose
void expand( int newMax );

The method must copy existing data to the newly allocated memory
...

The insert() method inserts a float value or a FloatArr object at
position pos
...

Also overload the shift operator << to output an array using the field width
originally defined to output the array elements
...


Now add calls to the new methods to your test program and output the results
after each call
...
h
// Definition of classes ListEl and List
// representing a linked list
...
h"
#include
#include
using namespace std;
class ListEl
{
// Unchanged as in Chapter 21
};
// -----------------------------------------------------// Definition of class List
class List
{
private:
ListEl* first, *last;
public:
// New methods:
List(const List&);
// Copy constructor
List& operator=( const List&); // Assignment
// Otherwise unchanged from Chapter 21
};
#endif // _LIST_H_
// ---------------------------------------------------// List
...

// ---------------------------------------------------#include "List
...

first = last = NULL;
ListEl *pEl = src
...

pEl = src
...


// ------------------------------------------------------// List_t
...

// ------------------------------------------------------#include "List
...

Date date( 11,8,1999);
// Insert 3 elements
...
56);
list1
...
setDate( 1, 1, 2002);
amount = -1000
...
pushBack( date, amount);
date
...
11;
list1
...
get();
List list2( list1);
cout << "A copy of the 1st list has been created!\n"
"Contents of the copy:\n" << endl;
cout << list2 << endl;
cout << "\nRemove the first element from the list:\n";
ListEl *ptrEl = ptrEl = list1
...
popFront();
}
cout << "\nContent of the list:\n";
cout << list1 << endl;
list1 = list2;

// Reassign the copy
...
h : Dynamic arrays of floating-point numbers
...

Number of present array elements

void expand( int newMax);

// Helps enlarge the array

public:
// Constructors , destructor,
// assignment, subscript operator, and method length()
// as before in this chapter
...

// To output the array
friend ostream& operator<<( ostream& os,
const FloatArr& v);
};
#endif

// _FLOATARR_

495

496



CHAPTER 22

//
//
//
//

DYNAMIC MEMBERS

----------------------------------------------------FloatArr
...

-----------------------------------------------------

#include "floatArr
...


//

---

The new functions

---

// Private auxiliary function to enlarge the array
...

void FloatArr::append( float val)
{
if( cnt+1 > max)
expand( cnt+1);
arrPtr[cnt++] = val;
}
void FloatArr::append( const FloatArr& v)
{
if( cnt + v
...
cnt);
int count = v
...
arrPtr[i];
}

// Necessary if v == *this

SOLUTIONS

// Insert a float or an array of floats
bool FloatArr::insert( float val, int pos)
{
return insert( FloatArr(1,val), pos);
}
bool FloatArr::insert( const FloatArr& v, int pos )
{
if( pos < 0 || pos >= cnt)
return false;
// Invalid position
if( max < cnt + v
...
cnt);
int i;
for( i = cnt-1; i >= pos; --i)
arrPtr[i+v
...
cnt; ++i)
arrPtr[i+pos] = v
...
cnt;
return true;

// Shift up
// starting at pos
// Fill gap
...
width();
// Save field width
...
arrPtr; p < v
...
cnt; ++p)
{
os
...
cpp
// Tests the class FloatArr
...
h"
#include
#include
using namespace std;
int main()
{
FloatArr v(10);
FloatArr w(15, 1
...
0
...
length() << endl;
" Current total of elements in w: "
w
...
0F;
for( ; x < 6 ; x += 1
...
append(x);

// Append values
...

cout << "\nThe copy of v has been created
...
remove(3);
w
...
0F);
w
...
0F);

//
//
//
//

Erase the element at
position 3
...

And once more!

v = w;
cout << "\nAssignment done
...
insert( cv, 0);
cout << "\nThe elements after inserting "
" the copy at position 0: \n"
<< setw(5) << v << endl;
return 0;
}

chapter

23

Inheritance
This chapter describes how derived classes can be constructed from
existing classes by inheritance
...


499

500



CHAPTER 23



INHERITANCE

CONCEPT OF INHERITANCE

Is relation

Car
Properties
and capacities
of class

Car

PassCar

Truck

Properties
and capacities
of class

Properties
and capacities
of class

Car

Car

Additional
properties and
capacities of class

Additional
properties and
capacities of class
Truck

PassCar

CONCEPT OF INHERITANCE



501

ᮀ Base Classes and Derived Classes
Inheritance allows new classes to be constructed on the basis of existing classes
...
But you can add
more characteristics and functionality to the new class
...
All of these vehicles have an
identification number that indicates the vehicle, the manufacturer, and the vehicle status, such as “hired,” “repair shop,” and so on
...

To differentiate between vehicle types, various classes are derived from the base class
Car, such as PassCar, which is used to represent passenger-carrying vehicles
...


ᮀ Is Relationship
An object of the PassCar type is a special object of the Car class
...
In cases like this we can say that the derived class establishes an is
relationship to the base class
...
As
already mentioned, a has relationship occurs between two classes when an member of
one class has another class type
...


ᮀ Data Abstraction and Reusability
Inheritance has a number of important benefits for software developers:




data abstraction: General characteristics and abilities can be handled by generic
(base) classes and specializations can be organized in hierarchical relationships by
means of derived classes
...

re-usability: Classes that you have defined and tested can be reused and adapted to
perform new tasks
...


502



CHAPTER 23



INHERITANCE

DERIVED CLASSES

Defining a derived class
class C : public B
{
private:
// Declaration of additional private
// data members and member functions
public:
// Declaration of additional public
// data members and member functions
};

Direct and indirect derivation

B

C

D

Base class B

B is a direct
base class

B is an indirect
base class

DERIVED CLASSES



503

When you define a derived class, the base class, the additional data members and methods, and the access control to the base class are defined
...
The C class
inherits the B class, which is defined in the public section following the colon
...


ᮀ Access to Public Members in the Base Class
Access privileges to the base class B are designated by the public keyword that precedes the B
...


This kind of inheritance ports the public interface of the base class to the derived
class where it is extended by additional declarations
...
A public base class, therefore, implements the is relationship; this is quite common
...
Only the methods of class C can still access the
public members of B, but not the users of that class
...


ᮀ Access to Private Members of the Base Class
The private members of the base class are protected in all cases
...


Imagine the consequences if this were not so: you would be able to hack access to the
base class by simply defining a derived class, thus undermining any protection offered by
data encapsulation
...
This allows for class
hierarchies
...

In the graphic on the opposite page, the arrow ↑ means directly derived from
...


504



CHAPTER 23



INHERITANCE

MEMBERS OF DERIVED CLASSES

Base class Car and derived class PassCar
// car
...
The Car class and a derived class PassCar are defined in the example
...
The derived class
PassCar inherits these data members
...
The object includes a so-called base subobject of type Car
...
So a PassCar type
object has a total of four data members
...

The base class Car contains a constructor, access methods, and the method
display(), which is used for screen output
...

In the PassCar class a constructor, additional access methods, and a second output
function also called display() are declared
...
The display()
method is said to have been redefined
...

The member assumes a new meaning for the derived class
...

We will be looking at this point in more detail later
...
For example, you can call the
getNr() method for an object named cabrio in the PassCar class
...
getNr();
The public interface of the derived class thus comprises



the public members of the base class and
the public members additionally defined in the derived class
...

long getNr(void);

...

}

void PassCar::display( void) const
{
cout << "\nCar number: "
<< getNr();
cout << "\nProducer: "
<< getProd();
cout << "Type: "<< passCarType;
cout << "Type: "<< passCarTyp
if( sunRoof) cout << "yes";
else
cout << " no";
cout << endl;
}

ok

MEMBER ACCESS



507

ᮀ Access to Additional Members
The methods of derived classes can access any member additionally defined in the
derived class
...


ᮀ Access to Private Members of the Base Class
However, a private member of the base class is not directly accessible for the methods of
the derived class
...

Methods belonging to derived classes only have indirect access to the private data
members of the base class
...
The opposite page shows a version of the display() method
that calls the get methods in its base class Car
...

The base class is identified by the this pointer, which is passed implicitly as an argument
...


The above example thus calls the getProd() in the base class Car, as the method is
not defined in the PassCar class
...
cpp
This version of method PassCar::display() calls
the method display() of the base class
...
The name does not occur in the base class → no redefinition
...
The name already exists in the base class → redefinition
...
In other words, redefining members in a derived class has no effect on the base
class
...


This situation is similar to the one seen for local and global variables
...


ᮀ Redefinition and Overloading
Normally, methods are redefined in derived classes
...
When a method is redefined, the signature and the return type of
the method can be changed
...

Redefining a method will always mask a method with the same name in the base class
...


ᮀ Access to the Members in the Base Class
If you redefine a method in a derived class, this does not alter the fact that the base class
method still exists
...
The range :: operator is used to access the base
class method
...
The
display() method defined in the base class is used to output the data members of the
base class
...

Otherwise the display() method in the derived class will call itself and head off into
an indefinite recursion
...

passCarType = tp;
sunRoof = sr;

// Initial values for data mem// bers of the derived class

}

Second version with base class initializer
// Second version of the constructors of PassCar
// ---------------------------------------------------PassCar::PassCar(const string& tp, bool sr, int n,
const string& hs) : Car( n, hs)
{
passCarType = tp;
// Initial values for data memsunRoof = sr;
// bers of the derived class
}

Third version with base class and member initializer
// Third version of the constructor of PassCar
// ---------------------------------------------------PassCar::PassCar(const string& tp, bool sr, int n,
const string& hs)
: Car( n, hs), passCarType( tp ), sunRoof( sr )
{
// There remains nothing to do
}

CONSTRUCTING AND DESTROYING DERIVED CLASSES



511

ᮀ Constructor Calls
The constructor of a derived class is required to create an object of the derived class type
...
The base class constructor is called to perform this task
...

The order in which the constructors are called is important
...
The object is thus constructed from
its core outwards
...
An implicit call to the default constructor of the base class occurs prior to this, and the base sub-object is initialized with
default values
...
A default constructor must be available in the base class and initialization with incorrect values before assigning live values impacts the response of the
program
...
This immediately initializes the data members with correct values
...

The second version of the constructor for PassCar contains a base initializer
...
This means that you can state both the base and the
member initializer in a list separated by commas
...


ᮀ Destroying Objects
When an object is destroyed, the destructor of the derived class is first called, followed by
the destructor of the base class
...

You need to define a destructor for a derived class if actions performed by the constructor need to be reversed
...


512



CHAPTER 23



INHERITANCE

OBJECTS OF DERIVED CLASSES

Sample program
// car_t
...

// ----------------------------------------------------#include "car
...
display();
cout << "\nAnd the passenger car number again: "
<< beetle
...
setNr(1000);
cabrio
...
display();
cout << "\nOnly data of the base class: ";
cabrio
...
Two objects,
beetle and cabrio, of the derived class PassCar type are declared
...
However, it
is sufficient to state a PassCar type with or without a sunroof as default values exist for
all other data members
...

However, the following call is invalid:

Example: beetle
...


ᮀ Calling Redefined Methods
When you call a redefined method, the object type determines what version of the
method will be executed
...
The statement

Example: cabrio
...
However, in
the case of the van object in the Car class, calling

Example: van
...


ᮀ Calling Methods in the Base Class
You may be wondering if a base class method can be called for an object of a derived
class, if the method has been redefined in the derived class
...

If you want to display the basic data of the cabrio object, you can use a direct call to
the base class method display() to do so
...
Car::display();
The name of the method is preceded by the name of the base class and the scope resolution operator in this case
...
h : The classes Safe and Castle
// --------------------------------------------------#include
using namespace std;
class Safe
{
private:
int topSecret;
protected:
int secret;
void setTopSecret( int n) { topSecret = n;}
int getTopSecret() const { return topSecret;}
void setSecret( int n){ secret = n;}
int getSecret() const { return secret;}
public:
int noSecret;
Safe()
{ topSecret = 100; secret = 10; noSecret = 0; }
};
class Castle : public Safe
{
public:
Castle()
{
// topSecret = 10;
setTopSecret(10);
secret = 1;
noSecret = 0;
}
void test()
{
// top
...

When you create a class hierarchy you may want require the methods and friend
functions of a derived class to communicate directly with the members of the base class
...

For example, a class used to represent a window on screen could contain the dimensions and other characteristics of a general windows
...


ᮀ Protected Members
To allow methods and friend functions access to the sheltered members of a base class,
let’s introduce an additional level of access control between private and public
...

A member declared protected is sheltered from external access just like a private member
...
However, in contrast to a private member,
methods and friend functions of derived classes can access the member
...
In contrast to this, protected
members are inaccessible to users of these classes
...
topSecret = 1;
treasure
...
setTopSecret(5);
treasure
...
If you change the declaration of a
protected member, every class derived from this class must be examined to ascertain

whether additional modifications are necessary
...
In addition, the class Truck is to be added to the class hierarchy
...
"



Define a destructor for the Car and PassCar classes
...
"









Then define the class Truck, which is derived from Car, using the data
members shown opposite, a constructor, a destructor, and the additional
methods shown opposite
...
Use the base initializer to initialize the data
members of Car
...

To test your class, create and display a Truck type object in your main
function
...


Observe how the various objects and member objects are created and
destroyed
...

Additionally define an overdraft limit and an interest rate for the DepAcc class
...





For both classes, define constructors to provide default values for all
parameters, add access methods, and add a display() method for
screen output
...
Then modify both a
savings and a deposit account interactively and display the new values
...

scanner()
printer()

PrepackedFood
Properties:
Price per piece

FreshFood
Properties:
Weight
Price per pound

Methods:

getPrice()
setPrice()

...

scanner()
printer()

EXERCISES



519

Exercise 3
A supermarket chain has asked you to develop an automatic checkout system
...

Groceries are either sold in packages or by weight
...
The price of groceries sold by weight is calculated by multiplying the
weight by the current price per kilo
...
The Product class, which contains generic information on all
products (barcode, name, etc
...







The Product class contains two data members of type long used for
storing barcodes and the product name
...
Add default values for the parameters to provide a default constructor for the class
...
For test purposes, these methods will simply
output product data on screen or read the data of a product from the
keyboard
...

Define two classes derived from Product, PrepackedFood and FreshFood
...

In both classes define a constructor with parameters providing
default-values for all data members
...

Define the access methods needed for the new data members
...

Test the various classes in a main function that creates two objects each
of the types Product, PrepackedFood and FreshFood
...
Use the default constructor to create the other object
...




CHAPTER 23



solutions

520

INHERITANCE

SOLUTIONS

Exercise 1
// ---------------------------------------------------// Car
...
cpp
// Implements the methods of Car, PassCar, and Truck
// -----------------------------------------------------#include "car
...
" << endl;
nr = n;
producer = prod;
}
Car::~Car()
{
cout << "Destroying an object of type Car" << endl;
}
void Car::display() const
{
cout << "\n---------------------------- "
<< "\nCar number:
" << nr
<< "\nProducer:
" << producer
<< endl;
}
// ------------------------------------------------------// The methods of the derived class PassCar:
PassCar::PassCar(const string& tp, bool sd, int n,
const string& hs)
: Car( n, hs), PassCarTyp( tp ), sunRoof( sd )
{
cout << "I create an object of type PassCar
...
" << endl;
}
Truck::~Truck()
{
cout << "\nDestroying an object of type Truck\n";
}
void Truck::display() const
{
Car::display();
cout <<
"Axles:
" << axles
<< "\nCapacity:
" << tons << " long tons\n";
}
// ----------------------------------------------------// Car_t
...

// ----------------------------------------------------#include "car
...
5, 1111, "Volvo");
toy
...
display();
}
cout << "\nDo you want to create an object "
<< " of type car? (y/n) ";
cin >> c;
if( c == 'y' || c == 'Y')
{
const Car oldy(3421, "Rolls Royce");
oldy
...
h:
// Defines the classes Account, DepAcc, and SavAcc
...
0)
: name(s), nr(n), balance(st)
{ }
const string& getName() const { return name; }
void setName(const string& n) { name = n;}
unsigned long getNr() const { return nr; }
void setNr(unsigned long n) { nr = n; }
double getBalance() const
{ return balance; }
void
setBalance(double st){ balance = st; }
void display()
{ cout << fixed << setprecision(2)
<< "----------------------------------------\n"
<< "Account holder:
" << name << endl
<< "Account number:
" << nr
<< endl
<< "Balance of the account:" << balance <}
};
class DepAcc : public Account
{
private:
double limit;
// Overdraft limit
double interest;
// Interest
public:
DepAcc(const string& s = "X",
unsigned long n = 1111111L, double st = 0
...
0, double ra = 0
...
0,
double in = 0
...

double getInterest() const
{ return interest; }
void
setInterest(double in){ interest = in; }
void display()
{
Account::display();
cout << fixed << setprecision(2)
<< "Interest rate:
" << interest << endl
<< "----------------------------------\n"
<< endl << endl;
}
};
#endif

SOLUTIONS



// ------------------------------------------------------// account_t
...
h"
int main()
{
string s;
double db;
SavAcc mickey("Mickey Mouse", 1234567,
2
...
5);
mickey
...
setName(s);
mickey
...
display();
DepAcc dag("Donald Duck", 7654321,
-1245
...
9);
dag
...
setLimit(db);
dag
...
h : Defines the classes
//
Product, PrepackedFood, and FreshFood
// ---------------------------------------------------#ifndef _PRODUCT_H
#define _PRODUCT_H
#include
#include
#include
using namespace std;
class Product
{
private:
long
bar;
string name;
public:
Product(long b = 0L, const string& s = "")
: bar(b), name(s)
{ }
void setCode(long b) { bar = b; }
long getCode() const { return bar; }
void setName(const string& s){ name = s; }
const string& getName() const { return name; }
void scanner()
{
cout << "\nBarcode:
"; cin >> bar;
cout <<
"Name:
"; cin >> name;
cin
...
clear();
}
void printer() const
{
cout << "\n-------------------------------"
<< "\nBarcode:
" << bar
<< "\nName:
" << name
<< endl;
}
};
class PrepackedFood : public Product
{
private:
double pce_price;

SOLUTIONS



public:
PrepackedFood(double p = 0
...
0, double p = 0
...
sync(); cin
...
cpp
Tests classes Product, PrepackedFood, and FreshFood
...
h"
int main()
{
Product p1(12345L, "Flour"), p2;
p1
...
setName("Sugar");
p2
...
printer();

// Output the second product

// Prepacked products:
PrepackedFood pf1(0
...
printer();

//
//
cout << "\n Input data of a
pf2
...
printer();
//

Output the first
prepacked product
prepacked product: ";
Input and output
data of 2nd product

FreshFood pu1(1
...
69, 98765, "Grapes"), pu2;
pu1
...
scanner();
//
pu2
...


"\n-------------------------------"
"\n-------------------------------"
"\nAgain in detail: \n"
fixed << setprecision(2)
"\nBarcode:
" << pu2
...
getName()
"\nPrice per Lbs: " << pu2
...
getWght()
"\nEnd price:
" << pu2
...
getWght()
<< endl;

return 0;
}

chapter

24

Type Conversion in Class
Hierarchies
This chapter describes implicit type conversion within class hierarchies,
which occurs in the context of assignments and function calls
...


529

530



CHAPTER 24



TYPE CONVERSION IN CLASS HIERARCHIES

CONVERTING TO BASE CLASSES

Example for implicit conversion

#include "car
...

}
//
//
//
//
//

ok!
Implicit conversion
to base class
...

If this is inconvenient, an explicit
type cast to type PassCar has to be performed
...
Objects of the derived class type then
become special objects of the base class, just like an automobile is a special type of vehicle
...
It is possible to assign an
object of a derived class to an object of the base class
...

The base class thus becomes a generic term for multiple special cases
...


ᮀ Assignments
Implicit type conversion in class hierarchies occurs in assignments to



base class objects
pointers or references to the base class
...

Given the function compare() with the following prototype

Example: bool compare( Car& , Car& );
and two objects of the derived PassCar class type, beetle and miata, the following
statement is valid

Example: compare( beetle, miata);
The compiler performs implicit type conversion for the arguments beetle and miata,
converting them to the parameter type, that is, to a reference to the base class Car
...


532



CHAPTER 24



TYPE CONVERSION IN CLASS HIERARCHIES

TYPE CONVERSIONS IN ASSIGNMENTS

ᮀ Effect of an assignment
Car
auto;
PassCar bmw("520i", true, 4325,
"Bayerische Motorenwerke");
auto = bmw;

auto

bmw

nr: 4325

nr: 4325

producer:
"Bayer
...
"

passCarType:
"520i"
sunRoof: true

TYPE CONVERSIONS IN ASSIGNMENTS



533

ᮀ Assignment to a Base Class Object
An object belonging to a derived class type can be assigned to an object of a base class
...
e
...
During
an assignment the object bmw is copied to the data members of the object auto step by
step
...
nr
= bmw
...
producer = bmw
...
display();
The fact that you can assign an object belonging to a derived class to a base class object
assumes that more will always fill less
...


ᮀ Assignments to Derived Class Objects
This is not the case when you attempt to assign a base class object to an object of a
derived class
...

An assignment in reverse order is only possible if you have defined an assignment of
this type or a copy constructor with a parameter of the type “reference to base class
...


534



CHAPTER 24



TYPE CONVERSION IN CLASS HIERARCHIES

CONVERTING REFERENCES AND POINTERS

ᮀ Effect of a pointer assignment
PassCar cabrio("Spitfire", true, 1001, "Triumph");
Car* carPtr = &cabrio;
carPtr = &cabrio;

carPtr

cabrio
nr

1001

producer

"Triumph"

carType

"Spitfire"

sunRoof

true

CONVERTING REFERENCES AND POINTERS



535

ᮀ Converting to Base Class Pointers
The is relationship between a derived class and a base class is also apparent when references and pointers are used
...


Example: Car* carPtr = &cabrio;
In this case cabrio is an object of the class PassCar
...


The additional members defined in the derived class are therefore inaccessible
...
Although carPtr points to an
object of the PassCar class in this case, it is impossible to call any methods additionally
defined in the derived class
...
Thus, the following assignment is also invalid

Example: PassCar auto;
auto = *carPtr;

// Error!

although carPtr is pointing at an object of the PassCar type in this case!

ᮀ Conversions in References to Base Classes
A similar situation arises when you are working with references
...
The reference will
address only the generic part of the object in this case
...
display();
carRef
...


536



CHAPTER 24



TYPE CONVERSION IN CLASS HIERARCHIES

EXPLICIT TYPE CONVERSIONS

Downcast

Pointer to

carPtr
Base class

Car

Downcast

static_cast(carPtr)
Derived
class

PassCar

Upcast

Pointer to

static_cast(PassCarPtr)
Base class

Car

Upcast

PassCarPtr
Derived
class

PassCar

EXPLICIT TYPE CONVERSIONS



537

ᮀ Upcasts and Downcasts
Type conversions that walk up a class hierarchy, or upcasts, are always possible and safe
...

Type conversions that involve walking down the tree, or downcasts, can only be performed explicitly by means of a cast construction
...


ᮀ Explicit Cast Constructions
Given that cabrio is again an object of the derived class PassCar, the following statements

Example: Car* carPtr = &cabrio;
( (PassCar*) carPtr )->display();

first point the base class pointer carPtr to the cabrio object
...
This allows you to access the display() method of the
derived class PassCar via the pointer
...

The operator static_cast< > conforms to the following

Syntax:

static_cast(expression)

and converts the expression to the target type type
...
They are read from left to right
...


ᮀ Downcast Safety Issues
Type conversions from top to bottom need to be performed with great care
...
This also applies to references to base classes
...
This technique is available for polymorphic classes and will be introduced in the next chapter
...
Your job is to test various cast techniques for this class (see also
Exercise 3 in Chapter 23)
...

Define an array with three pointers to the base class Product
...
The three objects are to be referenced by the array pointers
...
Initialize the
pointer with the address of a dynamically allocated object of the same
class
...
Which version of
printer() is executed?
Perform downcasting to execute the correct version of printer() in
every case
...

Use the pointer of the derived class FreshFood to call the base class version of printer()
...

Test the function isLowerCode()by multiple calls to the function with
various arguments
...




CHAPTER 24

TYPE CONVERSION IN CLASS HIERARCHIES



solution

540

SOLUTION

//
//
//
//
//
//

---------------------------------------------------product
...
cpp
Tests up and down casts for the classes
Product, PrepackedFood, and FreshFood
...


#include "product
...
49, 23456, "Salt");
pv[2] = new FreshFood(1
...
69, 98765, "Grapes");
pu =

new FreshFood(2
...
69, 56789, "Peaches");

cout << "\nA fresh product: ";
pu->printer();
cout << "\nThe generic data of the other products:";
int i;
for(i=0; i < 3; ++i)
pv[i]->printer();
cin
...
get();
cout << "\nAnd an upcast: " << endl;
static_cast(pu)->printer();

SOLUTION

cout << "\nNow compare the barcodes!" << endl;
cout << "\nIs barcode for flour or salt smaller?";
isLowerCode(*pv[0], *pv[1])
...
printer();
return 0;
}
const Product& isLowerCode(const Product& p1,
const Product& p2)
{
if(p1
...
getCode())
return p1;
else
return p2;
}



541

This page intentionally left blank

chapter

25

Polymorphism
This chapter describes how to develop and manage polymorphic classes
...


543

544



CHAPTER 25



POLYMORPHISM

CONCEPT OF POLYMORPHISM

Example

Classes with virtual methods:

Base:
base class with virtual method display()
...


Base class pointer and objects:

Base*

basePtr;

Derived1 angular;

// Base class pointer
// Objects

Derived2 round;
Calling virtual methods:
When a virtual method is called, the corresponding version of the method is
executed for the object currently referenced
...
This is the case when dynamic allocated objects are
inserted into a data structure or deleted from that structure
...
However, you can only access the
common base members of these objects
...


Given a base class pointer, carPtr, the statement

Example: carPtr->display();
should output all the data members of the object currently being referenced
...
The type field stored the type of the current class
...

This solution has a disadvantage; adding derived classes at a later stage also meant
adding a case label and recompiling
...
In C++, virtual methods are used to implement polymorphic classes
...
cpp : Tests the virtual method display()
//
of the classes Car and PassCar
...
h"
// The Car class with virtual method display():
// class Car
// {
//

...

int i = 0;
// Index
pCar[0] = new Car( 5634L, "Mercedes");
pCar[1] = new PassCar("Miata",true,3421,"Mazda");
pCar[2] = new Truck( 5, 7
...


Example: virtual void display() const;
The definition of a virtual method is no different from the definition of any other member function
...
The derived class
then inherits the virtual method from the base class
...

Creating a proprietary version of a virtual method means redefining that method
...
the same signature and
2
...

The new version of a virtual method is automatically virtual itself
...

When you redefine a virtual function, be aware of the following:





if the return type is a pointer or reference to the base class, the new version of the
virtual method can also return a pointer or reference to a derived class (Note:
Not all compilers support this option
...


If you use a different signature or return type of a virtual base class method to define a
method in a derived class, this simply creates a new method with the same name
...
In other words, only the non-virtual version of the method is available for
a derived class object
...
cpp
// Base class with a virtual destructor
...
When such an object reaches the end of its lifetime, the memory occupied by
the object must be released by a delete statement
...

delete carPtr;

ᮀ Destructor Calls
When memory is released, the destructor for an object is automatically called
...
What does this mean for objects in derived classes? The destructor of the
derived class is called first and then the destructor of the base class executed
...
However, non-virtual methods will always execute the base
class version
...
As the
PassCar destructor is not called, neither is the destructor called for the data member
passCarType, which is additionally defined in the derived class
...

If multiple objects are created dynamically in the derived class, a dangerous situation
occurs
...


ᮀ Virtual Destructors
This issue can be solved simply by declaring virtual destructors
...
Just like any other virtual
method, the appropriate version of the destructor will be executed
...

A class used as a base class for other classes should always have a virtual destructor
defined
...


550



CHAPTER 25



POLYMORPHISM

VIRTUAL METHOD TABLE

VMT for the classes Car and PassCar

Object of type Car
VMT of Car

VMT pointer

nr

12345

producer Audi

Address of Car::display()
Address of Car::~Car()

Object of type PassCar
VMT pointer

nr

54321

producer Geo
passCarType 500
sunRoof

true

VMT of PassCar
Address of

PassCar::display()
Address of

PassCar::~PassCar()
Object of type PassCar
VMT pointer

nr

98765

producer VW
passCarType GTI
sunRoof

false

VIRTUAL METHOD TABLE



551

ᮀ Static Binding
When a non-virtual method is called, the address of the function is known at time of
compilation
...
This is also referred
to as static or early binding
...
So this is also a case of early binding
...
The statement

Example: carPtr->display();
could execute different versions of the display() method, depending on the object
currently referenced by the pointer
...
This is referred to as late
or dynamic binding
...
A
VMT is created for each class with at least one virtual method—that is, an array with the
addresses of the virtual methods in the current class
...
Dynamic binding causes the virtual function call
to be executed in two steps:
1
...

2
...

In comparison with static binding, dynamic binding does have the disadvantage that
VMTs occupy memory
...

However, this is a small price to pay for the benefits
...
This is particularly important when you consider commercial class libraries, from which a user can
derive his or her own classes and virtual function versions
...
cpp
// Dynamic casts in class hierarchies
...
h"
bool inspect( PassCar* ),
// Inspection of
inspect(Truck* );
// car types
...

int main()
{
Car* carPtr = new PassCar("520i", true, 3265, "BMW");
Truck* truckPtr = new Truck(8, 7
...
to test some casts and
...
The GNU compiler activates these options automatically
...
If
the referenced object does not correspond to the type of the derived class, fatal runtime
errors can occur
...


But

the

following

statement,

truckPtr->setAxles(10); could cause the program to crash
...
At runtime the operator checks whether the required conversion is
valid or not
...
The target type
must be a pointer or reference to a polymorphic class or a void pointer
...
If the target type is a reference,
expression must identify an object in memory
...
If this is not so, the dynamic_cast operator
will return a NULL pointer
...
In any other case, that is, if
the reference r_car does not identify a PassCar type object, an exception of the
bad_cast type is thrown
...
The classes involved do not need to
be polymorphic in this case
...
An
erroneous upcast is recognized and reported by the compiler
...
First, define a class called CityCar that
contains an array of pointers to the 100 objects in the Car class
...

The objects themselves will be created dynamically at runtime
...

The constructor will set the current number of array elements to 0
...
Make sure that you use a virtual destructor definition
in the base class Car to allow correct releasing of memory for trucks and
passenger vehicles
...
Each version will allocate memory to an object of the
appropriate type—that is of the PassCar or Truck class—and use the
arguments passed to it for initialization
...

The display() method outputs the data of all vehicles on screen
...

Create a new function called menu() and store this function in a new
source file
...

Additionally, write two functions, getPassCar() and getTruck(), which
read the data for a car or a truck from the keyboard and write the data
into the appropriate arguments
...
Insert one
car and one truck
...

If a user chooses “Add car” or “Add truck,” your program must read the
data supplied and call the appropriate version of insert()
...







Declare the virtual methods scanner() and printer() in the base class
Product
...

Write the record() function, which registers and lists products purchased in the store in a program loop
...

The checkout assistant is prompted to state whether a prepacked or
fresh food item is to be scanned next
...

After scanning all the available items, a sequential list is displayed
...

Now create an application program to simulate a supermarket checkout
...
If so, the record() function is called; if not, the program
terminates
...
h : Defines the base class Car and
//
the derived classes PassCar and Truck
// -------------------------------------------------------#ifndef _CAR_H_
#define _CAR_H_
#include
#include
using namespace std;
class Car
{
private:
long
nr;
string producer;
public:
Car( long n = 0L, const string& prod = "");
virtual ~Car() {}
// Virtual destructor
...

#endif
//
//
//
//

-----------------------------------------------------car
...

//

SOLUTIONS

// -----------------------------------------------------// city
...
h"
class CityCar
{
private:
Car* vp[100];
int cnt;
public:
CityCar(){ cnt = 0;}
~CityCar();
bool insert(const string&
long n, const
bool insert(int a, double
long n, const

tp, bool sr,
string& prod);
t,
string& prod);

void display() const;
};
#endif // _CITY_H
// -----------------------------------------------------// city
...
h"
CityCar::~CityCar()
{
for(int i=0; i < cnt; ++i)
delete vp[i];
}
// Insert a passenger car:
bool CityCar::insert(const string& tp, bool sr,
long n, const string& prod)
{
if( cnt < 100)
{
vp[cnt++] = new PassCar( tp, sr, n, prod);
return true;
}
else
return false;
}



559

560



CHAPTER 25

POLYMORPHISM

// Insert a truck:
bool CityCar::insert( int a, double t,
long n, const string& prod)
{
if( cnt < 100)
{
vp[cnt++] = new Truck( a, t, n, prod);
return true;
}
else
return false;
}
void CityCar::display() const
{
cin
...
clear();
// No previous input
for(int i=0; i < cnt; ++i)
{
vp[i]->display();
if((i+1)%4 == 0) cin
...
cpp : Test the CityCar class
// -------------------------------------------------#include "city
...
insert(6, 9
...
insert("A-class", true, 54320, "Mercedes");
char choice;
do
{
choice = menu();
switch( choice )
{
case 'Q':
case 'q': cout << "Bye Bye!" << endl;
break;

SOLUTIONS

case 'P':
case 'p': getPassCar(tp, sr, n, prod);
carExpress
...
insert(a, t, n, prod);
break;
case 'D':
case 'd': carExpress
...
get();
break;
default: cout << "\a";
// Beep
break;
}
}while( choice != 'Q'
return 0;



);

&& choice != 'q');

}
char menu()
// Input a command
...
sync(); cin
...
sync();
cout << "Producer:
"; getline(cin, prod);
cin
...
clear();
}

561

562



CHAPTER 25

POLYMORPHISM

void getTruck(int& a, double& t, long& n, string& prod)
{
cout << "\nInput data for truck:" << endl;
cout << "Number of axles:
"; cin >> a;
cout << "Weight in tons:
"; cin >> t;
cout << "Car number:
";
cin >> n;
cin
...
sync();
}

Exercise 2
//
//
//
//
//

---------------------------------------------------product
...


class Product
{
private:
long
bar;
string name;
public:
Product(long b = 0L, const string& s = "")
: bar(b), name(s)
{ }
//

Access methods as previously used
...


SOLUTIONS

// -----------------------------------------------------// counter
...
h"
void record();
int main()
{
cout << "\nHere is a checkout desk!" << endl;
char c;
while(true)
{
cin
...

void record()
{
Product* v[100];
int x, i, cnt = 0;
double sum = 0
...
sync();
cout << "\nWhat is the next article?" << endl;
cout << " 0 = No more article\n"
<< " 1 = Fresh Food\n"
<< " 2 = Prepacked article\n"
<< "? " ;
cin >> x;
if( x <= 0 || x >= 3)
break;



563

564



CHAPTER 25

POLYMORPHISM

switch(x)
{
case 2:
v[i] = new PrepackedFood;
v[i]->scanner();
sum += ((PrepackedFood*)v[i])->getPrice();
break;
case 1:
v[i] = new FreshFood;
v[i]->scanner();
sum += ((FreshFood*)v[i])->getPrice()
* ((FreshFood*)v[i])->getWght();
break;
}
}
cnt = i;
for( i=0; i < cnt; i++)
v[i]->printer();

// Output

cout << "\n-----------------------------"
<< fixed << setprecision(2)
<< "\nTotal price:
" << sum << endl;
}

chapter

26

Abstract Classes
This chapter describes how abstract classes can be created by defining
pure virtual methods and how you can use abstract classes as a
polymorphic interface for derived classes
...


565

566



CHAPTER 26



ABSTRACT CLASSES

PURE VIRTUAL METHODS

The base class Coworker
// Coworker
...

// ---------------------------------------------------#ifndef _COWORKER_H
#define _COWORKER_H
#include
#include
using namespace std;
class Coworker
{
private:
string name;
// more information
public:
Coworker( const string& s = ""){ name = s; }
virtual ~Coworker() {}
// Destructor
const string& getName() const{ return name; }
void setName( const string& n){ name = n; }
virtual void display() const;
virtual double income() const = 0;
virtual Coworker& operator=(const Coworker&);
};
#endif



NOTE
The virtual operator function for the assignment will be described in the section on ”Virtual
Assignments
...
It may happen that they rarely perform
any useful tasks in the base class
...

In this case, of course, you can define a virtual dummy method whose address is
entered in the VMT of the base class
...
It makes more sense not to define a function like this
...


ᮀ Declaration
When a pure virtual method is declared, the method is identified by adding the expression = 0
...

A NULL pointer is then entered in the virtual method table for the pure virtual method
...
The class is used as a base class for various
employees, blue-collar, white-collar, and freelancers
...
However, it could also contain the address of an employee, or the division where the
employee works
...
It makes more sense to store data like this in derived classes where the hourly
wage and number of hours worked by a blue-collar worker and the monthly salary for a
white-collar worker are also defined
...


568



CHAPTER 26



ABSTRACT CLASSES

ABSTRACT AND CONCRETE CLASSES

The derived class Laborer
// coworker
...

// -------------------------------------------------class Laborer : public Coworker
{
private:
double wages;
// Pay per hour
int
hr;
public:
Laborer(const string& s="", double w=0
...


ABSTRACT AND CONCRETE CLASSES



569

ᮀ Concrete or Abstract?
If a class comprises pure virtual methods, you cannot create objects of this class type
...
This avoids calling a method for worker that still
needs to be defined
...




NOTE
A class with pure virtual methods is an abstract class
...


ᮀ Deriving Abstract Classes
When a class is derived from an abstract class, it inherits all the methods the base class
contains, particularly the pure virtual methods
...




NOTE
A class derived from a class containing pure virtual methods is a concrete class, if it contains a definition
for each pure virtual function
...
Since the hourly wage and the number of hours worked are both defined
for blue-collar workers, it is possible to implement that method
...
In other words, an abstract class can be
derived from a concrete class
...
If the
class contains a protected constructor, objects of the class type cannot be created
...
A constructor of
this type normally acts as base initializer, when an object of a derived class type is created
...
h:
Extending the headerfile
...
0)
: Coworker(s), salary(g){ }
double getSalary() const { return salary; }
void
setSalary( double sa){ salary = sa; }
void
display() const;
double income()const { return salary; }
Employee& operator=( const Coworker& );
Employee& operator=( const Employee& );
};

Sample program
// coworker_t
...

// ------------------------------------------------#include "coworker
...
, 40);
felPtr[1] = new Employee("Smith, Eve", 3850
...


Example: Coworker *felPtr, &coRef;
The pointer felPtr is a base class pointer that can address objects belonging to derived
concrete classes
...


ᮀ References to Abstract Base Classes
References to base classes are often used as parameters in functions
...


Example: Coworker( const Coworker& );
The copy constructor expects an object belonging to a derived class, since the base class
is abstract
...


ᮀ Pointers to Abstract Base Classes
Pointers to base classes are generally used to address dynamically allocated objects
...


Example: Coworker* felPtr;
felPtr = new Laborer("Young, Neil",45
...


ᮀ Polymorphic Interface
Defining pure virtual methods also determines interfaces for general operations, although
the interfaces still need to implemented in the derived classes
...
Abstract classes are therefore also referred
to as polymorphic interfaces to derived classes
...
The operator functions for the assignments
are discussed and implemented in the following section
...
name;
return *this;
}

Assignments for class Employee
// Redefinition: virtual
Employee& operator=(const Coworker& m)
{
if( this != &m )
// No self assignment
{
Coworker::operator=( m );
salary = 0
...
salary;
}
return *this;
}



NOTE
Redefining the virtual operator function operator=(), which returns a reference to the derived class,
is not yet supported by all compilers
...


VIRTUAL ASSIGNMENT



573

ᮀ Virtual Operator Functions
Operator functions implemented as methods can also be virtual
...

One example of this is the operator function for an assignment
...
Any additional data members of the derived class
remain unchanged
...
The derived classes
Laborer and Employee both contain their own versions
...
If the object is a Laborer type, the assignment of the
Laborer class is performed
...


ᮀ Redefining the Standard Assignment
When you define a new version for a virtual method in a derived class, this implies using
the signature of the original method
...
The standard assignment for the Laborer class
has the following prototype:

Example: Laborer& operator=(const Laborer&);
The type const Laborer& is different from the const Coworker& type of the
parameter in the virtual operator function of the base class
...
This gives rise to two issues:



the virtual operator function for the assignment must be defined for every derived
class
to ensure that the standard assignment is also available, the standard assignment
must also be redefined in every derived class
...
h: Defining the classes Cell, BaseEl, and DerivedEl
// -------------------------------------------------------#ifndef _CELL_
#define _CELL_
#include
#include
using namespace std;
class Cell
{
private:
Cell* next;
protected:
Cell(Cell* suc = NULL ){ next = suc; }
public:
virtual ~Cell(){ }
// Access methods to be declared here
...

void display() const;
};
class DerivedEl : public BaseEl
{
private:
string rem;
public:
DerivedEl(Cell* suc = NULL,const string& s="",
const string& b="")
: BaseEl(suc, s), rem(b) { }
// Access methods would be declared here
...
An inhomogeneous list is a linear list whose elements can be of different types
...

Due to implicit type conversions in class hierarchies, you can use the base class pointers to manage the list elements, that is, you can manage the elements in a linked list
...
The
class contains a pointer of type Cell* as the data member used to link list elements
...

The Cell class does not contain any data that might need to be output
...
For this reason,
Cell contains a declaration of the pure virtual method display(), which can be modified for multiple derivations
...
To keep things simple, the BaseEl class contains
only a name, and the DerivedEl class additionally contains a comment
...
In addition, a
suitable version of the display() method is defined
...


576



CHAPTER 26



ABSTRACT CLASSES

IMPLEMENTING AN INHOMOGENEOUS LIST

Defining class InhomList
// List
...
h"
class InhomList
{ private:
Cell* first;
protected:
Cell* getPrev(const string& s);
void insertAfter(const string& s,Cell* prev);
void insertAfter(const string& s,
const string& b,Cell* prev);
public: // Constructor, Destructor etc
...

{
Cell* p = new BaseEl(prev->getNext(), s);
prev->setNext(p);
}
}

IMPLEMENTING AN INHOMOGENEOUS LIST



577

ᮀ The InhomList Class
The inhomogeneous list must allow sorted insertion of list elements
...
A pointer to the first element in the list is all you need for this task
...

The definition of the InhomList class is shown opposite
...
The constructor has very little to do
...

The list will be sorted by name
...
In our example, we first locate the immediate lexicographical predecessor
...
In this case, the new
list element is inserted as the first element in the list
...
There are two
cases that need to be looked at:
1
...
The new element becomes the first
element
...

2
...
Instead, you have to modify two pointers
...
This situation also applies in cases where the successor was a NULL
pointer, in other words, when the new element is appended to the list
...
They differ only in
different calls to the new operator
...
Both versions first call
the getPrev() method and the corresponding version of the insertAfter()
method
...



















Write the destructor for the InhomList class
...

Implement the getPrev() method and both versions of the insert()
and insertAfter() methods
...

Implement the displayAll() method, which walks through the list
sequentially, outputting each element
...
Check whether the comments
on the objects are output, if present
...
If the element is in the list, its address is returned
...

Write the erasePos() method, which deletes a list element at a given
position
...
Since the destructor for Cell was
declared virtual, only one version of the deletePos() method is necessary
...

Test deletion of list elements
...

Now implement the copy constructor and assignment
...
You can
call the typeid() operator to ascertain the type of the list element
currently to be inserted
...

Example: if( typeid(*ptr) == typeid(DerivedEl))
...

Then test the copy constructor and the assignment



CHAPTER 26



solution

580

ABSTRACT CLASSES

SOLUTION

// -----------------------------------------------------// cell
...

// -----------------------------------------------------#ifndef _CELL_
#define _CELL_
#include
#include
using namespace std;
class Cell
{
private:
Cell* next;
protected:
Cell(Cell* suc = NULL ){ next = suc; }
public:
virtual ~Cell(){ }
Cell* getNext() const { return next; }
void setNext(Cell* suc) { next = suc; }
virtual void display() const = 0;
};
class BaseEl : public Cell
{
private:
string name;
public:
BaseEl( Cell* suc = NULL, const string& s = "")
: Cell(suc), name(s){}
// Access methods:
void
setName(const string& s){ name = s; }
const string& getName() const { return name; }
void display() const
{
cout << "\n--------------------------------"
<< "\nName:
" << name << endl;
}
};

SOLUTION

class DerivedEl : public BaseEl
{
private:
string rem;
public:
DerivedEl(Cell* suc = NULL,
const string& s="", const string& b="")
: BaseEl(suc, s), rem(b){ }
// Access methods:
void
setRem(const string& b){ rem = b; }
const string& getRem() const { return rem; }
void display() const
{
BaseEl::display();
cout << "Remark:
" << rem << endl;
}
};
#endif
// -----------------------------------------------------// List
...
h"
class InhomList
{
private:
Cell* first;
protected:
Cell* getPrev(const string& s);
Cell* getPos( const string& s);
void insertAfter(const string& s, Cell* prev);
void insertAfter(const string& s,const string& b,
Cell* prev);
void erasePos(Cell* pos);
public:
InhomList(){ first = NULL; }
InhomList(const InhomList& src);
~InhomList();
InhomList& operator=( const InhomList& src);
void insert(const string& n);
void insert(const string& n, const string& b);
void erase(const string& s);
void displayAll() const;
};
#endif



581

582



CHAPTER 26

ABSTRACT CLASSES

// -----------------------------------------------------// List
...
h"
#include
// Copy constructor:
InhomList::InhomList(const InhomList& src)
{
// Append the elements from src to the empty list
...
first;
for( ; pEl != NULL; pEl = pEl->getNext() )
if(typeid(*pEl) == typeid(DerivedEl))
insert(dynamic_cast(pEl)->getName(),
dynamic_cast(pEl)->getRem());
else
insert(dynamic_cast(pEl)->getName());
}
// Assignment:
InhomList& InhomList::operator=(const InhomList& src)
{
// To free storage for all elements:
Cell *pEl = first,
*next = NULL;
while( pEl != NULL )
{
next = pEl->getNext();
delete pEl;
pEl = next;
}
first = NULL;

// Empty list

// Copy the elements from src to the empty list
...
first;
for( ; pEl != NULL; pEl = pEl->getNext() )
if(typeid(*pEl) == typeid(DerivedEl))
insert(dynamic_cast(pEl)->getName(),
dynamic_cast(pEl)->getRem());
else
insert(dynamic_cast(pEl)->getName());
return *this;
}

SOLUTION

// Destructor:
InhomList::~InhomList()
{
Cell *pEl = first,
*next = NULL;
while( pEl != NULL )
{
next = pEl->getNext();
delete pEl;
pEl = next;
}
}
Cell* InhomList::getPrev(const string& n)
{
Cell *pEl = first,
*prev = NULL;
while( pEl != NULL )
{
if( n > dynamic_cast(pEl)->getName() )
{
prev = pEl;
pEl = pEl->getNext();
}
else
return prev;
}
return prev;
}
Cell* InhomList::getPos( const string& n)
{
Cell *pEl = first;
while( pEl != NULL &&
(n != dynamic_cast(pEl)->getName()))
pEl = pEl->getNext();
if( pEl != NULL &&
n == dynamic_cast(pEl)->getName())
return pEl;
else
return NULL;
}
void InhomList::insertAfter(const string& s, Cell* prev)
{
if( prev == NULL )
// Insert at the beginning:
first = new BaseEl( first, s);
else
// In the middle or at the end:
{ Cell* p = new BaseEl(prev->getNext(), s);
prev->setNext(p);
}
}



583

584



CHAPTER 26

ABSTRACT CLASSES

void InhomList::insertAfter( const string& s,
const string& b, Cell* prev)
{
if( prev == NULL )
// Insert at the beginning:
first = new DerivedEl( first, s, b);
else
// In the middle or at the end:
{
Cell* p = new DerivedEl(prev->getNext(), s, b);
prev->setNext(p);
}
}
void InhomList::insert(const string& n)
{
Cell* pEl = getPrev(n);
insertAfter(n, pEl);
}
void InhomList::insert(const string& n, const string& b)
{
Cell* pEl = getPrev(n);
insertAfter(n, b, pEl);
}
void InhomList::erasePos(Cell* pos)
{
Cell* temp;
if( pos != NULL)
if( pos == first )
// Delete the first element
{
temp = first;
first = first->getNext();
delete temp;
}
else
// Delete from the middle or at the end
{
// Get the predecessor
temp = getPrev( dynamic_cast(pos)
->getName());
if(temp != NULL)
// and bend pointer
...
cpp : Tests the sorted inhomogeneous list
// -----------------------------------------------------#include "List
...
" << endl;
liste1
...
insert("Cheers, Rita", "always merry");
liste1
...
insert("Banderas, Antonio");
liste1
...
get();
cout << "\nTo test deleting
...
erase("Banderas, Antonio");
liste1
...
erase("Cheers, Rita");
liste1
...
get();
cout << "\n----------------------------------"
<< "\nGenerate a copy and insert an element
...


liste2
...
displayAll();
return 0;
}



585

This page intentionally left blank

chapter

27

Multiple Inheritance
This chapter describes how new classes are created by multiple
inheritance and explains their uses
...


587

588



CHAPTER 27



MULTIPLE INHERITANCE

MULTIPLY-DERIVED CLASSES

The multiply-derived class MotorHome

Car

Home

MotorHome

Definition scheme for class MotorHome
class MotorHome : public Car, public Home
{
private:
// Additional private members here
protected:
// Additional protected members here
public:
// Additional public members here
};

MULTIPLY-DERIVED CLASSES



589

A class can contain not just one but several different base classes
...


ᮀ The Multiply-Derived Class MotorHome
This class Car is used to represent vehicles and the class Home contains characteristic
values for an apartment, such as floor space, number and type of rooms, and typical operations, such as building, selling, or renting
...
The opposite page
shows the inheritance and definition schemes for the new class
...
More
specifically, the object contains two base sub-objects of type Car and Home
...
A MotorHome type object not only allows access to the additional
public members but to all the public members of the base classes Car and Home
...
The MotorHome class could
have the public base class Car and the protected base class Home
...
};

If the keyword is omitted, the base class will default to private
...
};

This statement defines the public base class Car and the private base class Home
...

In multiple inheritance each public base class establishes an is relationship
...
If the MotorHome class inherits two public base classes,
a motor-home is a special kind of motor vehicle and a special kind of home
...
The following statement

Example: class B : public A, public A

// Error

{
...

A class can be derived from several classes that have a common base class, however
...

The inheritance graph on the opposite page shows the multiply-derived class SUV,
which was derived from the classes PassCar and Van
...
This makes Car a multiple indirect base class of the
SUV class
...
Access to members
of the Car class results in ambiguity
...
);
cout << mySUV
...
In this case the compiler cannot decide which
method is meant
...
If both the Home class and the Car class
contain a method called getNr(), the getNr() method cannot be correctly identified
in the following statement
...
);
motorHome
...


Example: cout << motorHome
...
PassCar::getProd();

The getNr() method in the Home class is called first, followed by the getProd()
method inherited by PassCar from the Car class
...
Why should a station wagon contain two versions of
the manufacturer’s name or the chassis number for example? So you might be asking
yourself whether you can define multiply-derived classes that will contain only one
instance of an indirect base class
...
An object in a multiply-derived class contains
only one instance of the members in a virtual base class
...


ᮀ Declaration
A direct base class is declared virtual when a derived class is defined
...

In the definition scheme shown opposite, the Car class becomes the virtual base class
of PassCar and Van
...

A virtual base class takes effect in cases of multiple inheritance
...
};

ensures that the SUV class only contains one instance of the virtual base class Car
...

More specifically, the statement

Example: cout<<"Producer: " << mySUV
...

The following items are important with respect to virtual base classes:



a virtual base class stays virtual even if further derivations are built
...

you cannot change the declaration of an indirect base class to virtual
...
Later modifications will require modifications to the source code of any
derived classes
...
The sub-object whose class is nearer
to the top of the inheritance graph is created first
...

The activation order used for the constructors in simple inheritance has been generalized
for multiple inheritance
...

When a derived class is defined, the following rules apply:


In cases of multiple inheritance, base classes are entered into the inheritance
graph from left to right in the order in which they were stated when the class was
defined
...


If the class hierarchy does not contain any virtual base classes, the following applies to
the activation order of the constructors
...

Finally, the constructor belonging to the current class, which is at the bottom of
the inheritance graph, is executed
...
Then the constructor
of MultiDerived is executed
...
If the base initializer definition is missing in a constructor definition, the default constructor of the base class is
automatically executed
...


596



CHAPTER 27



MULTIPLE INHERITANCE

INITIALIZING VIRTUAL BASE CLASSES

Class SUV
class SUV : public PassCar, public Van
{
private:
//
...
) : Car(
...
However, if there is one virtual base class in the class hierarchy,
the virtual base class constructor is executed before a constructor of a non-virtual base
class is called
...


The constructor of the virtual base class nearest the top of the inheritance graph is
executed first
...

In our example with the multiply-derived class SUV (Sport Utility Vehicle) the constructor for the virtual base class Car is called first, followed by the direct base classes
PassCar and Van, and last but not least, the constructor of the SUV class
...
A base initializer of the directly-derived class or any other derivation could be
responsible
...
e
...


The example opposite shows SUV containing a constructor with one base initializer
...

For the purpose of initialization, it does not matter whether a class derived directly
from Car contains a base initializer or not
...
If the base classes
PassCar and Van also contained base initializers for the virtual base class Car, these
would be ignored too
...
Whatever happens, a default
constructor must then exist in every virtual base class! Thus, base initializers that happen
to exist in base classes are also ignored
...









Define an enumeration type CATEGORY that represents the categories
“Luxury,” “First Class,” “Middle Class,” and “Economy”
...
Supply default values for
your constructor definition to create a default constructor
...

Define a class derived from the Car and Home classes called MotorHome,
which is used to represent motorhomes
...
The MotorHome class contains a new data member used to
store one value of the CATEGORY type
...

Place your definitions of the Home and MotorHome classes in a separate
header file, which includes the existing header file car
...

Write a main function that first fully initializes a MotorHome type object
and then outputs the object
...
Call all the set methods in the
MotorHome class and its base classes to set your own values for the
objects
...


600



CHAPTER 27

MULTIPLE INHERITANCE

Class hierarchy for the multiply-derived class SUV

Car
Data members:
car number
producer

PassCar

Van

Data members:
car type
sun roof (y/n)

Data members:
capacity (lbs)

SUV
Data members:
number of seats

EXERCISES



601

Exercise 2
Now fully define the SUV class for testing virtual base classes
...
h header file to
make Car a virtual base class of the PassCar class
...
The
new class should contain an additional data member used to represent
the payload of the van in kilograms
...

The constructor should use default values to initialize the data members
with defaults, thus providing a default constructor for the class
...
In addition to the access
method display(), you still need to define methods for screen output
...
Store the number of seats available in the station
wagon as a data member
...

Additionally, define access methods and a display() to define output
...




CHAPTER 27



solutions

602

MULTIPLE INHERITANCE

SOLUTIONS

Exercise 1
//
//
//
//
//
//
//
//
//
//
//

-----------------------------------------------------car
...
cpp
Implementing methods of Car, PassCar, and Truck
-----------------------------------------------------These files have been left unchanged
from Chapters 23 and 25
...
h : Definition of the class Home and the
//
multiply-derived class MotorHome
// -----------------------------------------------------#ifndef _MOTORHOME_H_
#define _MOTORHOME_H_
#include "car
...
0)
{ room = r; ft2 = m2;}
void setRoom(int n){ room = n;}
int getRoom() const { return room; }
void
setSquareFeet(double m2){ ft2 = m2;}
double getSquareFeet() const { return ft2; }
void display() const
{
cout << "Number of rooms:
" << room
<< "\nSquare feet: "
<< fixed << setprecision(2) << ft2 << endl;
}
};

SOLUTIONS



class MotorHome : public Car, public Home
{
private:
CATEGORY cat;
public:
MotorHome(long n=0L, const string& prod="", int ro=0,
double m2=0
...
cpp
// Testing the multiply-derived class MotorHome
// -----------------------------------------------------#include "motorHome
...
5, LUXURY);
rv
...
display();
cin
...
setNr(54321);
holiday
...
setRoom(1);
holiday
...
5);
holiday
...
display();
return 0;
}

Exercise 2
// -----------------------------------------------------// car
...
cpp
// Implementing the methods of Car, PassCar, and Truck
// -----------------------------------------------------//
// These files are carried over from Chapter 23 and 25,
// with the following changes:
//
// Class Car is a virtual base class now
class PassCar : public virtual Car
{
//
...

};

// -----------------------------------------------------// suv
...
h"
class Van : public virtual Car
{
private:
double capacity;

SOLUTIONS

public:
Van(long n=0L, const string& prod="",
double l=0
...
0, int z = 1)
: PassCar(tp,sb), Car(n,prod),
Van(n,prod,l), cnt(z)
{ }
void display() const
{
PassCar::display();
Van::display();
cout << "Number of seats:
}
};
#endif

" << cnt << endl;



605

606



CHAPTER 27

MULTIPLE INHERITANCE

// -----------------------------------------------------// suv_t
...
h"
int main()
{
SUV mobil("Bravada", true, 120345, "Oldsmobile",350,6);
mobil
...
display();
trucky
...
setProd("Renault");
trucky
...
);
trucky
...
In addition to throwing and
catching exceptions, we also examine how exception specifications are
declared and exception classes are defined, additionally looking into the
use of standard exception classes
...

{

...



...

if(func()<=0)
// All errors
// are
// handled

...

{

...
error
else if
(x == -1)
//2
...

}

}
}

int func( void)
{

...

if(catastrophe)
return -1;

...
Some common causes of errors are






division by 0, or values that are too large or small for a type
no memory available for dynamic allocation
errors on file access, for example, file not found
attempt to access an invalid address in main memory
invalid user input

Anomalies like these lead to incorrect results and may cause a computer to crash
...

One of the programmer’s most important tasks is to predict and handle errors
...


ᮀ Traditional Error Handling
Traditional structured programming languages use normal syntax to handle errors:



errors in function calls are indicated by special return values
global error variables or flags are set when errors occur, and then checked again
later
...


Example: if( func()> 0 )
// Return value positive => o
...

else
// Treat errors

Error variables and flags must also be checked after every corresponding action
...

If you do happen to forget to check for errors, the consequences may be fatal
...
cpp: Defining the function calc(),
//
which throws exceptions
...
Exception handling is based on keeping
the normal functionality of the program separate from error handling
...
The calling environment performs central
error handling
...

When reporting an error, specific information on the error cause can be added
...


ᮀ The throw Statement
An exception that occurs is recorded to the calling environment by means of a throw
statement; this is why we also say that an exception has been thrown
...
It
can belong to any type except void
...


ᮀ Exception Classes
Normally, you define your own exception classes to categorize exceptions
...

An exception class need not contain data members or methods
...
Generally,
the exception class will contain members that provide more specific information on the
cause of the error
...
In the first case, the
exception thrown is a string
...
Instead of creating a local exception object errorObj, a temporary object
can be created:

Example: throw Error();

// It is shorter

612



CHAPTER 28



EXCEPTION HANDLING

EXCEPTION HANDLERS

Syntax of try and catch blocks
try
{
// Exceptions thrown by this block will be
// caught by the exception handlers,
// which are defined next
...

}
[ catch( Type2 exc2)
{
// Type2 exceptions are handled here
...

//etc
...
)
{
// All other exceptions are handled here
...
] in a syntax description indicate that the enclosed section is optional
...
An exception handler catches the exception object
thrown to it and performs error handling
...

This means that you need to specify two things when implementing exception handling:



the part of the program that can throw exceptions
the exception handlers that will process the various exception types
...
Each keyword precedes a code block and thus they are often referred to as try and catch blocks
...


ᮀ try and catch Blocks
A try block contains the program code in which errors can occur and exceptions can be
thrown
...

Each catch block defines an exception handler, where the exception declaration, which is
enclosed in parentheses, defines the type of exceptions the handler can catch
...
A minimum of one catch block is
required
...
If there is no handler defined for a particular exception type, the
program will not simply enter an undefined state but will be orderly terminated by a call
to the standard function terminate()
...
This functionality is provided by a special syntax in
the catch statement with an exception declaration consisting of just three dots
...
)
{ // General handler for
// all other exceptions
}

Since the application program decides what reaction is applicable for certain error conditions, the try and catch blocks are formulated in the application
...
cpp: Tests the function calc(),
//
which throws exceptions
...

}
catch( string& s)
// 1st catch block
{
cerr << s << endl;
}
catch( Error& )
// 2nd catch block
{
cerr << "Division by 0! " << endl;
}
catch(
...

return 0;
}



NOTE
As the Error class contains no data members, the corresponding catch block declares only the type
of exception, and no parameters
...


THROWING AND CATCHING EXCEPTIONS



615

ᮀ Backing Out of an Error Condition
When the throw statement is executed, an exception object is thrown
...


Example: throw "Cyclone!";
This creates a string as an exception object and copies the string "Cyclone!" to it
...

The exception object is then thrown and the program control leaves the try block
...

This specifically involves destroying any local, non-static objects
...


ᮀ Searching for Handlers
After leaving the try block, the program control is transferred to an matching handler
in the catch blocks that follow
...

A handler is called when the type in the exception declaration is




identical to the exception type thrown or
a base class of the exception type or
a base class pointer and the exception is a pointer to a derived class
...
) always has to be defined last
...


ᮀ Continuing the Program
After executing a handler, the program continues with the first statement following the
catch blocks, unless the handler throws another exception or terminates the program
...

The first two catch blocks handle both exceptions that the calc() function can
throw
...
If an unexpected exception occurs, a message is again displayed, but in this case the program then terminates
...

try
{
// Type1 and Type2 exceptions are thrown here
...

}
// Other Type1 exceptions
// can be thrown
...

}
catch(
...

}



NOTE
This scenario assumes that the error classes Type1 and Type2 are not derived one from another
...


NESTING EXCEPTION HANDLING



617

ᮀ Nested try and catch Blocks
A program will normally contain multiple try blocks with appropriate exception handlers
...

However, a try block can contain additional try blocks
...
Handlers in a nested try block
can also pre-handle specific errors and then pass control to the try block wrapper for
final handling
...
This is achieved using a throw statement that does not
expect an exception object
...
The statement is only valid within a nested catch block
for this reason
...
The application
programmer must have knowledge of both the function prototype and the exceptions the
function can throw to ensure that he or she will be capable of programming correct function calls and taking appropriate action in case of errors
...


Example: int func(int) throw(BadIndex, OutOfRange);
The list BadIndex, OutOfRange states the exceptions that the function func()can
throw
...
If the throw statement is also missing, there is no specific information about possible exceptions and any exception can be thrown
...
cpp: New version of function calc(),
//
which throws exceptions of type
//
MathError
...

}
catch( MathError& err)
// catch block
{
cerr << err
...

return 0;
}
double calc( int a, int b ) throw (MathError)
{ if ( b < 0 )
throw MathError("Denominator is negative!");
if( b == 0 )
throw MathError("Division by 0!");
return ((double)a/b);
}

DEFINING YOUR OWN ERROR CLASSES



619

ᮀ Exception Class Members
When an exception is thrown, the exception object type determines which exception
handler will be executed
...

However, an exception class can contain data members and methods—just like any
other class
...
Thus, the exception handler can
no longer access the previously existing objects
...
For example, you can store data important for exception handling in an
exception object
...
The calc() function throws an
exception when a number input by a user is negative or 0
...
The exception handler can then use
the getMessage() method to evaluate the message
...
A base class will
normally represent a general error type and specific errors will be represented by derived
classes
...
” You could call these
classes DivisionByZero and OverflowError, for example
...


620



CHAPTER 28



EXCEPTION HANDLING

STANDARD EXCEPTION CLASSES

Exception classes derived from logic_error

invalid_argument

Invalid argument

out_of_range

Argument value not in its expected range

length_error

Length exceeds maximum capacity

domain_error

Domain error reported by the implementation

Exception classes derived from runtime_error
range_error

Range error in internal computation

underflow_error

Arithmetic underflow error

overflow_error

Arithmetic overflow error

Using standard exception classes
// Subscript operator of class FloatArr throws
// exceptions with type of standard class out_of_range:
// --------------------------------------------------#include
#include
using namespace std;
double& FloatArr::operator[](int i) throw(out_of_range)
{ if( i < 0 || i >= anz )
throw out_of_range("Invalid index!");
else return arrPtr[i];
}
// -------------- Test Program -----------------int main()
{
try
{
// Uses arrays of type FloatArr
}
catch(out_of_range& err)
{
cerr << err
...

}

STANDARD EXCEPTION CLASSES



621

ᮀ Hierarchy of Standard Exception Classes
The C++ standard library contains various exception classes, which are used in the string
and container libraries, for example
...
Their definitions are to be found in the
header file stdexcept
...
In addition to a default constructor, a copy constructor, and
an assignment, this class contains a virtual public method, what(), which returns a
message on the error cause as a C string
...
These errors can be avoided
...
These errors are unpredictable
...
For example, the method at() in the
string class throws an out_of_range type exception when an invalid string position
is passed to it
...

An exception of the overflow_error or underflow_error type is thrown if the
value to be displayed is too large or too small for the type in use
...

A constructor with a string as a parameter is defined in every class derived from
exception
...

The what() method returns this error message as a C string
...


The second exception handler’s message:

Error in writing:
Invalid index:
...







Define the exception class BadIndex for this purpose and store the class
in the header file “floatArr
...
The exception class must contain a data
member to store the invalid index
...
The const access method
getBadIndex() returns the data member
...
Add an exception specification to the declaration of the subscript
operators
...
Add appropriate exception
specifications to the definitions and change the return types from bool to
void
...

Write a main function where a constant vector is created and initialized
with fixed values
...
The array elements are displayed and an index is read until an invalid
index value is input
...

Then create a non-constant array
...
Elements are appended or inserted within a try block
...
Then finally output the
array elements outside the try and catch blocks
...


EXERCISES



625

Exercise 2
Implement exception handling for the Fraction class, which is used to
represent fractions (see Exercise 2, Chapter 19)
...



Define the exception class DivError, which has no data members, within
the Fraction class
...

Change the definition of the constructor in the Fraction class
...

Similarly modify the operator functions
...
You will need
to arrange three different try and catch blocks sequentially
...
Create several fractions,
including some with a numerator value of 0 and one with 0 as its
denominator
...

The second try/catch block tests divisions
...
The corresponding exception handler should send the
second error message shown opposite to your standard output
...
If the value of the denominator is 0, the denominator is
read again
...




CHAPTER 28



solutions

626

EXCEPTION HANDLING

SOLUTIONS

Exercise 1
// -----------------------------------------------------// floatArr
...

// Methods throw exceptions for an invalid index
...

Current number of elements
...


public:
FloatArr( int n = 256 );
// Constructors
FloatArr( int n, float val);
FloatArr(const FloatArr& src);
~FloatArr();
// Destructor
FloatArr& operator=( const FloatArr&); // Assignment
int

length() const { return cnt; }

// Subscript operators:
float& operator[](int i) throw(BadIndex);
float operator[](int i) const throw(BadIndex);
// Methods to append a float value
// or an array of floats:
void append( float val);
void append( const FloatArr& v);

SOLUTIONS



FloatArr& operator+=( float val)
{
append( val);
return *this;
}
FloatArr& operator+=( const FloatArr& v)
{
append(v);
return *this;
}
// Methods to insert a float value
// or an array of float values:
void insert( float val, int pos) throw(BadIndex);
void insert(const FloatArr& v,int pos) throw(BadIndex);
void remove(int pos) throw(BadIndex); // Remove
// at pos
...
width();
// Save field width
...
arrPtr; p < v
...
cnt; ++p)
{
os
...
cpp
// Implementing the methods of FloatArr
...
h"
// --- Constructors --FloatArr::FloatArr( int n )
{
max = n;
cnt = 0;
arrPtr = new float[max];
}

// Sets max and cnt
...
max;
cnt = src
...
arrPtr[i];
}
// --- Destructor --FloatArr::~FloatArr()
{
delete[] arrPtr;
}
// Private functions to help enlarge the array
...
max;
cnt = src
...

arrPtr[i] = src
...

void FloatArr::append( float val)
{
if( cnt+1 > max)
expand( cnt+1);
arrPtr[cnt++] = val;
}
void FloatArr::append( const FloatArr& v)
{
if( cnt + v
...
cnt);
int count = v
...

for( int i=0; i < count; ++i)
arrPtr[cnt++] = v
...

void FloatArr::insert(float val, int pos) throw(BadIndex)
{
insert( FloatArr(1, val), pos);
}
void FloatArr::insert( const FloatArr& v, int pos )
throw( BadIndex )
{
if( pos < 0 || pos > cnt)
// Append is also possible
...
cnt)
expand(cnt + v
...
cnt] = arrPtr[i];
// position pos
...
cnt; ++i)
// Fill the gap
...
arrPtr[i];
cnt = cnt + v
...
cpp
// Tests exception handling for float arrays
...
h"
int main()
{
const FloatArr v(10, 9
...
\n"
<< "\nInvalid index: "
<< err
...
insert(1
...

w
...
2F, 1);
w
...
3F, 3);
// Error!
w[10] = 5
...
remove(7);
// Error!
}
catch(BadIndex& err)
{
cerr << "\nError in writing! "
<< "\nInvalid index: "
<< err
...
h
// A numeric class to represent fractions,
// exception handling is included
...
numerator * denominator
+ numerator * a
...
denominator;
return *this;
}
Fraction& operator-=(const Fraction& a)
{
*this += (-a);
return *this;
}
Fraction& operator++()
{
numerator += denominator;
return *this;
}
Fraction& operator--()
{
numerator -= denominator;
return *this;
}
friend Fraction operator+(const Fraction&,
const Fraction&);
friend Fraction operator-(const Fraction&,
const Fraction&);
friend Fraction operator*(const Fraction&,
const Fraction&);
friend Fraction operator/(const Fraction&,
const Fraction&)
throw(Fraction::DivisionByZero);
friend ostream& operator<<(ostream&, const Fraction&);
friend istream& operator>>(istream& is, Fraction& a)
throw(Fraction::DivisionByZero);
};
#endif

SOLUTIONS



// ------------------------------------------------------// fraction
...

// ------------------------------------------------------#include
#include
using namespace std;
#include "fraction
...
denominator = a
...
denominator;
temp
...
numerator*b
...
numerator * a
...
numerator = a
...
numerator;
temp
...
denominator * b
...
numerator == 0) throw Fraction::DivisionByZero();
// Multiply a with the inverse of b:
Fraction temp;
temp
...
numerator * b
...
denominator = a
...
numerator;
if( temp
...
numerator = -temp
...
denominator = -temp
...
numerator << "/" << a
...
numerator;
cout << " Denominator != 0: ";
is >> a
...
denominator == 0)
{
cout << "\nError: The denominator is 0\n"
<< "New Denominator != 0: "; is >> a
...
denominator == 0)
throw Fraction::DivisionByZero();
if( a
...
numerator = -a
...
denominator = -a
...
cpp : Testing the class Fraction
...
cpp fraction
...
h>
#include "fraction
...


We will also illustrate how to make objects in polymorphic classes
persistent, that is, how to save them in files
...


637

638



CHAPTER 29



MORE ABOUT FILES

OPENING A FILE FOR RANDOM ACCESS

Combined open modes for read and write access

Open mode

Effects

Must the file
exist?

ios::in
| ios::out

yes

ios::in
| ios::out
| ios::trunc

Opens the file for input and
output
...


no

ios::in
| ios::out
| ios::app



To open the file for input and
output
...
If the file does not exist,
it will be created
...


no

NOTE
1
...

2
...


OPENING A FILE FOR RANDOM ACCESS



639

ᮀ Random File Access
So far we have only looked at sequential file access
...

Random file access gives you the option of reading and writing information directly at a
pre-defined position
...
After pointing the pointer, you can revert to using the read and write operations
that you are already familiar with
...
This implies opening the file in binary mode to avoid having to
transfer additional escape characters to the file
...
fle", mode);

This statement opens the file "Account
...
The file will be created if it did not previously exist
...

To enable random read and write access to a file, the file can be opened as follows:

Example: ios::openmode mode = ios::in | ios::out |
ios::binary;
fstream fstr("account
...
If the file does not exist, you
can use the ios::trunc flag to create it
...
fle" cannot be found
...
The tellp() and tellg() methods return the current position of the put or
get pointers as a long value
...
tellg();
This statement queries the current position of the read pointer in the myfile stream
...

The current file position can be modified using the seekp() or seekg() method
...


ᮀ Positioning Flags
Three ios::seekdir type positioning flags are defined in the ios class for this purpose; these are ios::beg, ios::cur, and ios::end
...
fle" at offset pos
...
fle", ios::out |
ios::binary);
fstr
...
write( fstr );

This calls the write() method in the Account class, which allows an object to write
its own data members to a file (see Chapter 18)
...
The statement used to position the write pointer in the last
example can therefore be formulated as follows:

Example: fstr
...

However, you cannot position the read/write pointer before the beginning of the file
...
This only makes sense if all the empty slots in the file are of an equal length, as they
can be overwritten later
...


642



CHAPTER 29



MORE ABOUT FILES

POSITIONING FOR RANDOM ACCESS (CONTINUED)

Representing an index entry
// index
...
and:
int recordSize() const
{ return sizeof(key) + sizeof(recNr); }
fstream& write( fstream& ind) const;
fstream& read( fstream& ind);
fstream& write_at(fstream& ind, long pos) const;
fstream& read_at( fstream& ind, long pos);
};
#endif

The read_at() and write_at() methods
// index
...
h"
//
...
seekp(pos);
ind
...
write((char*)&recNr, sizeof(recNr) );
return ind;
}
fstream& IndexEntry::read_at(fstream& ind, long pos)
{
ind
...
read((char*)&key, sizeof(key) );
ind
...
You should be aware that
the first argument is 0L to indicate that long type is required
...
seekg(0L, ios::end);
unsigned long count = fstr
...

These positioning methods are useful for files opened in binary mode
...
In text
mode, conversions of LF <=> CR/LF prevent the methods from working correctly
...
Given that size is the length of a record
0L,

size,

2*size,
...

If you are working with variable length records, you cannot exactly compute their
positions
...

The index stores pairs of keys and record positions, so-called index entries in a file
...
If the index is sorted, the position that correlates to the required key can be
quickly found using the binary search algorithm
...
The class
comprises methods for reading and writing an index entry at the current file position or
at any given position
...


644



CHAPTER 29

MORE ABOUT FILES



FILE STATE

Representing an index
// index
...
close(); }
void insert( long key, long pos);
long search( long key);
void retrieve(IndexEntry& entry, long pos );
};

Constructor of class IndexFile
// index
...
open(file
...
clear();
mode |= ios::trunc;
index
...
c_str(), mode);
if(!index)
return;
}
else
name = file;
}
//
...
A file operation can also fail if a file cannot be opened, or if a
block is not transferred correctly
...
Each state
flag corresponds to a single bit in a status-word, which is represented by the iostate
type in the ios class
...
g
...


The “flag” ios::goodbit is an exception to the rule since it is not represented by a
single bit, but by the value 0 if no other flag has been set
...
A
method exists for each state flag; these are eof(), fail(), bad(), and good()
...
This means you can discover
the end of a file with the following statement:

Example: if( fstr
...

The status-word of a stream can be read using the rdstate() method
...
rdstate() == ios::badbit )
...
If you call clear()
without any arguments, all the state flags are cleared
...


ᮀ The IndexFile Class
The IndexFile class, which uses a file to represent an index, is defined opposite
...
A new file can then be created
...


646



CHAPTER 29



MORE ABOUT FILES

EXCEPTION HANDLING FOR FILES

Defining your own exception classes
// exceptio
...
For example, a method that reads records from a file
can throw an exception when the state flag ios::eof is raised, that is, when the end of
the file is reached
...
In each
case the file name is saved for evaluation by the exception handler
...
You can use the exceptions() method to specify the flags in the status-word of a stream that will cause
exceptions to be thrown
...
The method
expects one or multiple state flags separated by the | sign
...


Example: ifstream ifstrm("account
...
exceptions(ios::failbit | ios::badbit);

On accessing the fstrm stream an exception is thrown if either one of the flags
ios::failbit or ios::badbit is raised
...

The exception thrown here is of a standard exception class, failure
...
The exception handler
will normally send the string to standard error output
...
If a bit is set in the
return value of the exceptions() method, an appropriate exception will be thrown
whenever this error occurs
...
exceptions();
if( except & ios::eofbit)
...


648



CHAPTER 29



MORE ABOUT FILES

PERSISTENCE OF POLYMORPHIC OBJECTS

// account
...

// -------------------------------------------------//
...

public:
// Constructor, access methods
...

TypeId getTypeId() const { return DEP_ACC; }
ostream& write(ostream& fs) const;
istream& read(istream& fs);
};
class SavAcc: public Account
{
// Data members, constructor,
...
cpp: Implements the methods
...
h"
ostream& DepAcc::write(ostream& os) const
{
if(!Account::write(os))
return os;
os
...
write((char*)&deb, sizeof(deb) );
return os;
}
istream& DepAcc::read(istream& is)
{
if(!Account::read(is))
return is;
is
...
read((char*)&deb, sizeof(deb));
return is;
}
//
...
You need to ensure that an object can be reconstructed precisely
when it is read
...
So it is not simply a case of making the data members of an
object into records and writing them to a file
...
You must write both the type and the data members of the object to a file
...
If the objects contain dynamic members, you must save the referenced objects themselves along with
information on the object type
...
The methods can have a virtual definition within the class hierarchy
...


ᮀ Storing Objects of the Account Hierarchy
The opposite page shows the Account class, with which you should already be familiar
...
The implementation of the read() and
write() methods was discussed earlier in Chapter 18, “Fundamentals of File Input and
Output,” and is unchanged
...
The implementation first calls the appropriate base class method
...

At present, no type information will be written to file or read from file
...
The following section contains more details on this topic
...
h : (continued)
// Add definition of AccFile class
// -------------------------------------------------//
...
h"
class AccFile
{
private:
fstream f;
// Stream
string name;
// Filename
public:
AccFile(const string& s) throw(OpenError);
~AccFile(){ f
...
cpp: (continued)
// Implements methods of class AccFile
...
seekp(0L, ios::end);
// Seek to end,
long pos = f
...

if( !f )
throw WriteError(name);
TypeId id = acc
...
write( (char*)&id, sizeof(id));
if(!f)
throw WriteError(name);
else
acc
...


// To write an object
// to the file
...
Since the objects you need to save belong to different types, you
must save both the data members and the type of object
...

The methods in the class you are going to define should throw exceptions if errors
occur
...


ᮀ The AccFile Class
The AccFile class, which is used for random access to a file with account data, is
defined opposited
...

The constructor saves the file name and opens a given file for reading and appending
at end-of-file
...

The append() method writes an account passed to it as an argument at end-of-file
and returns the position where the account was written into the file
...
Depending on this type the append() method will write the appropriate type
field to the file and then call the virtual method write(), allowing the current object
to write itself to the file
...

The retrieve() method first reads the type identifier and then determines the type
of object it needs to allocate memory for
...
Here too, an
exception will be thrown if a stream access error occurs
...
cpp: (continued)
// Implements the methods of class IndexFile
...

void IndexFile::insert(long k, long n)
throw(ReadError, WriteError)
{
IndexEntry entry;
int size = entry
...

index
...
seekg(0, ios::end);
long nr = index
...

if(!index) throw ReadError(name);
nr -= size;
// Last entry
...
read_at(index, nr))
throw ReadError(name);
if( k < entry
...

{
entry
...
setKey(k); entry
...
write_at(index, nr + size);
if(!index)
throw WriteError(name);
}

// insert

APPLICATION: INDEX FILES



653

It makes sense to organize data sequentially in files if you need to walk through all the
records regularly
...

However, most applications need to provide quick access to specific data
...
Index files
can mean a real performance boost in cases like this
...
The
index consists of pairs of keys and record positions for the primary file
...
This situation can be more easily
explained by the following graphic:

Index

Primary file

12345 |

The index is sorted by reference to the keys for speed of access, allowing you to perform a
binary search to locate the position of a record
...
The insert()
method, which correctly inserts a new record into the sorted index, is defined opposite
...
If the current position is 0,
that is, the file is empty, the entry is inserted at offset 0
...


654



CHAPTER 29



MORE ABOUT FILES

IMPLEMENTING AN INDEX FILE

Representing the index file
// index
...
prim"), IndexFile(s + "
...
cpp:
Implementing the methods
...
getNr()) == -1)
{
long pos = append(acc); // Insert in primary file
if(pos != -1)
// Insert in
IndexFile::insert(acc
...

}
}
Account* IndexFileSystem::retrieve(long key )
{ long pos = search(key);
// Get the record address:
if( pos == -1 )
// Account number found?
return NULL;
else
{ IndexEntry entry;
// Read the index entry:
IndexFile::retrieve(entry, pos);
// Read from primary file:
return( AccFile::retrieve( entry
...

Let’s now look at a sample index file, used for managing bank accounts
...
The only data member is a string for the file name
...
Base initializers are then used to open the corresponding files
...


ᮀ Inserting and Retrieving Records
The insert() method was defined to insert new records
...
If not, a new
record is appended to the end of the primary file using the append() method
...

The IndexFileSystem class also contains the retrieve() method, which is used
to retrieve records from the primary file
...
Then the record is retrieved from the primary file by the AccFile class
retrieve() method
...
It’s your job to implement these three methods as
your next exercise!
Using a sorted file to implement an index has the disadvantage that records need to
be shifted to make room to insert new records
...




CHAPTER 29



exercise s

656

MORE ABOUT FILES

EXERCISES

Exercise 1
Class IndexFile
class IndexFile
{
private:
fstream index;
string name;

// Filename of the index

public:
IndexFile(const string s) throw(OpenError);
~IndexFile( ){ index
...
close(); }
long
append( Account& acc) throw(WriteError);
Account* retrieve( long pos ) throw(ReadError);
};

EXERCISES



657

Exercise 1
Complete and test the implementation of the IndexFileSystem class
...

a
...

b
...
The method
retrieves a record at a given position in the index
...
Define the search() method, which looks up an index entry for an
account number passed to it as an argument
...

Return value: The position of the record found, or -1 if the account
number is not found in the index
...
Then define the retrieve() method for the AccFile class, which first
evaluates the type field at a given position in the account file, then
dynamically allocates memory for an object of the appropriate type, and
finally reads the data for an account from the file
...
Write a main() function that uses a try block to create an IndexFileSystem type object and to insert several accounts of various types
into the index file
...
Write an exception handler to handle the various errors that could occur
...


658



CHAPTER 29

MORE ABOUT FILES

Hash Files
Hash Files profit from random file access in localizing file records directly
...

Hash file

4713123434

Hash function

Key

The idea behind hashing is to provide a function, the hash function, which is
applied to the hash key of a record and yields the address of the file record
...
However, hash keys, such as
account or insurance numbers, consist of a fixed number of digits that do not
start with 0
...
The number 0 is the first record number and b-1 is the last record
number in the address space of the hash file
...

However, the hash function maps the hash key values key, key + b, key + 2*b,
etc
...
In this case collisions may occur, for example,
when a new record being inserted hashes to an address that already contains a
different record
...
The process of finding another position at which to insert the new
record is called collision resolution
...
The new file record is then inserted at this position
...
The concept of hash
files is explained on the opposite page
...
The customer id is the key
used by the hash function opposite to compute the address of the record
...

Note: Linear solution provides for adequate access times if the address space is
sufficiently large and not too full
...
The hash function opposite will guarantee a good distribution if b is a
sufficiently large prime number
...
You need
to store the customer id as an unsigned long value and the name of
the customer as a char array with a length of 30
...
Both methods expect
the position and the stream as arguments
...
The private members of the class comprise an fstream type file stream, a string used to
store the file name, an int variable used to store the number b, and the
hash function shown opposite as a method
...
It opens the corresponding file for read and write access
...

Additionally declare the methods insert() and retrieve() to insert or
retrieve single records
...
If a collision
occurs, the methods perform a sequential search to locate the next free
slot in the address space (mod of address space size), or the desired customer data
...
g
...
Add various customer information
records to the hash file and then retrieve this data
...




CHAPTER 29



solutions

660

MORE ABOUT FILES

SOLUTIONS

Exercise 1
// -----------------------------------------------------// exceptio
...
earlier in this chapter)
...
h :
// Defines the classes
//
Account, DepAcc, and SavAcc
// with virtual read and write methods as well as
// the class AccFile to represent account files
...
h"
enum TypeId { ACCOUNT, DEP_ACC, SAV_ACC };
class Account
{
private:
string name;
unsigned long nr;
double balance;

// Data elements:

public:
// Constructor:
Account( const string c_name = "X",
unsigned long c_nr
= 1111111L,
double c_balance
= 0
...

// The other methods:
virtual TypeId getTypeId() const { return ACCOUNT; }
virtual ostream& write(ostream& fs) const;
virtual istream& read(istream& fs);
virtual void display() const
{
cout << fixed << setprecision(2)
<< "----------------------------------\n"
<< "Account holder:
" << name
<< endl
<< "Account number:
" << nr
<< endl
<< "Balance of account:
" << balance << endl
<< "----------------------------------\n"
<< endl;
}
};
class DepAcc : public Account
{
private:
double limit;
// Overdrawn limit
double interest;
// Interest rate
public:
DepAcc( const string s = "X",
unsigned long n = 1111111L,
double bal = 0
...
0,
double ir = 0
...

// The other methods are implicit virtual:
TypeId getTypeId() const { return DEP_ACC; }
ostream& write(ostream& fs) const;
istream& read(istream& fs);

661

662



CHAPTER 29

MORE ABOUT FILES

void display() const
{
Account::display();
cout << "Overdrawn limit:
" << limit << endl
<< "Competitive interest: " << interest
<< "\n----------------------------------\n"
<< endl;
}
};
class SavAcc: public Account
{
private:
double interest;

// Compound interest

public:
// Methods as in class DepAcc
...
close(); }
long append( Account& acc)
throw(WriteError);
Account* retrieve( long pos) throw(ReadError);
void display() throw( ReadError);
};
#endif

SOLUTIONS

// ---------------------------------------------------// account
...

// ---------------------------------------------------#include "account
...
write((char*)&nr, sizeof(nr) );
os
...
read((char*)&nr, sizeof(nr) );
is
...
write((char*)&limit, sizeof(limit) );
os
...
read((char*)&limit, sizeof(limit) );
is
...




663

664



CHAPTER 29

MORE ABOUT FILES

// ---- Methods of class AccFile ---AccFile::AccFile(const string& s) throw( OpenError)
{
ios::openmode mode = ios::in | ios::out | ios::app
| ios::binary;
f
...
c_str(), mode);
if(!f)
throw OpenError(s);
else
name = s;
}
void AccFile::display() throw(ReadError)
{
Account acc, *pAcc = NULL;
DepAcc depAcc;
SavAcc savAcc;
TypeId id;
if( !f
...
read((char*)&id, sizeof(TypeId)) )
{
switch(id)
{
case ACCOUNT: pAcc = &acc;
break;
case DEP_ACC: pAcc = &depAcc;
break;
case SAV_ACC: pAcc = &savAcc;
break;
default: cerr << "Invalid flag in account file"
<< endl;
exit(1);
}
if(!pAcc->read(f))
break;
pAcc->display();
cin
...
eof())
throw ReadError(name);
f
...
seekp(0L, ios::end);
// Seek to end,
long pos = f
...

if( !f )
throw WriteError(name);
TypeId id = acc
...
write( (char*)&id, sizeof(id));

// Write the TypeId

if(!f)
throw WriteError(name);
else
acc
...

if(!f)
throw WriteError(name);
else
return pos;
}
Account* AccFile::retrieve( long pos) throw(ReadError)
{
f
...
seekg(pos);
// Set the get pointer
if( !f )
throw ReadError(name);
TypeId id;
f
...
h: Contains definitions of classes
//
IndexEntry representing an index entry,
//
Index
representing the index and
//
IndexFile representing an index file
...
h"
using namespace std;
class IndexEntry
{
private:
long key;
long recPos;

// Key
// Offset

public:
IndexEntry(long k=0L, long n=0L){ key=k; recPos=n; }

void
long
void
long

setKey(long k)
getKey() const
setPos(long p)
getPos() const

{
{
{
{

key = k; }
return key; }
recPos = p; }
return recPos; }

int recordSize() const
{ return sizeof(key) + sizeof(recPos); }
fstream& write( fstream& ind) const;
fstream& read( fstream& ind);
fstream& write_at(fstream& ind, long pos) const;
fstream& read_at( fstream& ind, long pos);

SOLUTIONS



void display() const
{
cout << "Account Nr: " << key
<< " Position: " << recPos << endl;
}
};
class IndexFile
{
private:
fstream index;
string name;

// Filename of index

public:
IndexFile( const string& s) throw (OpenError);
~IndexFile() { index
...
prim"), IndexFile(s + "
...
cpp : Methods of the classes
//
IndexEntry, Index, and IndexFile
// -----------------------------------------------------#include "index
...
seekp(pos);
ind
...
write((char*)&recPos, sizeof(recPos) );
return ind;
}
fstream& IndexEntry::read_at(fstream& ind, long pos)
{
ind
...
read((char*)&key, sizeof(key) );
ind
...
write((char*)&key, sizeof(key) );
ind
...
read((char*)&key, sizeof(key) );
ind
...
open( file
...
clear();
mode |= ios::trunc;
index
...
c_str(), mode);
if(!index)
throw OpenError(name);
}
name = file;
}

SOLUTIONS



void IndexFile::display() throw(ReadError)
{
IndexEntry entry;
index
...
read(index))
break;
entry
...
eof())
throw ReadError(name);
index
...

int size = entry
...

index
...
seekg(0L, ios::end);
end = index
...
read_at(index, mid*size);
if(!index)
throw ReadError(name);
key = entry
...
read_at(index, begin * size);
if(!index)
throw ReadError(name);
if( k == entry
...
recordSize(); // Length of an index
// entry
...
clear();
index
...
tellg();
// Get file length
// 0, if file is empty
...
read_at(index, nr))
throw ReadError(name);

// Last entry
...
getKey())
// To shift
...
write_at(index, nr + size);
nr -= size;
}
else
{
found = true;
}
}
entry
...
setPos(n);
entry
...
clear();
if(!entry
...

bool IndexFileSystem::insert( Account& acc)
throw(ReadError, WriteError)
{
if(search(acc
...

{
long pos = append(acc);
// Add to primary file
...
getNr(), pos); // Add to Index
return true;
}
else
return false;
}
Account* IndexFileSystem::retrieve(long key )
{
// Get the record address from the index:
long pos = search(key);
// Byte offset of
// index entry
...

return NULL;
else
// Account number does exist:
{
IndexEntry entry;
// To read the index eintry
IndexFile::retrieve( entry, pos);
// Get from primary file:
return( AccFile::retrieve( entry
...
cpp : Testing the index file
// -----------------------------------------------------#include
#include
using namespace std;
#include "index
...
h"

671

672



CHAPTER 29

MORE ABOUT FILES

int main()
{
try
{
IndexFileSystem database("AccountTest");
Account acc1( "Vivi", 490UL, 12340
...
insert( acc1 );
SavAcc acc2( "Ulla", 590UL, 4321
...
5);
database
...
20, 10000
...
9);
database
...
IndexFile::display();
cin
...
AccFile::display();
unsigned long key;
cout << "Key? "; cin >> key;
if(database
...
retrieve(key);
if( pAcc != NULL )
{
pAcc->display();
delete pAcc;
pAcc = NULL;
}
else cout << "Retrieving failed" << endl;
}
catch(OpenError& err)
{
cerr << "Error on opening the file:" << err
...
getName() << endl;
exit(1);
}

SOLUTIONS



catch(ReadError& err)
{
cerr << "Error on reading from the file: "
<< err
...
)
{
cerr << " Unhandled Exception" << endl;
exit(1);
}
return 0;
}

Exercise 2
// ------------------------------------------------------// exceptio
...


// ------------------------------------------------------// hashFile
...

// ------------------------------------------------------#ifndef _HASH_H_
#define _HASH_H_
#include
#include
#include
#include
#include ...
h"
class HashEntry
{
private:
unsigned long nr;
char name[30];

673

674



CHAPTER 29

MORE ABOUT FILES

public:
HashEntry(unsigned long n = 0L, const string& s = "")
{
nr = n;
strncpy(name, s
...
c_str(), 29); name[30]='\0'; }
int getSize() const
{ return(sizeof(long) + sizeof(name)); }
fstream& write(fstream& fs);
fstream& read(fstream& fs);
fstream& write_at(fstream& fs, unsigned long pos);
fstream& read_at(fstream& fs, unsigned long pos);
virtual void display()
{
cout << fixed << setprecision(2)
<< "----------------------------------\n"
<< "Client number:
" << nr
<< endl
<< "Client:
" << name << endl
<< "----------------------------------\n"
<< endl;
cin
...
cpp : Methods of classes HashEntry and HashFile
// ------------------------------------------------------#include "hashFile
...
write((char*)&nr, sizeof(nr) );
f
...
read((char*)&nr, sizeof(nr) );
f
...
seekp(pos);
f
...
write( name, sizeof(name) );
return f;
}
fstream& HashEntry::read_at(fstream& f, unsigned long pos)
{
f
...
read((char*)&nr, sizeof(nr) );
f
...
open(file
...

if(!f)
// If file doesn't exist:
{
f
...
open(file
...
seekp(0L);
for( unsigned long i=0; i < b; i++) // Initialize
{
// the address space
rec
...
getSize();
// Hash-Wert:
unsigned long pos = hash_func(rec
...
read_at(f, pos*size);
if(!f)
throw ReadError(name);
else
{
if(temp
...
write_at(f, pos*size);
else
{
bool found = false;

// Read a slot
...

No => Search for
a free slot
...
read_at(f, p);
if(!f)
throw ReadError(name);
else
if(temp
...

else
// Proceed to the next slot:
p = (p + size)%(b*size);
}
if( p == pos*size )
// Address space full
...
write_at(f,p);

// Add to file
...
getSize();
unsigned long pos = hash_func(key);

// Hash value
...
read_at(f, pos*size);

// Read a slot
...
getNr() == key)
// Found?
return temp;
// Yes => finish
else
// No
=> search
{
unsigned long p = (pos*size + size)%(b*size);
while( p!= pos *size )
{
temp
...
getNr() == key)
return temp;
else
p = (p + size)%(b*size);
}
temp
...
setName("");

// Record found
...

// Key doesn't
// exist
...
seekg(0L);
for(unsigned int i = 0; i < b; i++)
{
temp
...
display();
}
f
...
cpp : Tests hash files
// ------------------------------------------------------#include
#include
#include "hashFile
...
fle", 7);
cout << "\nInsert: " << endl;
HashEntry kde( 3L, "Vivi");
hash
...
setNr(10L); kde
...
insert( kde );
kde
...
setName("Alexa");
hash
...
setNr(21L); kde
...
insert( kde );
kde
...
setName("Jeany");
hash
...
display();
unsigned long key;
cout << "Key? "; cin >> key;
HashEntry temp = hash
...
getNr() != 0L)
temp
...
getName() << endl;
exit(1);
}

catch(WriteError& err)
{
cerr << "Error writing to file: "
<< err
...
getName() << endl;
exit(1);
}
return 0;
}



679

This page intentionally left blank

chapter

30

More about Pointers
This chapter describes advanced uses of pointers
...

An application that defines a class used to represent dynamic
matrices is introduced
...
cpp: Sorts an array of pointers to accounts
//
according to the account numbers
// --------------------------------------------------#include "account
...

for( ; kptr < lastp; ++kptr )
{
minp = kptr;
for( temp = kptr + 1; temp <= lastp; ++temp )
{
if( (*temp)->getNr() < (*minp)->getNr() )
minp = temp;
}
ptrSwap( kptr, minp );
}
}
void ptrSwap( Account **p1, Account **p2 )
{
Account *help;
help = *p1; *p1 = *p2; *p2 = help;
}

POINTER TO POINTERS



683

ᮀ Motivation
Pointer variables are objects that have an address in memory, and this means you can use
pointers to address them
...
This is necessary
if



an array of pointers is to be dynamically allocated, or
a function expects an array of pointers as an argument
...
Since each element in the array is a pointer, this pointer variable must be a
pointer to a pointer
...


Example: Account** ptr = new Account*[400];
The pointer ptr is now pointing at the first pointer in the array with a total of 400
Account* type pointers
...


Example: void accSort( Account **kptr, int len);
You can use the kptr parameter to manipulate a pointer array whose length is stored in
the second parameter, len
...
Instead of
Account **kptr you can also use the equivalent form Account *kptr[]
...
The func-

tion uses the selection sort algorithm (which you have already worked with) for sorting
...

This saves time-consuming copying
...
h>
int func( char *buffer, int max,
...

long arg3;

...

arg3 = va_arg( argptr, long ); // Read arguments
...


...


VARIABLE NUMBER OF ARGUMENTS



685

C++ allows you to define functions that allow a variable number of arguments
...
The printf() function uses the conversion
specifiers in the format string to compute the number and type of arguments that follow
...
At least one obligatory argument is required
...
The optional arguments are represented by three dots
...
The function shown opposite, func(),
expects two or more arguments
...
);
To allow functions with a variable number of arguments to be defined, C++ pushes the
last argument onto the stack first
...

The optional arguments are accessed via a pointer, the so-called argument pointer,
which is designated by argptr here
...
h contain
macros, which conform to ANSI standard, to manage the pointer and assure that the
source code will be portable
...
The va_list type argument pointer argptr must be declared in addition to
other local variables
...
h
as a typeless or char pointer
...
The macro va_start() is then called to point the argument pointer argptr
to the first optional argument
...


Example: va_start( argptr, max );

686



CHAPTER 30



MORE ABOUT POINTERS

VARIABLE NUMBER OF ARGUMENTS (CONTINUED)

The function input()
// input
...

//
The input can be corrected with backspace
...
Pointer to the input buffer
...
Maximum number of characters to be read
/
3
...

//
This list has to end with CR = '\r'!
// Returns:
Character that breaks the input
...
h>
#include ...
)
{
int c, breakc; // Current character, character to
// break with
...

va_list argp;
// Pointer to the following arguments
...

// For special keys:
// Extended code + 256
...

do
// Compare with break characters:
if( c == (breakc = va_arg(argp,int)) )
return(breakc);
while( breakc != '\r');
va_end( argp);
if( c == '\b' && nc > 0)
// Backspace?
{
--nc, --buffer;
putch(c); putch(' '); putch(c);
}
else if( c >= 32 && c <= 255 && nc < max )
{
// Place character into the buffer
++nc, *buffer++ = c; putch(c); // and output
...

}

}

VARIABLE NUMBER OF ARGUMENTS (CONTINUED)



687

3
...
The arguments of va_arg() are the name of the
argument pointer and the type of the optional argument:

Example: arg3 = va_arg( argptr, long);
Each call to the macro va_arg() sets the argument pointer to the next optional
argument
...
It must be
identical to the type of the corresponding optional argument
...
A specific value (such as NULL, Ϫ1 or CR) can be used, or the current number of arguments can be defined by an obligatory argument
...
After evaluating the arguments the argument pointer is set to NULL by the
va_end() macro:

Example:

va_end( argptr);

Optional arguments can also be read more than once
...


ᮀ Notes on the Example Opposite
The sample function input() on the opposite page uses the getch() function to read
character input from the keyboard and store it in the buffer addressed by the first argument
...
All
other arguments are characters that can terminate keyboard input
...
Input
can be terminated by pressing the space, ESC, F1, or return keys
...
Non-printable characters are ignored unless stated as
optional arguments
...
For function keys this code is within
the range 59–68
...
A table of extended codes is available in
the Appendix
...
cpp: Demonstrates the use of an array
//
of pointers to functions
...
put(c);
}
void message_low( char *s)
{
int c;
for( ; *s != '\0';++s) c = tolower(*s), cout
...
It addresses the
machine code for the function
...

There are many uses for pointers to functions
...
Individual functions are then accessible via an index
...
This
makes sense if the function you are calling needs to work with different functions
depending on the current situation
...
qsort() uses the quick sort
algorithm to sort an array
...


ᮀ Declaring Pointers to Functions
A pointer to a function is declared as follows:

Syntax:

type (* funcptr)( parameter_list );

This defines the variable funcptr, which can store the address of a function
...
The first pair of parentheses is also
important for the declaration
...

Now let’s point funcptr to the function compare() and call compare() via the
pointer
...
1, 7
...
The declaration of
compare() is necessary to let the compiler know that compare is the name of a function
...
functab is initialized by the functions stated in its definition and thus functab[0] points to
error_message(), functab[1] to message(), etc
...


690



CHAPTER 30



MORE ABOUT POINTERS

COMPLEX DECLARATIONS

1st Example:

char (* strptr) [50]
3
...


0
...


0
...
pointer to
2
...
char
...


4
...


0
...


3
...
func is a
1
...
pointer to
3
...
pointer to
5
...


3rd Example:

char *
6
...


(* (* funcptr ) () ) []
3
...


0
...
funcptr is a
1
...
a function with return value of type
3
...
an array with elements of type
5
...
char
...


4
...
These operators
are:

Operator

Significance

[]

Array with elements of type

()

Function with return value of type

*

Pointer to

&

Reference to

A complex declaration always uses more than one of these operators
...
In a declaration, a combination of
the three operators is permissible, however, the following exceptions apply:



the elements of an array cannot be functions
a function cannot return a function or an array (but it can return a pointer to a
function or an array)
...
You can use
parentheses to redefine the order of precedence
...
Always start with the identifier being declared
...
If the parentheses/brackets () or [] are on the right, they are interpreted
...
If there is nothing or just a right bracket on the right ), the asterisk on the left is
interpreted, if it exists
...

This proceeding is demonstrated by the example opposite
...


692



CHAPTER 30



MORE ABOUT POINTERS

DEFINING TYPENAMES

1st Example:
typedef DayTime FREETIME;
FREETIME timeArr[100];

2nd Example:
typedef struct { double re, im; } COMPLEX;
COMPLEX z1, z2, *zp;

3rd Example:
typedef enum { Mo, Tu, We, Th, Fr } WORKDAY;
WORKDAY day;

4th Example:
typedef enum { Diamonds, Hearts,
Spades, Clubs } COLOR;
typedef enum { seven, eight, nine, ten ,
jack, queen, king, ace } VALUE;
typedef struct
{
COLOR f;
VALUE w;
} CARD;
typedef CARD[10] HAND;
HAND player1, player2, player3;

DEFINING TYPENAMES



693

ᮀ The typedef Keyword
C++ allows you to give types a new name using the keyword typedef
...
The statement

Example: BYTE array[100];
will then define an array array with 100 elements of the unsigned char type
...


Examples: typedef int* INTPTR;
typedef enum{ RED, AMBER, GREEN } Lights;

Here, INTPTR identifies the type “pointer to int” and Lights is an enumerated type
...
Omitting the typedef prefix will define a variable name but not a new type
name
...
They simply
introduce a new name for an existing type
...
” The declaration

Example: PTR_TO_FUNC search;
is then equivalent to
char* (*search)();

ᮀ Advantages
The major advantage of using typedef is that it improves the readability of your programs, especially when complex types are named
...
When a
program is ported to another platform, you only need to change the platform dependent
type once in the typedef definition
...
h: Representing dynamic matrices
...
Matrices are used for computing vectors needed to move, rotate, or zoom images in graphics
programming, for example
...
Additionally, it should
be possible to use the index operator to access the elements of the matrix
...
As you already
know, a matrix is a single-dimensional array whose elements are single-dimensional
arrays themselves
...
The index operator is overloaded for the Row class to allow
an exception of the out_of_range type to be thrown for invalid indices
...
mat is thus a pointer to a pointer
...
A loop is then used to allocate memory to the rows dynamically
...

The subscript operator in the Matrix class returns the line array i for a given index
i
...
Then the subscript operator of the Row class is called for the line array
...

You will be enhancing the Matrix class in the exercises to this chapter by overloading the copy constructor and the assignment, for example
...
The size of each element is specified by size
...
qsort() calls the function with two arguments
that point to the elements being compared
...
The
function must return an integer less than, equal to, or greater than zero if the
first argument is less than, equal to, or greater than the second
...
);

Refer to the Appendix “Binding C Functions
...
The function expects a variable number of unsigned int values as
arguments
...




Exercise 3
Write a C++ program that compares the speed of the quick sort and selection
sort algorithms
Sort two identical sequences of random numbers of the type int to test the
sort algorithms
...
Display the time in
seconds required for the sort operation on screen after each sort operation
...

Use the standard function qsort(), whose prototype is defined opposite, as quick sort algorithm
for this exercise
...







Add a const version of the subscript operator to the Row and Matrix
classes
...

Define a constructor for the Matrix class
...
Also write a copy constructor
...

Addition is defined for two n ϫ n matrices, A and B, which have equal numbers of rows and columns
...
, n-1

Test the Matrix with a suitable main function that calls all the methods
...




CHAPTER 30



solutions

698

MORE ABOUT POINTERS

SOLUTIONS

Exercise 1
Screen output: P WHITE E LUE K
Exercise 2
// ------------------------------------------------------// minivar
...

// The function expects a variable number of arguments
// with unsigned int types
...
h>
unsigned int min( unsigned int first,
...
cpp
// Compares the performances of sorting algorithms
//
quick sort and selection sort
// For this purpose, two identical arrays are dynamically
// generated and initialized with random numbers
...

// ------------------------------------------------------#include
#include
#include
#include
using namespace std;
void isort(int *v, int lenv);
// For qsort():
extern "C" int intcmp(const void*, const void*);
main()
{
unsigned int i, size;
int *numbers1, *numbers2;
long time1, time2;
cout <<
<<
<<
<<

"\n
The performance of the sorting algorithms"
"\n
quick sort and selection sort"
"\n
is being compared
...
\n";
srand((unsigned)time(NULL)); // Initialize the
// random number generator
...
\n";
time(&time1);
// Length of time
// for quick sort
...
\n";

699

700



CHAPTER 30

MORE ABOUT POINTERS

cout << "\nI am sorting again
...
\n"
<< "\nOutput sorted numbers? (y/n)\n\n";
char c;
if( c ==
for( i
cout

cin >> c;
'Y' || c == 'y')
= 0 ; i < size ; ++i)
<< setw(12) << numbers1[i];

cout << endl;
return 0;
}

extern "C" int intcmp( const void *a, const void *b)
{
return (*(int*)a - *(int*)b);
}
// ------------------------------------------------------// isort() sorts an array of int values
//
using the selection sort algorithm
...

minp points to the "current"
smallest array element
...


help = *a, *a = *minp, *minp = help;
}
}

// Swap
...
h : Represents dynamic matrices
// ------------------------------------------------------#ifndef _MATRIX_H_
#define _MATRIX_H_
#include
#include
using namespace std;
class Row
{
double *ro;
int size;
public:
Row( int s) { size = s; z = new double[s]; }
~Row(){ delete[]ro; }
double& operator[](int i)
{
if(i < 0 || i > size)
throw out_of_range("Row index: Out of Range\n");
return ro[i];
}
const double& operator[](int i) const
{
if(i < 0 || i > size)
throw out_of_range("Row index: Out of Range\n");
return ro[i];
}
};
class Matrix
{
private:
Row **mat;
int lines, cols;

// Pointer to array of rows
// Number of rows and columns

public:
Matrix(int ro , int co)
{
lines = ro; cols = co;
mat = new Row*[lines];
for(int i=0; i < lines; i++)
mat[i] = new Row(cols);
}
Matrix:: Matrix( int z, int s, double val);

701

702



CHAPTER 30

MORE ABOUT POINTERS

Matrix( const Matrix& );
~Matrix()
{ for(int i=0; i < lines; i++)
delete mat[i];
delete[] mat;
}
int getLines() const { return lines; }
int getCols() const { return cols; }
Row& operator[](int i)
{
if(i < 0 || i > cols)
throw out_of_range("Row index: Out of Range\n");
return *mat[i];
}
const Row& operator[](int i) const
{
if(i < 0 || i > cols)
throw out_of_range("Row index: Out of Range\n");
return *mat[i];
}
// Assignments:
Matrix& operator=( const Matrix& );
Matrix& operator+=( const Matrix& );
};
#endif
// -----------------------------------------------------// matrix
...
h"
Matrix:: Matrix( int ro, int co, double val)
{
lines = ro; cols = co;
mat = new Row*[lines];
// Array of pointers to
// arrays of rows
int i, j;
for(i=0; i < lines; i++)
// Arrays of rows:
{
mat[i] = new Row(cols);
// Allocate memory
for(j = 0; j < cols; ++j)
(*this)[i][j] = val;
// and copy values
...
lines; cols = m
...

}
}
Matrix& Matrix::operator=(const Matrix& m)
{
int i, j;
// Free "old" storage:
for(i=0; i < lines; i++)
delete mat[i];
delete[] mat;
lines = m
...
cols;

// Rows, columns

mat = new Row*[lines];

// Array of pointers
// to arrays of rows
// Array of rows:

for(i=0; i < lines; ++i)
{
mat[i] = new Row(cols);
for( j = 0; j < cols; ++j)
(*this)[i][j] = m[i][j];

// Allocate space

// and copy values
...
cols && lines == m
...
cpp : Tests dynamic matrices
// -----------------------------------------------------#include "matrix
...

int main()
{
Matrix m(4,5);
try
{
int i,j;
for( i=0; i < m
...
getCols(); j++)
m[i][j] = (double)i + j/ 100
...
" << endl;
display(cop);
cop += m;
cout << "Compute the sum:" << endl;
display(cop);
Matrix m1(4, 5, 0
...
what() << endl;
return 0;

exit(1);

}
void display( Matrix& m)
{
for(int i=0; i < m
...
getCols(); j++)
cout << m[i][j] << " ";
cout << endl;
}
cin
...
The
applications included demonstrate calculations with parity bits,
conversion of lowercase and capital letters, and converting binary
numbers
...


705

706



CHAPTER 31



MANIPULATING BITS

BITWISE OPERATORS

“True or False” table for bitwise operators

Bitwise AND

Result

Bitwise inclusive OR

Result

0 & 0

0

0 | 0

0

0 & 1

0

0 | 1

1

1 & 0

0

1 | 0

1

1 & 1

1

1 | 1

1

0 ˆ 0

0

~0

1

0 ˆ 1

1

~1

0

1 ˆ 0

1

1 ˆ 1

0

Examples
unsigned int a, b, c;

Bit pattern

a = 5;

0 0
...
0 1 1 0 0

c = a & b;

0 0
...
0 1 1 0 1

c = a ˆ b;

0 0
...
1 1 0 1 0

BITWISE OPERATORS



707

ᮀ Bit Coding Data
In cases where conservative use of memory is imperative, data often need to be bit coded,
a technique to represent information as individual bits
...

To access bit coded data, you need to be able to read or modify individual bits
...
Operands belonging to float
or double types are invalid
...
If a bit is set, that is, if it has a value of 1, it will be interpreted as
true
...
Examples for each bitwise operator follow
...
If, for example, both operands are int types, the result will also be of an int type
...
If one operand type is an int and the other a long, the int value
will be converted to long before the operation is performed
...
The latter do not affect individual bits but interpret the whole value of
their operands as boolean, returning a boolean value
...

The precedence of the bitwise NOT operator ∼ is high, since ∼ is a unary operator
...
However, their precedence is higher than that of the logical
operators && and ||
...
0 0 0 0 1 1 0 0

b = a << 3;

0 0
...
0 0 0 0 0 0 1 1

Using shift operators
// getbin_t
...
0101
...

// -------------------------------------------------#include
using namespace std;
unsigned int getbin()
{
char c;
unsigned int val = 0;
while ( (c = cin
...
get();
}
return val;
}

BITWISE SHIFT OPERATORS



709

ᮀ Left and Right Shift
The shift operators << and >> shift the bit pattern of their left operand a certain number
of bit positions
...
The examples
opposite illustrate this point
...
The bits dropped on the left are lost
...
In all other cases, the compiler determines
whether to pad an expression with 0 bits (logical shift) or with the sign bit (arithmetic
shift), although an arithmetic shift normally occurs
...


ᮀ Integral Promotion
Integral promotion is performed for the operands of a shift operator, that is char is
extended to int
...

The result of a shift operation is unpredictable if the value of the right operand is negative or larger than the length of the left operand expressed in bits
...
Shifting a number n places left (or right) is equivalent to a multiplication (or division) by 2n
...
A so-called mask is used
to determine which bits to delete
...
This means that all the bits in c, with the exception of the least significant bits,
are deleted
...

The variable c can be of any integral type
...


ᮀ Setting and Inverting Bits
You can use the bitwise OR operator | to set specific bits
...
In ASCII code, the only difference
between a lowercase and an uppercase letter is the fifth bit
...
Each
0-bit is set to 1 and each 1-bit is deleted if the corresponding bit in the mask has a
value of 1
...
Every second bit in the least significant eight
bits of c is therefore inverted
...

The following overview demonstrates the effect of a statement for an integral expression x and any given mask, MASK:




x & MASK
x | MASK
x ^ MASK

deletes all bits that have a value of 0 in MASK
sets all bits that have a value of 1 in MASK
inverts all bits that have a value of 0 in MASK
...


712



CHAPTER 31



MANIPULATING BITS

USING BIT MASKS

Computing the parity of an integer
// parity_t
...

// Returns:
0, if the number of 1-bits is even,
//
1 in all other cases
...


Example: x = x & ∼3;
In the bit pattern of 3, only the bits at positions 0 and 1 are set
...
The above
expression would thus delete the two least significant bits in x
...

The next example shows masks that address exactly one bit in a word
...


Examples: x = x | (1 << 6);
x = x & ∼(1 << 6);
The first expression sets the sixth bit in x
...

Of course, you can also use masks such as (1 << n) where n is a variable containing
the bit position
...


Examples: x >>= 1;
x ^= 1;

Both statements are equivalent to
x = x >> 1;
x = x ^ 1

The function parity() shown opposite includes compound assignments with bitwise
operators
...


714



CHAPTER 31



MANIPULATING BITS

BIT-FIELDS

Header of ATM cells

Byte
1

General Flow
Control

Virtual Path
Identifier

2

Virtual Path
Identifier

Virtual Channel
Identifier

3

4

5

Virtual Channel
Identifier
Virtual Channel
Identifier

Payload
Type

CLP

Header Error
Control

General Flow Control
Virtual Path/Channel Identifier
Payload Type

Controls the data stream
Address of the virtual path/channel
Distinguish between payload and control
data
Mark cells with high priority
Check sum for header

CLP (Cell Loss Priority)
Header Error Control

Representing an ATM cell
struct ATM_Cell
{
unsigned GFC : 4;
unsigned VPI : 8;
unsigned VCI : 16;
unsigned PT : 3;
unsigned CLP : 1
unsigned HEC : 8;
char payload[48];
};

//
//
//
//
//
//
//

General Flow Control
Virtual Path Identifier
Virtual Channel Identifier
Payload Type
Cell Loss Priority
Header Error Control
Payload

BIT-FIELDS



715

C++ lets you divide a computer word into bit-fields and give the bit-fields a name
...


ᮀ Defining Bit-Fields
Bit-fields are defined as data members of a class
...
The width is defined as the number of bits the bit-field
occupies in a computer word and is separated from the bit-field name by a colon
...
bit0_4 designates the 5 least significant bits in a computer word
and can store values in the range 0 to 31
...
The member word
...

You cannot reference nameless bit-fields
...

The width of a bit-field cannot be greater than that of the computer word
...
If a bit-field will not fit in a
computer word, the following bit-field is also positioned on the next word boundary
...
You cannot create arrays of bitfields
...

the order bit-fields are positioned in depends on the machine being used
...
This is true of DEC
Alpha workstations, for example
...
Cells are used for data
transportation in ATM (Asynchronous Transfer Mode) networks
...
The header shown here is used to connect a computer to the network in the
User Network Interface
...

1st Number
2nd Number
The
The
The
The
The

bit
bit
bit
bit
bit

--> 57
--> -3

pattern
pattern
pattern
pattern
pattern

of
of
of
of
of

57 = x :
-3 = y :
x & y :
x | y :
x ^ y :

0000
1111
0000
1111
1111

0000
1111
0000
1111
1111

0011
1111
0011
1111
1100

1001
1101
1001
1101
0100

How many bit positions is x to be shifted?
Count --> 4
The bit pattern of x << 4 : 0000 0011 1001 0000
The bit pattern of x >> 4 : 0000 0000 0000 0011
Repeat (y/n)?

EXERCISES



717

Exercise 1
a
...
Only the 16 least significant bits are to be
output no matter what the size of the computer word
...

b
...
First
read two decimal integers from the keyboard and store them in the variables x and y
...

To demonstrate the shift operators, shift the value of x a given number of
bit positions right and left
...
Use the value 1 in case of invalid input
...


Exercise 2
Your task is to encrypt data to prevent spying during data communications
...

a
...
The
int value and the positions of the bits to be swapped are passed as arguments to the function
...
If one of
the positions passed to the function is invalid, the int value should be
returned unchanged
...
Write a filter that swaps the bits at bit positions 5 and 6, 0 and 4, and 1
and 3 in all characters except control characters (defined as ASCII Code
>= 32)
...
The output must comprise the original unencrypted
data
...
cpp
// Demonstrates bitwise operators
...
\n\n"
<< "1st number --> ";
cin >> x;
cout << "2nd number --> ";
cin >> y;
cout << "\nThe bit pattern of "
<< setw(6) << x << " = x :
putbits(x);

";

cout << "\nThe bit pattern of "
<< setw(6) << y << " = y :
putbits(y);

";

cout << "\nThe bit pattern of
putbits(x&y);

x & y

:

";

cout << "\nThe bit pattern of
putbits(x|y);

x | y

:

";

cout << "\nThe bit pattern of
putbits(x^y);

x ^ y

:

";

cout << "\n\nHow many bit positions"
" is x to be shifted?"
<< "\nNumber --> ";
cin >> count;

SOLUTIONS



if( count < 0 || count > 15)
{
cout << "Invalid input!"
<< " Shifting by one bit position
...

void putbits( unsigned int n )
{
int i;
for( i = 15; i >= 0 ; --i)
{
cout << (char)( ((n>>i) & 1) + '0');
// i-th bit
if( i % 4 == 0 && i > 0)
// and after 4 bits
cout << ' ';
// one blank
...
cpp: Filter to encrypt data
...

//
Modules: hide_t
...
cpp
//
// Call:
hide_t [ < sourcefile ] [ > destfile ]
// -------------------------------------------------------

719

720



CHAPTER 31

MANIPULATING BITS

#include
using namespace std;
int swapbits( int ch, int bitnr1, int bitnr2); // Prototype
int main()
{
int c;
while( (c = cin
...
cpp: The function swapbits() swaps two bits
within an integer
...

Returns:
The new value
...

int newx, mask1, mask2;
int msb = 8 * sizeof(int) - 1; // Highest bit position
if( bitnr1 < 0 || bitnr1 > msb ||
bitnr2 < 0 || bitnr2 > msb)
return x;
// Return, if bit position is invalid
mask1 = (1 << bitnr1);
mask2 = (1 << bitnr2);

// Shift 1 to position bitnr1
// Shift 1 to position bitnr2

newx = x & ~(mask1 | mask2);

// Delete both bits

if( x & mask1 )
if( x & mask2 )

// Swap bits
...
Thus, templates are a powerful tool
for automating program code generation
...
In addition, special options, such as default arguments,
specialization, and explicit instantiation are discussed
...

A class used to represent an array of int values is very similar to a class representing
an array of double values, for example
...
Operations performed with elements, such as search
and sort algorithms, must be defined separately for each type
...


A class template can provide a generic definition that can be used to represent various
types of arrays, for example
...


ᮀ Advantages of Templates
Templates are powerful programming tools
...
Individual functions or classes are automatically generated when needed
...

Errors caused by multiple encoding are avoided
...
The classes string,
istream, ostream, iostream, and so on are instantiations for the char type
...
The various algorithms are implemented as global function templates and can be used for any set of objects
...
h : The class template Stack with
//
methods push() and pop()
...
Although you
must state the class keyword, T can be any given type, such as an int or double
...
The parameter T represents the type
of variables, which are to interchange
...


ᮀ Defining Class Templates
Example: template
class Demo
{
U elem;
};


...


This defines the class template Demo
...
You simply need to state the name of the template, Demo,
within the class scope
...
Each
method in a class template is thus a function template
...
The method name is prefixed by the
class template type and the scope resolution operator
...

A stack is managed according to the last-in-first-out principle, lifo-principle for short; the
last element to be “pushed” onto the stack is the first to be removed, or “popped,” from
the stack
...
This
ensures that the definition will be visible to the compiler, since it requires the definition
to generate machine code for concrete template arguments
...
cpp: Testing a stack
// ---------------------------------------------------#include
#include
using namespace std;
#include "stack
...


void fill( USTACK& stk );
void clear( USTACK& stk );
int main()
{
USTACK ustk(256);
// Create and fill
fill( ustk);
// the original stack
...

cout << "The copy: " << endl;
clear( ostk);
// Output and clear the copy
...

return 0;
}
void fill( USTACK& stk )
{
unsigned x;
cout << "Enter positive integers (quit with 0):\n";
while( cin >> x && x != 0 )
if( !stk
...
empty())
cerr << "Stack is empty!" << endl;
else
{
unsigned x;
while( stk
...
The machine code
for functions or methods is not generated until instantiation
...
The compiler determines the
parameter type of T by the function arguments
...
The template functions can be called after this step
...
Given
that x and y are two double variables, the following statement

Example: exchange( x, y );
creates a second template function for the double type
...


Example: Stack istack(256);

// implicit

This statement first creates the template class Stack, generating the machine
code of all methods for the int type
...

If a further template class, such as Stack is created, the machine code generated for the methods in this template class will be different from the machine code of
the Stack methods
...
However, it does spare the programmer’s extra work required to
develop multiple versions of functions and classes
...
The first check recognizes errors
that are independent of the template parameters
...


728



CHAPTER 32



TEMPLATES

TEMPLATE PARAMETERS

The Stack template with two template parameters
// stackn
...


};

which has two parameters U and V
...

A template parameter need not always be a type name
...


Example: template
class Stack{
...

The example on the opposite page uses the parameter n to specify the size of an array
used to represent a stack
...
Objects can then be
created without allocating dynamic storage
...
The copy constructor, the assignment operator, and the destructor no longer need to be defined!

ᮀ Restrictions
Two restrictions apply to template parameters other than type parameters:



they cannot be modified
they cannot be floating-point types
...
};

pointers and references to floating-point types are:

Example: template
class Demo {
...
cpp: Passing arguments to
//
function templates
// ---------------------------------------------#include
using namespace std;
template
T min( T x, T y)
{
return( (x < y) ? x : y);
}
int main()
{
short x = 10, y = 2;
cout << "x = " << x << " y = " << y << endl;
cout << "The smaller value is: "
<< min(x, y) << endl;
// Call is ok
...
2;
float z2 = 1
...
1;
cout << "\nz1 = " << z1
<< " z3 = " << z3 << endl;
cout << "The smaller value is: "
<< min(z1, z3) << endl;
// Call is ok
...
The argument types
must exactly match to the types of the template parameters
...
In the
case of the template function min() this means that both arguments must be of the
same type
...
1; double y = 7
...


Example: int cnt = 256;

// Error:
typedef Stack ShortStack;

Since only an int constant is permitted as a template argument, this statement provokes
an error
...


Example: template class Demo{
...

The definition of a function template and a function with the same name, which can be
generated by the function template, causes the compiler to output an error message (ex
...

That is why the ANSI standard provides its own syntax for defining specializations:
#include
template<>
const char* min( const char* s1, const char* s2 )
{
return( (strcmp(s1, s2) < 0 ) ? s1: s2 );
}

SPECIALIZATION



733

ᮀ Motivation
A template function can only be instantiated if all the statements contained in the function can be executed
...

More specifically, all operators used in a template function must be defined for the
current argument type
...

Besides non-executable instructions there are other reasons to prevent a function
template being instantiated for a particular type:



the generic approach defined by the template does not return any useful results
for a given type
there are more efficient approaches for some types
...


ᮀ Defining Specialization
In cases like this, it makes sense to specialize the template function definition
...
This
technique is demonstrated on the opposite page using the function template min(),
where a specialization has been defined for the char* type, both for older and more
modern compilers that support the current ANSI standard
...
The order the compiler looks up a function
guarantees that if both a function template and a specialization are defined for a specific
type, the specialization will be called
...
More specifically, a template class can only be created if all the methods in the
appropriate function template can be instantiated without error
...
h: Defines the template QuadMatrix
//
to represent quadratic matrices
// ----------------------------------------------------#include
#include
using namespace std;
template
class QuadMatrix
{
private:
T mat[cnt][cnt];
public:
int dim() const{ return cnt; }
T* operator[](int line) throw(out_of_range)
{
if( line < 0 || line >= cnt)
throw out_of_range("Matrix: Index out of range");
else
return mat[line];
}
const T*

operator[](int line) const
throw(out_of_range)

{
if( line < 0 || line >= cnt)
throw out_of_range("Matrix: Index out of range");
else
return mat[line];
}
friend QuadMatrix& operator+(const QuadMatrix&,
const QuadMatrix&);
// etc
...
If an argument required to instantiate a template is missing, the default value is then
used
...


ᮀ The Class Template QuadMatrix
The class template defined opposite, QuadMatrix, represents quadratic matrices
...
If the line index i is outside of the valid range, a standard
out_of_range type exception is thrown
...

QuadMatrix is merely the name of a template
...


ᮀ Rules
The same rules apply to the default arguments of templates as to the default arguments of
functions:



if you declare a default argument for at least one parameter, you must define
default values for all the remaining parameters
if a template argument for which a default argument was declared is omitted during instantiation, all the remaining template arguments must be omitted
...
cpp: Tests explicit instantiation
// ----------------------------------------------------#include
#include
using namespace std;
#include "quadMat
...
dim(); k++)
{
for( int l = 0; l < m
...
what() << endl;
}
return 0;
}

EXPLICIT INSTANTIATION



737

In addition to implicit instantiation of templates, which occurs when a template function is called, for example, explicit instantiation is also possible
...


ᮀ Syntax
Explicit instantiation can be achieved by the following

Syntax:

template declaration;

where declaration contains the name of the template and the template arguments
...

Function templates can also be instantiated explicitly
...


ᮀ ANSI Instantiation
The ANSI standard provides an additional technique for the explicit instantiation of
function templates
...


Example: min(x, y);
In this case, a template function min() for the long type is generated
...

Explicit instantiation of function templates extends their possible usage:




function templates can be parameterized by types that cannot be derived from the
function arguments—more specifically, function templates can be defined without function parameters
function templates can be defined with function parameters that are not template
parameters themselves
...

The given value is compared with the array element at the position where the
value is “expected” to be
...
If the
required value is lesser than that of the array element found at the expected
position, the search is continued in the left part of the subarray, just like a binary
search
...

The “expected” position exp in an array v can be calculated as follows: If key
is the required value, begin is the lowest, and end is the highest index of the
corresponding subarray, the following applies:
double temp = (double)(key-vp[begin]);
temp /= (vp[end]-vp[begin]);
temp = temp * (end - begin) + 0
...
As long as a greater array element can be found
starting from the end of the left subarray, the element is shifted up by one
position
...




NOTE
The left, sorted part originally consists of only one element, the first array
element
...
The array elements are of the same type
as the template parameter T
...

The function template returns the index of the first element in the array
that corresponds to the searched for value, or –1 if the value cannot be
found in the array
...
Use the technique described opposite
as your algorithm for the interpolation search
...
h
...
The array elements are of the type of the template parameter T
...
There is no return value
...

The function template has two parameters—a pointer to the first array
element and the number of array elements
...

■ Use the function templates interpolSearch(), insertionSort(), and
display() to define template functions for double and short types
...

Write a main function that creates and calls each template function
insertionSort() for the int and double types
...

Add a call to each template function search() in your main function
...


740



CHAPTER 32

TEMPLATES

Exercises
The class FloatArr (as defined in Chap
...
1)
class FloatArr
{
private:
float* arrPtr;
int max;
int cnt;

// Without conversion functions

//
//
//
//

Dynamic member
Maximum number, without having
to reallocate storage
...


public:
FloatArr( int n = 256 );
FloatArr( int n, float val);
FloatArr(const FloatArr& src);
~FloatArr();
FloatArr& operator=( const FloatArr& );
int length() const { return cnt; }
float& operator[](int i) throw(BadIndex);
float operator[](int i) const throw(BadIndex);
void append( float val);
void append( const FloatArr& v);
FloatArr& operator+=( float val)
{
append( val);
return *this;
}
FloatArr& operator+=( const FloatArr& v)
{
append(v);
return *this;
}
void insert( float val, int pos) throw(BadIndex);
void insert( const FloatArr& v, int pos )
throw(BadIndex);
void remove(int pos) throw(BadIndex);
friend ostream& operator<<( ostream& os,
const FloatArr& v);
};

EXERCISES



741

Exercise 2
Define a class template Array to represent an array with a maximum of
n elements of type T
...
If there is no space left to insert an element in the array, an
exception of the OutOfRange type should be thrown
...
Use
the error class BadIndex, which was defined in Exercise 1 of Chapter 28
...

Use 255 as the default value for the parameter n of the class template
...
Now define a default constructor and a constructor that initializes a given number of array elements with a given value
...

As access methods define the size() and the length() methods, the
size() method returns the maximum number of array elements, that
is, n; the length() method returns the current number of elements in
the array
...
The methods have a void return type and
can throw exceptions of type BadIndex and/or OutOfRange
...
The subscript
operator throws BadIndex type exceptions
...

Define arrays of the appropriate types, then insert and delete elements in
the arrays
...

Modify the test program by adding an array for objects of a class type
...

Test the array template by defining an array with 5 DayTime class objects
and inserting a few objects
...




CHAPTER 32



solutions

742

TEMPLATES

SOLUTIONS

Exercise 1
// -----------------------------------------------------// interpol
...

temp = (double)(key - vp[begin])
/ (vp[end]-vp[begin]);
temp = temp * (end - begin) +0
...

int j;
// Shift greater elements up:
for( j = i-1; j >= 0 && vp[j] > temp; j--)
vp[j+1] = vp[j];
vp[j+1] = temp;
// Insert
...
get();
}
// Two arrays for testing:
short sv[5] = { 7, 9, 2, 4, 1};
double dv[5] = { 5
...
5, 2
...
4, 4
...
sync();
int pos = interpolSearch(key, sv, 5);
if( pos != -1)
cout << "\nfound!" << endl, cin
...
get();
// ------------------------------------------------cout << "\nInstantiation for type double: " << endl;
display(dv, 5);
insertionSort(dv, 5);
cout << "\nAfter sorting: ";
display(dv, 5);
double dkey;
cout << "\nArray element? "; cin >> dkey; cin
...
get();
else
cout << "\nnot found!" << endl, cin
...
h
// Use of class templates to represent arrays
...
cnt > n)
// Not enough space
...
cnt;
for( int i=0; i < count; ++i)
arr[cnt++] = v
...

if( n < cnt + v
...
cnt] = arr[i];

// Shift up
// starting at pos
...
cnt; ++i)
arr[i+pos] = v
...
cnt;

// Fill the gap
...
width();
// Save the field width
for( int i = 0; i < v
...
width(w);
os << v
...
h
Class DayTime with relational operators,
the operators ++ and -- (prefix and postfix),
and the operators << and >> for I/O
...


//
//
//
//

-----------------------------------------------------Array_t
...

------------------------------------------------------

#include "array
...
h"
#include
#include
#include
using namespace std;
typedef Array
typedef Array

IntArr;
DoubleArr;

typedef Array DayTimeArr;
int main()
{
try
{
const DoubleArr vd(10, 9
...
remove(3);
kd
...
0);
kd
...
0);

//
//
//
//

Delete the element at
position 3
...

And repeat!

cout << "\nThis is the modified array: "
<< endl;
cout << setw(8) << kd;

747

748



CHAPTER 32

TEMPLATES

IntArr vi;
int i;
for(i=0; i < 10; i++)
vi
...


for(i=0; i < 3; i++)
{
if( !(cin >> temp))
break;
vt
...
getBadIndex()
<< " invalid";
exit(1);
}
catch(OutOfRange& )
{
cerr << "\nArray is full!";
exit(2);
}
return 0;
}

chapter

33

Containers
This chapter describes standard class templates used to represent
containers for more efficient management of object collections
...


Besides discussing how to manage containers, we will also be looking at
sample applications, such as bitmaps for raster images, and routing
techniques
...

Arrays

Stacks

Queues
etc
...
These operations include object insertion, deletion, and
retrieval
...
Containers thus
provide a safe and easy way to manage collections of objects
...
These classes can be categorized as follows:



sequential containers, or sequences, where the objects are arranged sequentially
and access to an object can either be direct or sequential
associative containers, where the objects are generally organized and managed in
a tree structure and can be referenced using keys
...
Restricted operations, such as appending at the end of a container, have constant runtimes
...

The following are sequential containers:




arrays, which provide the same operations as C arrays but increase and decrease
in size dynamically, in contrast to C arrays
queues, which are managed on the FIFO (First In First Out) principle
...
The last
element to be inserted is removed first
...

There are also so-called bitsets, which represent bit sequences of a given length and
provide bitwise operators, with which bits can be manipulated
...

At the beginning or in the
middle: linear
...


deque= allocator >

At the beginning or end:
constant
...
These
are class templates parameterized by the type T of the objects to be managed
...







The container class vector supports standard array operations, such as direct access to individual objects via the subscript operator [],
and quick appending and deletion at the end of the container
...

The container class list provides functionality that is typical for double linked lists
...
General list operations, such as sorting and merging, are also defined
...
The same operations in the middle of a container have a linear runtime
...
The
storage management is represented by a so-called allocator class, which is parameterized
by an object of type T
...
The
default value of the template parameter is the standard allocator class allocator
that uses the new and delete operators to allocate and release memory
...
An adapter class
expects a sequence as a template argument and stores the sequence in a protected
data member
...
The priority_queue template
represents priority queues
...
The default value of the template
parameter is the predefined comparator class, less, which uses the lesser than operator < for type T
...

// --------------------------------------------------#include
#include
using namespace std;
typedef list INTLIST;
// int list
int display(const INTLIST& c)
{
int z = 0;
list::const_iterator pos;

// Counter
// Iterator

for( pos = c
...
end(); pos++, z++)
cout << *pos << endl;
cout << endl;
return z;
}

Iterating vectors
// iterat_t
...

// --------------------------------------------------#include
#include
using namespace std;
#include "account
...
begin(); pos < v
...
To allow
you to work with the objects in a container, the positions of the objects in the container
must be accessible
...


This situation should be familiar from your experience of working with pointers
...

Iterators were introduced in C++ to provide a uniform model for positioning and iteration in containers
...


ᮀ Iterator Types
Two types of iterators are important in this context:




bidirectional iterators, which can be shifted up by the increment operator ++
and down with the decrement operator --, and use the operators * and -> to
provide write or read access to objects
random access iterators, which are bidirectional iterators that can additionally
perform random positioning
...


The container classes vector and deque have random access iterators and the
container class list has bidirectional iterators
...
An iterator belonging to one of these classes can reference constant or
non-constant objects
...
The begin() method accesses
the first position and end() accesses the position after the last container object
...
You cannot use iterators to walk through them
...
h: The Class Template SortVec representing
//
a sorted vector
...
cpp :
Tests the template SortVec
...
h"
typedef SortVec IntSortVec;
int main()
{
IntSortVec v, w;

// Default constructor

v
...
insert(7); v
...
search(7);
w
...
insert(9);
v
...
Their functionality is similar for the
various classes and is discussed in the following section using the vector class as an
example
...
You can then insert
individual objects into the container
...


Example: Fraction x(1, 1);
vector cont(100, x);

This defines the container cont with 100 Fraction type objects, and fills it with the
object x
...

Finally, you can initialize a container with a part of another container
...


Example: vector v(first,last);
The arguments first and last are iterators in an existing container
...


ᮀ Constructors for Adapter Classes
Only a default constructor and the copy constructor are defined for adapter classes
...

The opposite page shows the derived container class sortVec, which is used to represent sorted, dynamic arrays
...

The second template parameter is a comparator class, which represents a comparison criterion for sorting
...


void push_front(const T&x);

Adds x before the first
element of the sequence
...


size_type insert(iterator pos, Inserts n copies of x after
size_type n, const T& x) position pos and returns the
number of inserted elements
...


Method insert() of the derived container class SortVec
// Method insert() adds a new object at the end
// of the vector and reorganizes in ascending order
...

pos = end();

pos--;

// Last position

while (pos-- > begin())
// Sort:
{
if( obj < *pos)
// Swap:
{ temp = pos; *(++temp) = *pos; *pos = obj; }
else
break;
}
}

INSERTING IN SEQUENCES



759

ᮀ Insertion Methods
The following methods are defined in the container classes vector, deque, and list



push_back()
insert()

insert at end
insert after a given position
...


This method is not defined in the vector class
...
Given
two containers v and w the following

Example: w
...
begin(), v
...
end());
inserts the objects from container v in front of all the other objects in w
...
The assignment operator is
overloaded for containers to allow this operation
...
Insertion of one object with the insert() method also has a constant runtime in the list class
...

This dissimilar runtime behavior for methods can be ascribed to the implementation
of various container classes
...
This allows for extremely quick inserting at a given position
...
Inserting in the
middle means shifting the objects in the container to make place for the new object
...


ᮀ Insertion in Adapter Classes
There is only one insertion method for adapter classes: push()
...
Insertion of objects into priority
queues depends on the priority of the object and the runtime is linear
...
h
// Method search() seeks an object obj in the vector
// using the binary search algorithms:
// The object obj is first compared to the element in
// the middle of the vector
...
We repeat this
// process comparing obj with the "middle" element in
// the section where it is known to be, repeatedly
// halving the size of the interval until the interval
// consists of a single point, which is where obj
// belongs
...

// ---------------------------------------------------template
int SortVec::search(const T& obj)
{
int first = 0, last = end() - begin() - 1, mid;
while( first < last )
{
mid = (first + last + 1)/ 2;
// Search the left half,
if( obj < (*this)[mid] )
last = mid - 1;
else first = mid;
// the right half
...

// Not found
...


Both methods return a reference to the object in question
...
front();
v
...
9;

This saves the first object in container v in the variable z and then overwrites the object
by 1
...


ᮀ Access via Indices
The subscript operator [] is overloaded in the vector and deque classes to permit the
use of indices for access to the objects in a container
...


Example: v[20] = 11
...

When you use the subscript operator, you must ensure that the index does not exceed
the valid range
...


Example: v
...
2;
The at() method throws an exception of the standard error class out_of_range if an
error occurs
...

Before you can manipulate the tenth object in the container, for example, you need to
walk through the container sequentially up to that position
...

The queue class comprises the front() method, which is used to access the first
element
...
h: Method merge() merges the argument vector
//
with the vector *this
...
size())
if( pos[n1] <= v[n2] )
temp
...
push_back(v[n2++]);
// Append the rest:
while( n1 < size())
temp
...
size())
temp
...


The length of a container changes after every insertion or deletion—the capacity does
not
...
The method
returns an integer of the size_type type
...
size();

The variable sz contains the value 100 in this case
...
You can also use the empty() method
to discover whether a container is empty
...


Example: while( !cont
...

The methods size() and empty() are defined for all container classes
...


Example: cont
...
If n == size(), nothing happens
...
The second argument, x, can be omitted
...


ᮀ Capacity
The capacity of a container can be checked using the max_size() method
...
max_size();
The return value depends on the amount of memory available and the object size
...
You cannot
discover the capacity of an object, nor can you call resize() to change its length
...
cpp : Testing a priority queue
// ------------------------------------------------#include
#include
#include
using namespace std;
class Parcel
{
private:
unsigned int prio;
// Priority
string info;
public:
Parcel(unsigned int p, const string& s)
:prio(p), info(s) {}
// Access methods,
...
prio < y
...
prio << " "<< x
...
push(Parcel(7,"Bob"));
pq
...
push(Parcel(4,"Susan"));

// Insert

while( !pq
...
top() << endl; // Output
pq
...


The following method is additionally defined in the deque and list classes:


pop_front() deletes the first object in the container
...

The pop_back() and pop_front() methods are preferable on account of their
constant runtimes
...
However, the runtime is linear in the vector and deque classes, since objects
must be shifted within the container to fill the gap left by the deletion
...


Example: cont
...
begin() + 10, cont
...
The
erase() method returns the new position of the object immediately after the range of
objects deleted
...
Given that
wait is a queue of the queue type, the following statement

Example: wait
...
In the case of a stack, pop() deletes
the element at the top of the stack, and for priority queues, the object with the highest
priority
...


766



CHAPTER 33



CONTAINERS

LIST OPERATIONS

Sample program
// list_t
...
push_back( rand()%10 );

// ex
...
push_back(ls
...
reverse();

// 1 4 7 1

ls
...
push_back( rand()%10 );

// ex
...
end();
ls
...
begin());

// 1 1 4 0 7

display(sls);

// 9 4

ls
...
sort();
ls
...
unique();

//
//
//
//

return 0;
}

0
4
0
0

1 1 4 7
9
1 1 4 4 7 9
1 4 7 9

LIST OPERATIONS



767

The container class list comprises methods for list operations that are not defined in
other container classes
...


ᮀ Sorting, Inverting, and Splicing Lists
A container of the list type, or list container for short, can be sorted by a call to
sort()
...
A call to sort() sorts
the container in ascending order
...
What was originally the first element in the container becomes the last, and the second element becomes the second to last, and so on
...
Given that ls1 and ls2
are two sorted list containers, the following call

Example: ls1
...

The ls2 container is empty following this operation
...
You can transfer either a
whole container or just part of a container
...
splice(pos, ls2);
This inserts the whole of container ls2 in front of position pos in ls1
...
The following statement

Example: ls1
...
If you want to transfer part of a container, the third and fourth
arguments must contain the starting and end position
...


768



CHAPTER 33



CONTAINERS

ASSOCIATIVE CONTAINERS

Container classes

Container Class

Representing

set< class T,
class Compare = less,
class Allocator = allocator >

collections of objects with

multiset< class T,
class Compare = less,
class Allocator = allocator >

collections of objects with

unique keys

equivalent keys, i
...

possibly multiple copies of
the same key value

map< class Key, class T,
class Compare = less,
class Allocator = allocator >

collections of objects/key

multimap< class Key, class T,
class Compare = less,
class Allocator = allocator >

collections of objects/key

pairs where the keys are
unique

pairs with possibly
equivalent keys

Associative containers and header files

Container Class

Header File



set< T, Compare, Allocator >
>



map< Key, T, Compare, Allocator >



multimap< Key, T, Compare, Allocator >



multiset
ASSOCIATIVE CONTAINERS



769

Sequences store objects in linear order
...
If you have only a few objects to deal with, this will not cause any significant delay
...


ᮀ Representing Sets and Maps
Associative containers with different classes that represent sets and maps allow you optimize runtimes
...
Operations are performed by sortable keys
...

Insertion, deletion, and search operations in sets and maps can be performed with logarithmic runtimes
...
Since a logarithmic function grows very slowly, response
will be phenomenally quick
...
This is why we refer to embedded keys
...
Besides sets, which have
unique keys, you can also define multisets, where multiple objects can have the same key
...
In other words, the key is not embedded in
the object but stored separately from it
...
The relationship between the objects is again defined by the keys
...


ᮀ Associative Container Classes
The opposite page shows various classes used to represent sets, multisets, maps, and multimaps
...
Both parameters have default values, which we already saw in the context
of sequences
...
They return the position of the first element or the position
after the last element
...
cpp: Tests sets and multisets
// ---------------------------------------------------#include
#include
#include
#include
using namespace std;
typedef set IntSet;
typedef IntSet::iterator SetIter;

// Define type and
// iterator type

typedef multiset IntMultiSet;
// Multiset and
typedef IntMultiSet::iterator MultiSetIter; // iterator
int main()
{
IntSet lotto;
SetIter pos;

// Create a set
...
size() < 6)
// Insert
lotto
...
begin(); pos != lotto
...

MultiSetIter mpos;
// Bidirectional iterator
for( int i=0; i < 10; i++) // Insert
ms
...
begin(); mpos != ms
...
Keys are always parts of objects, thus, keys are data members whose relationships to one another must be defined in the corresponding class
...


ᮀ Declaring Sets and Multisets
The container classes set and multiset have two constructors each for creating containers
...
The second constructor inserts objects from a range of iterators into the new set or
multiset
...

The copy constructor is also defined, and this allows you to use an existing container
of the same type to initialize a new container
...
This allows for insertion of individual
objects or multiple objects from a given range of iterators
...
insert(Account(1234,"May, Tom",100));
In contrast to multisets, a new object is only inserted in a set if it does not already exist
in the container
...
To do so, you can either specify
the object itself or its position in the container
...
erase(mySet
...

You can delete all objects in a container with the following statement:

Example: mySet
...
begin(), mySet
...
Calling empty()
will tell you whether the container is empty
...


772



CHAPTER 33



CONTAINERS

MAPS AND MULTIMAPS

Using multimaps
// mulmap_t
...
insert(pairm
...
insert(pairm
...

// Iterator
...
begin(); pos!= m
...
find(3);

// Search for the pair
// with the given key 3
if( pos != m
...
count(key)
<< " pairs with key " << key << endl;
return 0;
}

MAPS AND MULTIMAPS



773

ᮀ Representing Pairs of Keys/Objects
Maps and multimaps store pairs of sorted keys and objects
...
The comparison criterion is
applied to the keys
...
The first template parameter, Key, is the key type
and the second is the object type T
...

Given that pos is the position of an object in a map or multimap, you can reference
the key with pos->first, and the associated object itself with pos->second
...
Thus, you can create a container with a length
of 0, or use the objects in an existing container to initialize a new container
...

The methods insert() for insertion, and erase() and clear() for deletion have
the same interfaces as in the container classes set and multiset
...

The find() method is used to look up key/object pairs and expects a key as an argument in the map and multimap classes
...
In the case of multimaps where several objects can have the same key, it
returns the first position with that key
...

You can use the count() method to discover the number of key/object pairs with a
given key in the container
...
The method
returns 0 or 1 for maps, depending on whether a pair exists or not
...


774



CHAPTER 33



CONTAINERS

BITSETS

Representing raster images with bitmaps
// bitmap
...

// ------------------------------------------------#ifndef _BITMAP_
#define _BITMAP_
#include
#include
using namespace std;
template
class Bitmap : public bitset
{
private:
int lines, cols; // Number of rows and columns
int ax, ay;
// Current cursor position
int ai;
// Current index in the bitset
public:
Bitmap(int l, int c);
void move(int x, int y);
void draw(int x, int y);
};
template
Bitmap::Bitmap(int l, int c)
{
if (l*c <= N)
{
reset();
// Set all bits to 0
lines = l; cols = c;
// Rows and columns
ax = 0; ay = 0; ai = 0;
// Current position
}
else throw invalid_argument("Invalid argument \n");
}
template
void Bitmap::move(int x, int y)
{
if( x >= 0 && x < lines && y >= 0 && y < cols)
{
ax = x; ay = y;
ai = x * cols + y; }
else throw invalid_argument("Invalid argument\n");
}
// to be continued

BITSETS



775

ᮀ Declaring Bitsets
A bitset stores a bit sequence of a given length
...

The container class bitset provides the functionality needed to manage bitsets
...

You can use the default constructor to create a bitset with no initial values
...
The bit-pattern is either defined
as an unsigned long value or as a string
...
The last character in the string
will be the first bit value (that is 0 or 1) at bit position 0, the second to last character in
the string is the bit value at position 1, and so on
...
This also applies when an unsigned long value is used for initialization purposes
...
A pixel (picture element) is represented by a bit in a
bitset
...

The number of pixels that can be represented horizontally and vertically is defined by
the resolution
...
The value of N is the
product of the number of pixels in horizontal and vertical direction
...
Thus, the class comprises a bitset and all the public bitset management methods
it inherits
...
The move()method
moves the cursor to the position with the given coordinates
...


776



CHAPTER 33



CONTAINERS

BITSETS (CONTINUED)

Bresenham algorithm
// bitmap
...

// --------------------------------------------------template
void Bitmap::draw(int x, int y)
{
if( x >= 0 && x < lines && y >= 0 && y < cols)
{
int savex = x, savey = y;
if(ax > x) // Draw in ascending x-direction
{
// => possibly swap (ax,ay) and (x,y)
int temp = ax; ax = x; x = temp;
temp = ay; ay = y; y = temp;
}
int dx = x - ax, dy = y - ay;
int xinc = 1, yinc;
// Increment
if( dy < 0)
{ yinc = -1; dy = -dy;}
else yinc = 1;

// Gradient < 0 ?
// Decrement y
// or else increment
...


while( count-- > 0)
{
ai = ax * cols + ay;
set(ai);
if( d < 0)
{ ay += yinc;
else
{ ax += xinc;

// Index in the bitset
// Set the bit

// Next pixel in
d += dx; }
// y-direction
// or else in
d -= dy; }
// x-direction

}
ax = savex; ay = savey; // Current cursor position
ai = ax * cols + ay;
// Current index in bitset
}
else throw invalid_argument("Invalid argument\n");
}
#endif

BITSETS (CONTINUED)



777

ᮀ Manipulating Bits
The container class Bitset provides the get() and set() methods for reading
and writing individual bits
...
You can
additionally pass a value of 0 or 1 to the set method, which writes this value at the bit
position stated
...

If you call the set() method without any arguments, all the bits in the bitset are set
to 1
...
Bits can be inverted by a call
to the flip() method
...

Bits at specific coordinates can be referenced by the subscript operator
...

As you would expect, bitwise operators can also be used for bit manipulation
...
The operator functions for the
NOT operator ~, the shift operators << and >>, and the operators for compound assignments, &=, |=, ^=, are implemented as methods of the container class
...
The Bresenham algorithm used here
applies incremental techniques
...
To do this, you only need to increment or decrement the x- or y-coordinate by 1
...

To allow drawing to take place along a positive x-axis, the starting and target points
of the straight line can be swapped
...

Drawing neighboring pixels creates a “staircase” effect, which deviates from the
straight line
...
If the value of
d is negative, the line is seen to be growing along y-direction and the next pixel is drawn
along the y-direction
...
As soon as d
becomes positive, the next pixel is drawn along the x-direction and the deviation is corrected with dy
...
Queue

2
...
Queue

Entrance

4
...

The queues will now be filled
using the hot potato algorithm
...

Output the queues:
1
...
queue:
3
...
queue:
5
...
queue:
7
...
queue:
9
...
En route to the target computers, so-called routers store these messages
in queues before transmitting them towards the target via the next available line
...

There are various routing techniques, including a simple algorithm that can do without address tables, the so-called Hot Potato Algorithm
...





Define a container class VecQueue, which is parameterized with a message
type T to represent this scenario
...

The constructor creates the number of empty queues passed to it as an argument
for the array
...

Overload the size() method in two versions: If no argument has been passed
to the method, it returns the current number of messages in all queues
...
Additionally, overload the empty() and
empty(int i) methods, which return true, if all queues or the i-th queue are
empty
...

The pop() and pop(int i) methods are used to simulate the assignment of
messages to lines, that is retrieval and removal of messages from queues, in this
exercise
...
The method pop(int i)
retrieves the message at the top of the i-th queue and deletes it, returning the
message
...
A message is represented by a number
...
Then display the remaining messages on screen, as shown opposite,
by calling the pop(int i) method
...
h
// Defining the Class Template VecQueue
// to represent a vector of queues
...
size(); }

//
//
//
//

Current number of all
elements
...


bool empty() const
{ return size() == 0; }
bool empty(int i) const { return size(i) == 0; }
void push(const T& a);

// Hot potato algorithm

const T& pop();

//
//
//
//
//

const T& pop(int i);
};

Removes the element at the
beginning of a randomly
choosen queue
...
resize(n);
sz = n;
srand(time(NULL));
}

// Constructor

SOLUTION

template
// Current number of all elements
size_t VecQueue::size() const
{
size_t count = 0;
for( int i=0; i < sz; ++i)
count += v[i]
...

if( v[i]
...
size())
small = i;
v[small]
...

}
template
const T& VecQueue::pop()
{
static T temp;
int i, i0;

// To retrieve and delete
// an element in a randomly
// choosen queue
...
empty())
// If i-th queue is not empty:
{
// To retrieve and delete the
temp = v[i]
...

v[i]
...

}
while( i != i0);
return temp;
}
template
// To retrieve and delete
const T& VecQueue::pop(int i) // an element in the
{
// i-th queue
...
front();
v[i]
...




781

782



CHAPTER 33

CONTAINERS

Solutions (continued)
// ----------------------------------------------------// hotpot_t
...

// ----------------------------------------------------#include
#include
#include
#include
using namespace std;

// For srand(), rand()
// For time()

#include “vecQueue
...

<< endl;
srand(time(NULL));
cout << “\nThe queues will now be filled “
<< “using the hot potato algorithm
...
push(rand()%100);

// To insert 100 elements

cout << “\nSome elements of randomly selected “
“queues are removed
...
pop();
cout << “\nTo output the queues:” << endl;
// To retrieve, remove
for( i = 0; i < nQueues; ++i)
// and display all
{
// remaining elements
...
Queue: “;
while( vq
...
pop(i);
}
cout << endl;
}
return 0;
}

appendix

This appendix contains


binary number representation



preprocessor directives



pre-defined standard macros



binding C functions



operator precedence table



ASCII Code table



screen control characters

783

784



APPENDIX



BINARY NUMBERS

The numbers used by a program can be divided into two groups depending on their type:



integers of the char, signed char, unsigned char, short, unsigned
short, int, unsigned int, long, unsigned long types and
floating-point numbers of the float, double, and long double types
...
However, the formats for representing integral and
floating-point numbers differ
...


Representing Signed and Unsigned Integers
The binary format of integers is basically the same for the char, short, int and long
types and differs only in



the number of bytes available for each type and
whether the number is interpreted as signed or unsigned
...
The sign
bit 0 additionally indicates that the number is positive in the case of signed types
...


The binary representation of the number 4 as signed char type value (8 bits) is thus
as follows:
0

0

0

0

0

1

0

0

26

25


...


22

21

20

Sign bit

Two’s complement is used to represent a negative number, for example -4:
First, one's complement of 4 is
computed, that is,
all the bits are inverted:

1

1

1

1

1

0

1

1

Then the number 1 is added:

0

0

0

0

0

0

0

1

Producing the bit pattern of –4:

1

1

1

1

1

1

0

0

BINARY NUMBERS



785

You can also use two’s complement to compute the absolute value of a negative number
...

Sign bits are not required for unsigned types
...

The following table contains the binary formats of signed and unsigned integral 8 bit
values:

Binary

Signed decimal

Unsigned decimal

0000 0000
0000 0001
0000 0010
0000 0011

...

0111 1101
0111 1110
0111 1111
1000 0000
1000 0001

...

1111 1100
1111 1101
1111 1110
1111 1111

0
1
2
3

...

125
126
127
–128
–127

...

–4
–3
–2
–1

0
1
2
3

...

125
126
127
128
129

...

252
253
254
255

If the bit-pattern of a negative number is interpreted as an unsigned number, the value
of the number changes
...


Representing Floating-point Numbers
To represent a given floating-point number, x, the number is first broken down into a
sign, v, a mantissa, m, and a power, exp, with a base of 2:
x = v * m * 2exp

786



APPENDIX

Memory for the values v, m, and exp is normally assigned in IEEE (Institute of Electronics and Electronical Engineers) format
...
The mantissa, m, has
a value that is greater than or equal to 1 and less than 2, the only exception being x ==
0, where the mantissa is 0
...
5 =

-1 * 1
...
The power is stored
along with its bias
...

The memory reserved for the mantissa defines the accuracy, and the memory reserved
for the power defines the range of values for the floating-point number
...

You can use an instantiation of the numeric_limits class template for the type in
question to query platform-dependent ranges by method calls
...


Syntax:

#define name[(parameterlist)] [SubstituteText]

The preprocessor replaces name or name(parameterlist)with SubstituteText
throughout the whole program
...
)

Example: #define BUFSIZ
#define
#define

512 // Symbolic constant
CLS
cout << "\033[2J" // Macro
MAX(a,b) ((a)>(b) ? (a):(b))// Macro

The # Operator
A macro parameter in a substitute text can be preceded by the # operator (or stringizing
token)
...


Example: #define TITLE(s)

"****

" #s "

*****"

The call
cout << TITLE(Catalog);

causes the preprocessor to expand the following string
"****

" "Catalog" "

****"

which is then concatenated to "**** Catalog ****"
...


Example: #define path(logid,subdir)
"\\user\\" #logid "\\bin\\" #cmd

With

path(Smith, games)

the string "\user\Smith\bin\games " is produced
...
The past token operator, ##, is used to this effect
...
Then the token and any leading or trailing whitespace character is removed
...
However, if
the result of a concatenation is a symbolic constant or a macro, text replacement is again
performed
...
To do so, the #undef directive is used
...

You can then use the #define directive to redefine the macro
...


...
The #include directive is replaced
by the content of the file
...

If the file name is stated in quotes the file will also be looked up in the current directory first
...
In this case the file is only looked up in
the directory stated
...
The substitute text must be
in quotes or square brackets in this case
...
h"
#if VERSION == 1
#define MYPROJ_H "version1
...
h"
#endif
#include MYPROJ_H

The #if, #elif, #else, and #endif Directives
You can use the #if, #elif, and #endif directives to compile certain parts of a source
file and ignore others
...


Syntax:

#if expression1
[text1]
[#elif expression2
text2]

...

[#elif expression(n)
text(n)]
[#else
text(n+1)]
#endif

Each #if directive must be terminated by an #endif directive
...
The #else directive can occur once only
...
in sequence
...

If none of these expressions is true, the #else directive is executed
...

expression1, expression1,
...
Some compilers do not allow the use of the
sizeof operator
...

When a corresponding text is processed, the preprocessor may first execute directives
before passing the expanded source code to the compiler for compilation
...


790



APPENDIX

The defined Operator
You can use the defined operator to check whether a symbolic constant or macro has
been defined
...

A definition created using the #define directive remains valid until it is removed by
an #undef directive
...

The defined operator is normally used in #if or #elif directives, for example

Example: #if defined VERSION

...


The #ifdef and #ifndef Directives
You can also perform the same check using the #ifdef and #ifndef directives
...

In contrast, the #ifndef directive ensures that a value has not yet been defined, that
is, that name is undefined, returning 0 if name has been defined, and a non-zero value
in any other case
...


The #line Directive
The compiler uses line numbers and the name of a source file to display errors discovered
on compilation
...


Syntax:

#line new_number ["filename"]

At this position a new line count begins by new_number
...

The new file name must be in quotes and new_number must be an integral constant
...
cpp"
The line number and the file name can also be stated as symbolic constants
...
In the case of error messages, the message can refer to the appropriate line
and file name in the original code
...


Example: cout << "Current line number: "
<< __LINE__ << endl
<< "File name: " << __FILE__ << endl;

The #error Directive
The #error directive can be used to show preprocessor errors
...


Example:

#if defined
VERSION
#if VERSION < 3
#error VERSION too old
...

#endif
#include "version
...

Version 3 or better needed
...


Syntax:

#pragma command

Any other compiler that supports the #pragma directive but does not support the command following #pragma simply ignores the command
...
Other options are pack(2) and pack(4)
...
Their names begin and
end with two underscores:
__LINE__

Returns the number of the line containing the __LINE__ macro
...
The numbering can be modified
using the #line directive
...
The name can be modified using the #line directive
...

__DATE__ refers to the point in time when the preprocessor started

processing the source
...

__TIME__

Returns the time as a string in the format hh:mm:ss, where hh refers
to hours, mm to minutes, and ss to seconds, e
...
, 15:23:47
...
Thus, the macro returns the same result at any
position in the source code
...

Is defined if the source code is compiled using a C++ compiler
...
However, function calls are
interpreted differently by the C++ compiler than you would expect from a C compiler
...


Example: extern "C" void oldfunc(int size);
This informs the C++ compiler that a C compiler was used to compile the oldfunc()
function
...
If you have already declared the functions in a
header file, you can include the header file in an extern "C" block
...
h"
}

It is common practise to declare extern "C" code in C header files
...


Example: #if defined _cplusplus
extern "C"
{
#endif
// Prototypes for C functions here
#if defined __cplusplus
}
#endif

The symbolic constant __cplusplus is evaluated to discover whether the current
compiler is a C or C++ compiler
...


Defining C Functions in C++ Programs
It is also possible to define your own C functions for a C++ program
...

The definition for a C function in a C++ program must be encased in an extern
"C" block
...


794



APPENDIX

Example: #include
#include
#include
using namespace std;
static char* city[] = { "Paris", "London",
"Barcelona", "Hollywood"}
static char* key = "New York";
extern "C" int scmp(const void*, const void*);
int main()
{
// Sort cities:
qsort( city, 4, sizeof(char*), scmp);
// Find city:
if( bsearch( &key, city, 4,
sizeof(char*),scmp) == NULL)
cout << "City" << (string) key
<< "not found
...


OPERATORS OVERVIEW



OPERATORS OVERVIEW

Operator

Meaning

Arithmetical Operators:

+

-

addition, subtraction
multiplication

*
/

%

division, modulus division

+

-

unary plus, minus operator

++

--

increment, decrement operator

Relational Operators:

==

!=

“equal”, “unequal”

<

<=

“less”, “less or equal”

>

>=

“greater”, “greater or equal”

Logical Operators:

&&

||

AND, OR
NOT

!
Assignment Operators:

=

simple assignment

op=

compound assignment
(op is a binary arithmetical or binary
bit-wise operator)

Bit-wise operators:

&

~

AND, NOT

|

^

OR, exclusive-OR

<<

>>

left shift, right shift



795

796



APPENDIX



OPERATORS OVERVIEW (CONTINUED)

Operator

Meaning

Access Operators:

::

scope resolution operator

[]

subscript operator

*

indirection operator


...
*

->*

pointer to member operators

Cast Operators:

(type)

C cast operator

dynamic_cast<>

dynamic cast operator

static_cast<>

static cast operator

const_cast<>

const cast operator

reinterpret_cast<>

reinterpret cast operator

Operators for Storage Allocation

new

new []

delete

delete []

To allocate storage dynamically for
an object, an array resp
...


Other Operators:

?:

,

conditional expression and comma
operator

&

address-of operator

name()

call to function name

type()

create a temporary object of type

type
sizeof()

sizeof operator (size of type)

typeid()

typeid operator (type informations)

OPERATOR PRECEDENCE TABLE



OPERATOR PRECEDENCE TABLE

Precedence

Operator

1
...



...


!

~

+ ("unary")
- ( "unary")
from left to right
++ ("prefix")
- ( "prefix")
& ("address")
* ( "indirection")
new new[] delete delete[]
(type)
sizeof()
4
...
*

5
...


+ ("binary") - ("binary")

from left to right

7
...


<

9
...


& ("bit-wise AND")

from left to right

11
...


|

from left to right

13
...


||

from left to right

15
...


=
%=
&=

17
...


15

017

F

(SI)

47

057

2F

/

16

020

10

(DLE)

48

060

30

0

17

021

11

(DC1)

49

061

31

1

18

022

12

(DC2)

50

062

32

2

19

023

13

(DC3)

51

063

33

3

20

024

14

(DC4)

52

064

34

4

21

025

15

(DC5)

53

065

35

5

22

026

16

(SYN)

54

066

36

6

23

027

17

(ETB)

55

067

37

7

24

030

18

(CAN)

56

070

38

8

25

031

19

(EM)

57

071

39

9

26

032

1A

(SUB)

58

072

3A

:

27

033

1B

(ESC)

59

073

3B

;

28

034

1C

(FS)

60

074

3C

<

29

035

1D

(GS)

61

075

3D

=

30

036

1E

(RS)

62

076

3E

>

31

037

1F

(US)

63

077

3F

?

ASCII CODE TABLE



ASCII CODE TABLE (CONTINUED)

decimal

octal

hex

character

decimal

octal

hex

character

64

100

40

@

96

140

60

`

65

101

41

A

97

141

61

a

66

102

42

B

98

142

62

b

67

103

43

C

99

143

63

c

68

104

44

D

100

144

64

d

69

105

45

E

101

145

65

e

70

106

46

F

102

146

66

f

71

107

47

G

103

147

67

g

72

110

48

H

104

150

68

h

73

111

49

I

105

151

69

i

74

112

4A

J

106

152

6A

j

75

113

4B

K

107

153

6B

k

76

114

4C

L

108

154

6C

l

77

115

4D

M

109

155

6D

m

78

116

4E

N

110

156

6E

n

79

117

4F

O

111

157

6F

o

80

120

50

P

112

160

70

p

81

121

51

Q

113

161

71

q

82

122

52

R

114

162

72

r

83

123

53

S

115

163

73

s

84

124

54

T

116

164

74

t

85

125

55

U

117

165

75

u

86

126

56

V

118

166

76

v

87

127

57

W

119

167

77

w

88

130

58

X

120

170

78

x

89

131

59

Y

121

171

79

y

90

132

5A

Z

122

172

7A

z

91

133

5B

[

123

173

7B

{

92

134

5C

\

124

174

7C

|

93

135

5D

]

125

175

7D

}

94

136

5E

^

126

176

7E

~

95

137

5F

_

127

177

7F

(DEL)



799

800



APPENDIX



SCREEN CONTROL SEQUENCES

The following escape sequences reflect the ANSI standard for screen control
...

ESC[#A
ESC[#B
ESC[#C
ESC[#D
ESC[z,sH or ESC[z;sf
ESC[s
ESC[u
ESC[#K

ESC[2J
ESC[#(;#
...


To enable these escape sequences, you must first load an appropriate screen device
driver
...
SYS file
DEVICE = C:\Windows\Command\Ansi
...
Corresponding functions based on system calls are offered for download
...

International Standard ISO/IEC 9899:1999(E), Programming Languages—C; published by
ISO Copyright Office, Case postale 56, CH-1211, Geneva 20, 1999
...

Josuttis, Nicolai, The C++ Standard Library, Addison Wesley, 1999
...


Symbols
&, 223, 231, 691
&&, 91
+, 50, 82, 85, 157
++, 85, 355
-, 82
--, 85, 355, 420, 755
*, 82, 233, 255, 355, 691, 755
/, 82
%, 82
->, 255, 755

=, 87
+=, 50, 87
-=, 87, 355
*=, 87, 157
/=, 87
%=, 87
==, 88, 159
!=, 88, 159
<, 88, 159
<=, 88, 159
>, 88, 159

>=, 88, 159
<<, 9, 88, 229, 429
>>, 44, 229, 429
::, 209
?:, 109
[], 691, 755
//, 91
/, 707
+-, 355
‘\n’, 51, 187
(), 691

A
Abstract classes, 565-585
concrete classes versus, 569
deriving, 569
and inhomogeneous lists, 574,
575-577
pointers and references to, 570
pure virtual methods for, 566
virtual assignment in, 572, 573
803

804



INDEX

Abstraction, 245
Access methods, 274, 275
AccFile class, 656
append() method of, 650, 651
Account class, 267, 392, 393
access methods for, 274
with constructors, 266
defining, 648
methods of, 248
read-only methods in, 276
sample class, 272
Account management index file, 655
accPtr array
pointers in, 364
accSort() function, 682, 683
Accuracy, 21, 786
Adapter classes, 753
access to objects in, 761
constructors for, 757
deletion in, 765
insertion in, 759
Addition, 82, 353, 417
Addresses, array, 351
Address operator, 231, 412
Address space, hash file, 658
Algorithm library
within C++ standard library, 723
Alignment
and fill characters, 67
setting, 67
Ambiguity, 591
Ambiguous keys, 769
American National Standards Institute (ANSI),
3
Ampersand character, 223, 231, 691
Analysis, 245
AND operator, 91
Angled brackets
and header files, 47
template arguments stated in, 737
Appending
in arrays, 485
at end-of-file, 639
list elements, 465, 467
append() method, 333, 481, 485, 655
for class AccFile, 650

Applications
dynamic matrices, 694, 695
index files, 652, 653
inhomogeneous lists, 574-575
area() function
defining and calling, 176, 177
Argument pointer, 685
Arguments, 43
access to, 685
arrays as, 356
command line, 366, 367
functions without, 45
macros called with, 123
objects as, 235
objects passed as, 282
passing, 178
pointer arrays as, 683
pointers as, 235
template, 730, 731
variable number of, 684, 685, 686
argv array
in memory, 366
Arithmetic operators, 20, 412
binary, 82 83
precedence of, 84
unary, 84, 85
Arithmetic shifts, 709
Arithmetic type conversions
and precedence, 707
Arithmetic types, 20, 21
in assignments, 145
arr array
in memory, 322
Array elements, 323
addressing, 353
arrays as, 331
index for, 323
pointers interrelated with, 352
Arrays
appending/deleting in, 485
as arguments, 356
as array elements, 331
class FloatArr, 427
class representing, 426, 427
defining, 322, 323
dynamic, 461

INDEX

dynamic storage allocation for, 460, 461
encapsulating, 333
initializing, 324, 325
length of, 357
member, 332
multidimensional, 330, 331
name and address of, 351
parameters declared as, 357
of pointers, 364
pointers moved in, 355
and pointer variables, 351
sample program, 350, 352
as sequential containers, 751
subscript operator for, 427
Arrow operator, 255
Article class, 287, 311
copy constructor of, 310
ASCII code (American Standard Code for Information Interchange), 17, 800
Assignment operator, 87, 253, 412
overloading, 489
Assignments, 279, 488, 489
implicit type conversions in, 145, 531
type conversions in, 145, 532, 533
virtual, 572, 573
...
See also Abstract classes;
Adapter classes; Base classes; Derived classes;
Type conversion for classes
class keyword, 247, 257
Class member access operator, 253
Class-specific constants, 309
Class template, 723
defining, 725
for sequences, 753
clear() method, 70, 645
for deleting objects in container classes, 765
for erasing containers, 771
and maps/multimaps, 773
Client class, 303
climits header file, 19
clog stream, 58, 59
close() method, 389
Closing files, 388, 389
CLS macro, 123
cmath header file, 41
Collision resolution, 658
Collisions, 658
Colons
after labels, 113
Command line arguments, 367
sample program, 366
Comma operator, 412
syntax for, 101
Commas
for separating member initializers, 301

Comments
C++ program with, 10
examples of, 11
Comparative operators, 88, 159, 355
Comparator class, 753
compare() function, 689
Comparisons
results of, 89, 159, 355
Compiler, 7
Complex declarations, 690
operators and, 691
rules for evaluating, 691
complex header file, 48
Compound assignments, 145
bitwise operators in, 713
demonstration of, 86
operators, 87
Compound conditions, 91
Concatenation operators, 50, 157
Concrete classes
abstract classes versus, 569
Conditional expressions, 109
compilation, 790
structogram for, 108
Conditional inclusion, 126, 127
Conditional operator precedence, 109
conio
...
See also Destructors
Container adapters, 752
Container classes, 753, 768
deleting objects in, 765
Containers, 749-782
description of, 751
length and capacity of, 763
positioning and iterating in, 755
types of, 750, 751
Containers Library, 751, 753
Contiguous memory space, 323
continue statement, 113
Control, 28
Controlling expression, 97
ControlPoint class, 424, 425
Conversion constructors, 442, 443
Conversion functions, 443
conversion constructor versus, 445
defining, 445
“Cooked mode,” 386
Copy constructor, 279
effect of standard, 486
for FloatArr class, 486, 487
proprietary version of, 487
cos() function, 40
Counter
initializing, 99
count() method
and maps/multimaps, 773
count variable, 643
cout, 9, 30, 32
cout stream, 47, 49, 58, 61
Coworker class, 566, 567
assignment for, 572, 573
CPU registers, 205
cstdlib header file, 45
C strings
initializing, 326
specializing function template for, 732
and string class, 327

ctime() function, 167
ctype
...
See also Constructors
Direct base class, 503
Direct derivation, 502
displayError() function, 365
display() function, 227
display() method, 247, 253, 509
calling, 546, 547
new version of, 508
Division, 82
Dot operators, 253
Double ended queue, 753
Double quotes
and header files, 47
string constant within, 25
double type, 21, 25
do-while loop, 97
syntax for, 103
do-while statement
structogram for, 102
Downcasting, 536, 537

safety issues in, 537, 553
draw() method
and Bitmap container class, 775

and Bresenham algorithm, 777
Dynamically allocated objects
destroying, 548, 549
Dynamic arrays, 461
Dynamic binding, 551
Dynamic casting, 537
dynamic_cast operator, 553
Dynamic casts
using, 552
Dynamic data structures, 463
Dynamic matrices, 694, 695
Dynamic members, 477-498
classes with, 480
description of, 479
objects created with, 480
of varying length, 478
Dynamic memory allocation, 453-475
for containers, 751
Dynamic storage allocation
for arrays, 460, 461
for classes, 458

E
Early binding, 551
Elementary operations, 463
Element functions
for output in fields, 66
else branch, 105, 107
Else-if chains
structogram for, 106
switch statement contrasted with, 111
Embedded keys, 769
Employee class, 570
assignment for, 572, 573
Empty lists, 465, 577
empty() method, 771
and container classes, 763
Empty statements, 99
Empty strings, 25
Encapsulation, 3, 245, 257
of arrays, 333
and static data members, 307



809

810



INDEX

end() method, 755

and associative container classes, 769
endl manipulator, 9, 61
Enumeration
definition, 309
sample program, 308
enum keyword, 309
eof bit, 387
Equals sign
and initialization, 33
erase() method, 161, 771
for deleting objects in container classes, 765
errno
...

See also Header files; Records
File scope
object defined with, 199
File state, 644, 645
File stream classes, 382, 383
functionality of, 383
in iostream library, 383
File streams, 383
definition, 385
sample program/creating, 384
Fill-characters
specifying for field, 67
fill() method, 67
Filter programs
using, 131
Filters, 131
find() method, 163
and maps/multimaps, 773
fixed manipulator, 65
Fixed point output, 65
Flags, 60
for open mode of file, 386



811

open mode, 387
positioning, 641
state, 645, 647
FloatArr class, 740
constructors in, 483
copy constructor for, 486, 487
data members of, 478
new declarations in, 488
new methods of, 490, 491
prototype of operator function for, 489
versions of, 479, 480, 481, 484, 485
Floating-point constants, 25
examples for, 24
Floating-point division, 413
Floating-point numbers, 17, 21, 25
formatted output of, 64
inputting, 73
Floating-point types, 20, 21
conversion of, to integral type, 145
conversion of, to larger floating-point type, 143
conversion of, to smaller type, 145
Floating-point values
types for, 16
float type, 21, 25, 331
for loops
syntax for, 99
Formatting, 61
options, 63
standard settings, 65
Formatting flags, 61
Formatting operator, 63, 67
for statement, 97
sample program, 100
structogram for, 98
Fraction class, 431
simplify() method of, 448
Fractions
calculating with, 430
Friend classes, 424, 425
declaring, 425
using, 425
Friend declaration, 423
Friend functions, 422, 423
declaring, 423
overloading operators with, 423
using, 425

812



INDEX

friend keyword, 423
front() method, 761

and container classes vector, deque, and list, 761

Fundamental types, 16, 17, 18, 20
example with, 303
operators for, 82-90

fstream class, 383, 387

Function blocks, 175
Function call operator, 420
Function calls
defined, 43
implicit type conversions in, 147, 531
sample program, 42
Function prototype, 11, 41
example of, 40
Functions, 171-195
C++ program with, 10
calling and called, 178
conversion of, 443
declaring, 40-41, 175, 177
default arguments defined for, 182, 183
defining, 174
error checking after leaving, 608
external, 207
general form of, 174, 175
hash, 658
inline, 180, 181
libraries, 173
and macros, 125
operator, 414, 415, 416
overloading, 184, 185
and passing by value, 179
pointers to, 688, 689
pointer versions of, 358, 359
recursive, 186, 187
return value of, 176
sample, 205
scheme of, with varying arguments, 684
signatures, 185
significance of, in C++, 172
static, 207
virtual operator, 573
without arguments, 45
without return value, 45
Function templates, 723
ANSI instantiation of, 737
defining, 725
explicit instantiation of, 737
passing arguments to, 730, 731

G
get() function, 75
getch() function, 132, 687
getline() function, 51, 155
getline() method, 75, 391
get() method, 75, 391
getPassword() function, 203, 207

get pointer, 643
getput() function, 187
get/put pointer, 639
getTypeid() method, 651
Global arrays, 325
Global functions, 9, 51
from C++ standard library, 173
methods versus, 283
programming, 175
Global objects, 199
defining, 201
using, 201
Global operator functions, 420, 421
defining, 421
Global variables, 33, 34
goto statement, 113
Graphical user interfaces, 7, 173

H
“Has-A” relationship, 299
Hash files, 658-659
Hash function, 658
Hashing, 325
Hash key, 658
Hash tables, 641
has relationship, 501
Header files, 7, 9, 41, 249
and associative containers, 768
and macros, 125
multiple inclusions of, 126
searching for, 47
and sequences, 752
standard, 48
standard class definitions in, 47
using, 46, 47

INDEX

Heap, 454, 455, 769
Hexadecimal constant, 23
Hexadecimals
displaying, 63
outputting, 63
hex manipulator, 63, 73
Hot potato algorithm, 778, 779

I
Identical types, 323
Identifiers, 31
declaring, 41
read-only, 223
IEEE
...
See also Multiple
inheritance
Inheritance graph
building, 594, 595
InhomList class
complete, 578
defining, 576, 577
Inhomogeneous lists
application with, 574
implementing, 576
terminology for, 575
init() call, 253
Initialization, 33
and constructor calls, 595
of constructors, 269
explicit, 329
of member objects, 301
of objects, 251, 279, 455
references, 223
for virtual base classes, 596, 597

814



INDEX

Initialization list, 325, 329
and arrays of pointers, 365
init() method, 247, 267
Inline functions, 125, 180, 181
definition of, 181
global, 273
and macros, 181, 183
inline keyword, 181
Inline methods, 272, 273
Input
errors, 73
fields, 71
formatted, 70
formatted, for numbers, 72
redirecting standard, 130, 131
stream classes for, 58
streams, 9
input() function, 686, 687
insertAfter() method, 577
Insertion methods
in sequences, 758
in vector, deque, and list container classes, 759
Insertion sort algorithm, 738
insert() method, 161, 485, 771
of class IndexFile, 652, 653
of class IndexFileSystem, 654, 655
and maps/multimaps, 773
of SortVec derived container class, 758
Instances, class, 51, 251
Instantiation
and template definition, 723
of template functions, 733
of templates, 726, 727
Institute of Electrical and Electronic Engineers, 20
Integer promotions, 140, 141
Integers, 17
computing parity of, 712
formatted output of, 62
inputting, 73
types for, 16
Integer types, 21
Integral constants, 23
examples for, 22
Integral numbers
displaying, 63
Integral promotion, 709

Integral types, 18, 19
conversion of, to floating-point type, 143
conversion of, to smaller type, 145
and operands for bitwise operators, 707
Integrated software development environment, 7
internal manipulator, 67
Internal static object, 203
International Organization for Standardization, 3
Interpolation search, 738
INT_MAX, 19
INT_MIN, 19
int type, 19, 23
Invalid indexes, 427
invalid_argument class, 620
I/O (input/output)
formatted/unformatted, 74, 75, 391
overloading shift operators for, 428
redirecting, 130, 131
iomanip header file, 48, 65, 66
ios baseclass
flags defined in, 386
ios::boolalpha flag, 69
ios class, 59
ios::seekdir type positioning flags, 641
iostream class, 59
iostream header file, 9
iostream library, 59
file stream classes in, 383
isLess() method, 282
islower(c) macro, 129
ISO
...
h header file, 190
Matrix, 331
Matrix class, 695
constructor, destructor, and subscript operator for,
695
Member arrays, 332
Member functions, 9, 51, 245
Member initializers, 300, 301
Member objects, 298, 299
constant, 302, 303
initializing, 301
Members, 247
redefining, 508, 509
Member sub-object, 299
Memory
allocating, 249
objects in, 251
releasing, 459
union and usage of, 259
Memory address
for object of class, 255
merge() method
for merging list containers, 767
of SortVec container class, 762
message() function, 227
Methods, 51, 245
calling, 51
of class template, 725
const and non-const versions of, 277, 279
and data members, 505
defining, 248, 249
global functions versus, 283

name lookup for, 507
operator functions as, 415
operators overloadable by, 420
positioning, 643
pure virtual, 566, 567
standard, 278, 279
min() function template, 732
MIN macro, 127
Modifiers
signed and unsigned, 19
Modular programming, 7, 249
Modules, 7, 173, 199
MotorHome multiply-derived class, 588, 589, 598
move() method
and BitmapN container class, 775
Multidimensional arrays
defining, 331
as parameters, 359
sample program, 330
Multimaps, 769
using, 772, 773
Multiple assignments, 87
Multiple indirect base classes, 590, 591
Multiple inheritance, 587-606
constructor calls, 594
initializing virtual base classes, 596
multiple identical base classes, 591
multiple indirect base classes, 590
multiply-derived classes, 588, 589
virtual base classes, 592
Multiple template parameters, 729
Multiply-derived classes, 588, 589
multiset container class, 771
Multisets, 769
declaring, 771
sample, 770

N
Names and naming
arrays, 351
bit-fields, 715
constructors, 267
declaring, 41
file, 385
macros, 121
operator functions, 415

INDEX

source file, 7
valid, 31
of variables, 31
namespace keyword, 209
Namespaces
defining, 208, 209
n-dimensional array, 331
Negation, 417
Negative numbers
converting, 142
outputting as decimals, 63
Nested if-else statements, 105
Nested namespaces, 209
Nesting exception handling, 616, 617
Nesting loops, 103
new handler, 457
New-line characters, 11, 51
new operator, 454
calling for fundamental types, 455
calling with default constructor, 459
new[] operator, 461
noboolalpha manipulator, 69
Nongraphic characters, 28
noshowpoint(*), 64
noshowpos(*) manipulator, 60
NOT operator, 91
nouppercase manipulator, 63
NULL, 365, 465, 577
Null character, 25, 26, 327
NULL pointer, 333, 363, 457
Numbers
formatted input of, 72
Number symbol (#), 9, 11
Numerical constants, 23
Numeric operations
exception handling for, 618, 619
numeric_limits, 786

O
Object-oriented programming, 3, 4, 5, 245
Object persistence, 392, 393
Objects, 5, 33
accessing, 281, 760, 761
as arguments, 235
assigning, 253
cleaning up, 271

creating/destroying, 51, 482, 483, 511
creating with dynamic members, 480
declaring, 513
defining, 250, 251
of derived classes, 512
explicit initialization of, 459
initializing, 251, 455
lifetime of, 199
local, 179
member, 298
in memory, 251
passing as arguments, 282
passing by reference, 283
passing by value, 283
pointers to, 254, 255
references returned to, 285
representing pairs of, 773
returning, 284, 285
static, 203
storage classes of, 198
storing, 393
of union WordByte in memory, 258
using, 252
...
See Object-oriented programming
open() method, 386, 387
Open mode flags, 387
Open modes, of file, 386
Operands
and order of evaluation, 91
symmetry of, 419
Operations
file, 380, 381
for sequences, 752
Operator functions, 414, 415, 416
calling, 415, 419
declaration of, 428
defining global, 421
definition of, 428



817

818



INDEX

Operator functions (continued)
global or method, 421
as methods, 415
naming, 415
negation, addition, and subtraction, 417
operator keyword, 415, 445
Operators
bitwise, 706, 707
for classes, 413
and complex declarations, 691
dot, 253
indirection, 232
overloadable, 412
overloading, 413
with pointer variables, 355
reference type, 229
in template functions, 733
unary, 233
Operators for fundamental types
binary arithmetic operators, 82-83
increment/decrement operators, 85
logical operators, 90
relational operators, 88, 89
sign operators, 85
unary arithmetic operators, 84
Optional arguments, 685, 687
OR operator, 91
ostream class, 47, 59, 61
out constant, 309
out_of_range(*), 620
Output
redirecting standard, 130, 131
stream classes for, 58
streams, 9
overflow_error(*) class, 620
Overloaded operators
rules for, 412
using, 418, 419
Overloading
assignment operator, 489
functions, 184, 185
operators, 413, 423
and redefinition, 509
shift operators for I/O, 428, 429
subscript operators, 426, 427, 485

P
Parameters, 175
declaring, 357
multidimensional arrays as, 359
pointers as, 234
read-only pointers as, 361
Parentheses
in syntax description, 33
Parity bit computation, 713
parity() function, 713
PassCar

versions of, 510, 511
PassCar class

virtual method table for, 550
PassCar derived class, 504

Passing arguments
to function templates, 730, 731
Passing by reference, 179, 225, 283
Passing by value, 179, 225, 283
Persistence
object, 392, 393
of polymorphic objects, 648, 650
Pixels (picture element), 775
Pointer arithmetic, 354, 355
Pointer arrays
generating dynamically, 683
Pointer assignment
effect of, 534
Pointers, 233, 285, 729, 755
to abstract classes, 570, 571
as arguments, 235
array elements interrelated with, 352
arrays of, 364
comparing, 355
to const objects, 361
defining, 230
defining arrays of, 365
to functions, 688, 689
moving in array, 355
NULL, 333
to objects, 254, 255
as parameters, 234
parameters declared as, 357
read-only, 360
returning, 362, 363

INDEX

sample program, 350, 352
subtracting, 355
typeless, 351
use of, instead of indices, 359
Pointers to pointers, 682, 683
Pointer types, 231
Pointer variables, 231, 235, 683
addressing with, 353
and arrays, 351
Polymorphic interfaces, 571
Polymorphic objects
persistence of, 648, 650
storing, 649
Polymorphism, 3, 543-564
concept of, 544, 545
destroying dynamically allocated objects, 548, 549
dynamic casts, 552, 553
virtual methods, 546, 547
virtual method table, 550, 551
pop_back() method
for deleting objects in container classes, 765
popFront() method, 465, 467
pop() method, 765
Positioning flags, 641
Positioning methods, 643
Positive numbers
converting to, 142
Postfix increment, 430
Postfix notation, 85
effects of, 84
Precedence
of arithmetic operators, 84
and arithmetic type conversions, 707
of Boolean operators, 91
for cast operator (type), 147
for comma operator, 101
for indirection operator, 233
operator, 85
for operators with pointer variables, 355
of relational operators, 88, 89
precision() method, 65
Prefixes, 31
Prefix increment, 430
Prefix notation, 85
effects of, 84

Preprocessor, 9
Preprocessor directives, 11
Primary file, within index file, 653, 655
printf() function, 685
Priority queues, 753
testing, 764
priority_queue template, 753
Private data members
accessing, 275
Private members, 245, 247, 249, 503, 507
Procedures, 5
Program scope
object defined with, 199
Projects, 249
Properties, 5
protected constructors, 569
Protected declarations, 515
Protected members, 515
Prototype, 175, 177
public base classes
is relationship established by, 589
Public interface, of class, 247
Public members, 245, 247
access to, in base class, 503
Public methods, 51
Pure virtual methods, 566, 567
pushBack() method, 465, 467
push_back() method, 759
push_front() method, 759
push() method, 759
put() method, 75, 391

Q
qsort() function, 689, 696, 697
QuadMatrix template, 734, 735

Quadratic matrices
class template representing, 734, 735
Queues
as sequential containers, 751
Quick sort algorithm, 187, 689
Quotient
of Fibonacci number, 325

R
rand(), 45



819

820



INDEX

Random access iterators, 755
Random file access, 381, 639
positioning for, 640, 641, 642, 643
Random number generator
initializing, 44, 45
Random positioning statements, 643
Random read and write access, 639
Range checking, 427
Range operator, 305
base class method accessed by, 509
range_error class, 620
Raster images
representing with bitmaps, 774, 775
rdstate() method, 645
Readability
and complex expressions, 109
and empty statements, 99
and loop body, 97
and macros, 121
and typedef, 693
Read access
open mode for, 638
read_at() method, 642
Reading
blocks of records, 390
characters, 75
records, 381
read() method
of classes DepAcc and SavAcc, 648, 649
implementing, 392, 393
Read-only methods, 277
Read-only pointers, 360
for non-constant objects, 361
Read-only references, 223, 225
Records, 257
inserting and retrieving, 655
position of, in files, 643
reading, 381
reading/writing blocks, 390
Recursive data structures, 465
Recursive functions, 186, 187
Redefined methods
calling, 513
Redefinition, 509

References, 3, 729
to abstract classes, 570, 571
conversions in, to base classes, 535
defining, 222
as parameters, 224
and pointers, 231
read-only, 223, 225
returning, 285
as return value, 226, 227
sample program, 222
Reference type function
calling, 227
register keyword, 205
Registers
CPU, 205
Register variables, 205
sample function with, 204
Relational operators, 50, 412
precedence of, 88, 89
remove() method, 481, 485
replace() method, 163
reset() method
and manipulating bits, 777
Resistant mistakes
program with, 76
resize() method
and container classes, 763
Result class, 303, 424, 425
constructors for, 298, 299
new version of, 302
with static members, 304
with static methods, 306
retrieve() method, 651
of IndexFileSystem class, 654, 655
Return address, 181
return statement, 9, 177
Return values, 41, 285
Reusability, 5, 501
reverse() function, 357
reverse() method, 767
rfind() method, 163
Right shift operators, 708, 709
Round brackets, 33
Routers, 779

INDEX

Row class

setw() manipulator, 66

defining, 694, 695
RTTI
...
h header file, 48
Signatures
constructor, 267, 269
function, 185
signed char type, 19, 142
Signed integers
converting, 142
signed keyword, 19
Signed type
conversion of, to larger integral type, 143
Sign extension, 143
Sign operators, 85
Simple assignments, 87
Single characters
meaning of, 26
Single quotes
character constants within, 25
size() method
and length of container, 763
and maps/multimaps, 773
and number of objects in container, 771
sizeof operator, 21
sort() method
list container sorted by call to, 767
SortVec container class
merge() method of, 762
search() method of, 760
using, 756
Source code, 7
Source files, 7, 249
layout of, 11
name, 7

S
Safe class, 514, 515
SavAcc class

defining, 648, 649
scientific manipulator, 65

Scope, 199
Scope resolution operator, 209, 211, 249
Screen control macros, 123, 125
Scrolling string output, 334
search() method, 655
seekg() method, 641
seekp() method, 641
SelectionSort() function, 697
Semicolon, 9, 103
Sequences
and header files, 752
operations for, 752
representing, 753
Sequential containers (or sequences), 750, 751
Sequential file access, 381
set container class, 771
setfill() manipulator, 66
setfill() method, 67
setf() method, 60, 61, 69
set() method, 777
setprecision() manipulator, 65
Sets
associative containers within, 751
declaring, 771
representing, 769
sample, 770
setTime() method, 282



821

822



INDEX

Spaces, 11
Special characters, 28
Special objects, of base class, 531
splice() function, 466, 467
Splice operations, 767
sqrt() function, 40, 53
srand() function, 45
sstream class, 48
Stack class template, 724
explicit instantiation for, 737
with two template parameters, 728
Stack content
after calling function, 178
Stacks, 179
fixed/varying arguments on, 684
and recursive functions, 187
as sequential containers, 751
testing, 726
Standard copy constructor, 487
Standard exception classes
hierarchy of, 621
using, 620
Standard exception handling
for streams, 647
Standard input, 59
Standard methods, 279
sample program, 278
Standard output, 59
Standard settings, 65
Star character, 233
State flags, 645, 647
Statements, 9
Static arrays, 325
Static binding, 551
Static data members, 304, 305
accessing, 306
declaring, 305
definition and initialization, 305
and encapsulation, 307
Static data structures, 463
Static functions, 207
static keyword, 305
static_cast, 537
Static lifetime, 199, 203
Static member functions, 307
Static objects, 203

static storage class, 202, 203, 207
std standard namespace, 9, 209

Storage classes, 199
of functions, 206
Storage class specifiers, 198
strcat() function
and return pointers, 363
strcmp() function, 327
index version of, 368
strcpy() function, 327
pointer versions of, 358
and return pointers, 363
Stream access errors, 651
Stream class
shift operators, 229
streambuf class, 48
Streams, 9
discovering/changing status of, 645
standard, 59
standard exception handling for, 647
String assignments, 155, 157
string class, 153, 251, 413
C strings and, 327
defining, 155
objects of, 51
sample assignments of, 228
sample program, 50, 154
String constants, 23, 25
String literal
internal representation of, 24
Strings
characters accessed in, 164
comparing, 158
concatenating, 156, 157
escape sequences used in, 29
initializing, 154, 155
inserting and erasing in, 160, 161
numbers converted to, 288
output of, 68, 69
searching and replacing in, 162, 163
stringstream class, 288
strlen() function, 327, 359
Stroustrup, Bjarne, 3
strstr() function sample program, 362, 363
struct keyword, 257
structs sample program, 256

INDEX

Style, 11
Sub-object lattice, 595
Subroutines, 5, 181
Subscript, 323
Subscript operators, 165, 427
and access via indices, 761
bits referenced by, 777
in Matrix class, 695
overloading, 426, 427
read and write access using, 485
Substrings
erasing, 160
replacing, 162
Subtraction, 355, 417
swap()

implementing as method, 282
swap() function, 235

Swapping, 455
switch statement, 111
else-if chains contrasted with, 111
structogram for, 110
Symbolic constants, 121
sync() method, 70
Syntax, 249
brackets in descriptions, 612
for defining variables, 33
errors, 7

T
Tabs, 11
tan() function, 40
tellg() method, 641
TelList class, 332, 333
methods implemented for, 336, 337
tellp() method, 641
Template arguments
restrictions on, 731
Template function definition, 733
Template functions
motivation for, 733
Template parameters
multiple, 729
restrictions on, 729
Templates, 3, 721-748
advantages of, 723
arguments, 730, 731

in C++ standard library, 723
default arguments of, 734, 735
defining, 724, 725
defining with multiple parameters, 729
function and class, 723
instantiating, 726, 727, 736, 737
parameters, 728, 729
specialization, 732-733
terminate() function, 613
Testing characters, 129
Text
mode, 386
and nesting loops, 103
Text editor, 7
this pointer
sample class DayTime, 280
using, 281
Throwing exceptions, 614
throw statement, 611
using, 610
timediff() function, 207
time() function, 167
time_t type, 261
tm struct, 260
Tokens, 11
Tone
and nesting loops, 103
top() method, 761
toupper() macro, 129
Traditional procedural programming, 4, 5
Translation unit, 199
true keyword, 23
trunc open mode, 386
Truth table
for logical operators, 90
try block, 615
nested, 616, 617
syntax of, 612, 613
Two-dimensional arrays
initialization list of, 331
parameter declaration for, 359
Type casting, 351
Type conversion for classes, 441-452
ambiguities of type conversions, 446-447
conversion constructors, 442-443
conversion functions, 444-445



823

824



INDEX

Type conversions, 43, 146
ambiguities of, 446, 447
in assignments, 145, 532, 533
explicit, 147, 536, 537
failure, 447
implicit, 140, 144, 147, 531
standard, 445
usual arithmetic, 141, 142
typedef keyword, 693
Type hierarchy, 140
Typeless pointers, 351
Typenames
defining, 692
Types, 611
platform dependent, 693
pointer, 231

U
Unary arithmetic operators, 84, 85
Unary operators, 83, 233
underflow_error class, 620
#undef directive, 127
Underscores
and internal names, 31
Unicode, 17
Union, 258, 259
defined, 259
Unique keys, 769
usetf() method, 60, 61
unsigned char type, 19
unsigned keyword, 19
unsigned short, 19
Unsigned types, 143
Unsigned value, 45
Unwinding the stack, 615
Upcasting, 536, 537, 553
User Network Interface, 715
using declaration, 211
using directive, 211
using keyword, 9, 49, 210
Usual arithmetic type conversions, 141, 145
performing, 142

V
va_arg() macro

arguments of, 687
valarray class, 48

Variables
defining, 33
defining in if statements, 105
names of, 31
pointer, 683
sample program, 32
Variable type, 77
Vector, 323
vector container class, 755
constructors of, 757
methods for deleting objects in, 765
Vectors
iterating, 754
Virtual assignments
using, 573
Virtual base classes, 592, 593
constructor calls in, 597
initializing, 596, 597
Virtual destructors
declaring, 549
virtual keyword, 593
Virtual methods, 546, 547
calling, 544, 545
declaring, 547
pure, 566, 567
redefining, 547
Virtual method tables, 550, 551
Virtual operator functions, 573
VMT
Title: FULL CONCEPT FOR C++ PROGRAMMING LANGUAGE
Description: Fundamentals 1 Development and Properties of C++ 2 Object-Oriented Programming 4 Developing a C++ Program 6 A Beginner’s C++ Program 8 Structure of Simple C++ Programs 10 Exercises 12 Solutions 14 Chapter 2 Fundamental Types, Constants, and Variables 15 Fundamental Types 16 Constants 22 Escape Sequences 26 Names 28 Variables 30 The Keywords const and volatile 32 Exercises 34 Solutions 36 contents Chapter 3 Using Functions and Classes 39 Declaring Functions 40 Function Calls 42 Type void for Functions 44 Header Files 46 Standard Header Files 48 Using Standard Classes 50 Exercises 52 Solutions 54 Chapter 4 Input and Output with Streams 57 Streams 58 Formatting and Manipulators 60 Formatted Output of Integers 62 Formatted Output of Floating-Point Numbers 64 Output in Fields 66 Output of Characters, Strings, and Boolean Values 68 Formatted Input 70 Formatted Input of Numbers 72 Unformatted Input/Output 74 Exercises 76 Solutions 78 Chapter 5 Operators for Fundamental Types 81 Binary Arithmetic Operators 82 Unary Arithmetic Operators 84 Assignments 86 Relational Operators 88 Logical Operators 90 Exercises 92 Solutions 94 Chapter 6 Control Flow 95 The while Statement 96 The for Statement 98 The do-while Statement 102 Selections with if-else 104 Else-if Chains 106 Conditional Expressions 108 Selecting with switch 110 Jumps with break, continue, and goto 112 Exercises 114 Solutions 116 xii ■ CONTENTS Chapter 7 Symbolic Constants and Macros 119 Macros 120 Macros with Parameters 122 Working with the #define Directive 124 Conditional Inclusion 126 Standard Macros for Character Manipulation 128 Redirecting Standard Input and Output 130 Exercises 132 Solutions 134 Chapter 8 Converting Arithmetic Types 139 Implicit Type Conversions 140 Performing Usual Arithmetic Type Conversions 142 Implicit Type Conversions in Assignments 144 More Type Conversions 146 Exercises 148 Solutions 150 Chapter 9 The Standard Class string 153 Defining and Assigning Strings 154 Concatenating Strings 156 Comparing Strings 158 Inserting and Erasing in Strings 160 Searching and Replacing in Strings 162 Accessing Characters in Strings 164 Exercises 166 Solutions 168 Chapter 10 Functions 171 Significance of Functions in C++ 172 Defining Functions 174 Return Value of Functions 176 Passing Arguments 178 Inline Functions 180 Default Arguments 182 Overloading Functions 184 Recursive Functions 186 Exercises 188 Solutions 191 Chapter 11 Storage Classes and Namespaces 197 Storage Classes of Objects 198 The Storage Class extern 200 CONTENTS ■ xiii The Storage Class static 202 The Specifiers auto and register 204 The Storage Classes of Functions 206 Namespaces 208 The Keyword using 210 Exercises 212 Solutions 216 Chapter 12 References and Pointers 221 Defining References 222 References as Parameters 224 References as Return Value 226 Expressions with Reference Type 228 Defining Pointers 230 The Indirection Operator 232 Pointers as Parameters 234 Exercises 236 Solutions 238 Chapter 13 Defining Classes 243 The Class Concept 244 Defining Classes 246 Defining Methods 248 Defining Objects 250 Using Objects 252 Pointers to Objects 254 Structs 256 Unions 258 Exercise 260 Solution 262 Chapter 14 Methods 265 Constructors 266 Constructor Calls 268 Destructors 270 Inline Methods 272 Access Methods 274 const Objects and Methods 276 Standard Methods 278 this Pointer 280 Passing Objects as Arguments 282 Returning Objects 284 Exercises 286 Solutions 290 xiv ■ CONTENTS Chapter 15 Member Objects and Static Members 297 Member Objects 298 Member Initializers 300 Constant Member Objects 302 Static Data Members 304 Accessing Static Data Members 306 Enumeration 308 Exercises 310 Solutions 314 Chapter 16 Arrays 321 Defining Arrays 322 Initializing Arrays 324 Arrays 326 Class Arrays 328 Multidimensional Arrays 330 Member Arrays 332 Exercises 334 Solutions 338 Chapter 17 Arrays and Pointers 349 Arrays and Pointers (1) 350 Arrays and Pointers (2) 352 Pointer Arithmetic 354 Arrays as Arguments 356 Pointer Versions of Functions 358 Read-Only Pointers 360 Returning Pointers 362 Arrays of Pointers 364 Command Line Arguments 366 Exercises 368 Solutions 372 Chapter 18 Fundamentals of File Input and Output 379 Files 380 File Streams 382 Creating File Streams 384 Open Modes 386 Closing Files 388 Reading and Writing Blocks 390 Object Persistence 392 Exercises 394 Solutions 398 CONTENTS ■ xv Chapter 19 Overloading Operators 411 Generals 412 Operator Functions (1) 414 Operator Functions (2) 416 Using Overloaded Operators 418 Global Operator Functions 420 Friend Functions 422 Friend Classes 424 Overloading Subscript Operators 426 Overloading Shift-Operators for I/O 428 Exercises 430 Solutions 432 Chapter 20 Type Conversion for Classes 441 Conversion Constructors 442 Conversion Functions 444 Ambiguities of Type Conversions 446 Exercise 448 Solution 450 Chapter 21 Dynamic Memory Allocation 453 The Operator new 454 The Operator delete 456 Dynamic Storage Allocation for Classes 458 Dynamic Storage Allocation for Arrays 460 Application: Linked Lists 462 Representing a Linked List 464 Exercises 466 Solutions 468 Chapter 22 Dynamic Members 477 Members of Varying Length 478 Classes with a Dynamic Member 480 Creating and Destroying Objects 482 Implementing Methods 484 Copy Constructor 486 Assignment 488 Exercises 490 Solutions 492 Chapter 23 Inheritance 499 Concept of Inheritance 500 Derived Classes 502 xvi ■ CONTENTS Members of Derived Classes 504 Member Access 506 Redefining Members 508 Constructing and Destroying Derived Classes 510 Objects of Derived Classes 512 Protected Members 514 Exercises 516 Solutions 520 Chapter 24 Type Conversion in Class Hierarchies 529 Converting to Base Classes 530 Type Conversions and Assignments 532 Converting References and Pointers 534 Explicit Type Conversions 536 Exercises 538 Solutions 540 Chapter 25 Polymorphism 543 Concept of Polymorphism 544 Virtual Methods 546 Destroying Dynamically Allocated Objects 548 Virtual Method Table 550 Dynamic Casts 552 Exercises 554 Solutions 558 Chapter 26 Abstract Classes 565 Pure Virtual Methods 566 Abstract and Concrete Classes 568 Pointers and References to Abstract Classes 570 Virtual Assignment 572 Application: Inhomogeneous Lists 574 Implementing an Inhomogeneous List 576 Exercises 578 Solutions 580 Chapter 27 Multiple Inheritance 587 Multiply-Derived Classes 588 Multiple Indirect Base Classes 590 Virtual Base Classes 592 Constructor Calls 594 Initializing Virtual Base Classes 596 Exercises 598 Solutions 602 CONTENTS ■ xvii Chapter 28 Exception Handling 607 Traditional Error Handling 608 Exception Handling 610 Exception Handlers 612 Throwing and Catching Exceptions 614 Nesting Exception Handling 616 Defining Your Own Error Classes 618 Standard Exception Classes 620 Exercises 622 Solutions 626 Chapter 29 More About Files 637 Opening a File for Random Access 638 Positioning for Random Access 640 File State 644 Exception Handling for Files 646 Persistence of Polymorphic Objects 648 Application: Index Files 652 Implementing an Index File 654 Exercises 656 Solutions 660 Chapter 30 More About Pointers 681 Pointer to Pointers 682 Variable Number of Arguments 684 Pointers to Functions 688 Complex Declarations 690 Defining Typenames 692 Application: Dynamic Matrices 694 Exercises 696 Solutions 698 Chapter 31 Manipulating Bits 705 Bitwise Operators 706 Bitwise Shift Operators 708 Bit Masks 710 Using Bit Masks 712 Bit-Fields 714 Exercises 716 Solutions 718 Chapter 32 Templates 721 Function and Class Templates 722 Defining Templates 724 xviii ■ CONTENTS Template Instantiation 726 Template Parameters 728 Template Arguments 730 Specialization 732 Default Arguments of Templates 734 Explicit Instantiation 736 Exercises 738 Solutions 742 Chapter 33 Containers 749 Container Types 750 Sequences 752 Iterators 754 Declaring Sequences 756 Inserting in Sequences 758 Accessing Objects 760 Length and Capacity 762 Deleting in Sequences 764 List Operations 766 Associative Containers 768 Sets and Multisets 770 Maps and Multimaps 772 Bitsets 774 Exercise 778 Solution 780