Introducing C For Scientists Engineers and Mathematicians 2nd Edition Derek Capper Download
Introducing C For Scientists Engineers and Mathematicians 2nd Edition Derek Capper Download
https://ebookbell.com/product/introducing-c-for-scientists-
engineers-and-mathematicians-2nd-edition-derek-capper-38548008
https://ebookbell.com/product/introducing-philosophy-for-canadians-a-
text-with-integrative-readings-1st-edition-robert-c-solomon-46248138
https://ebookbell.com/product/introducing-functional-programming-
using-c-leveraging-a-new-perspective-for-oop-developers-1st-edition-
vaskaran-sarcar-52166254
https://ebookbell.com/product/introducing-functional-programming-
using-c-leveraging-a-new-perspective-for-oop-developers-vaskaran-
sarcar-52181446
https://ebookbell.com/product/introducing-qt-6-learn-to-build-fun-
apps-games-for-mobile-desktop-in-c-1st-ed-ben-coepp-36665958
Introducing Psychology For Nurses And Healthcare Professionals 2nd
Edition Dominic Upton
https://ebookbell.com/product/introducing-psychology-for-nurses-and-
healthcare-professionals-2nd-edition-dominic-upton-48467806
https://ebookbell.com/product/introducing-pharmacology-for-nursing-
healthcare-roger-mcfadden-2345084
https://ebookbell.com/product/introducing-psychology-for-nurses-
healthcare-professionals-dominic-upton-2397962
https://ebookbell.com/product/introducing-net-for-apache-spark-
distributed-processing-for-massive-datasets-1st-edition-ed-
elliott-24015384
https://ebookbell.com/product/introducing-english-for-research-
publication-purposes-1st-edition-john-flowerdew-pejman-
habibie-34809146
Introducing Engineers and Mathematicians
Springer-Verlag London Ltd.
Derek Capper
i Springer
Derek Capper
Apart from any fair dealing for the purposes of research or private study, or criticism or review, as permitted under
the Copyright, Designs and Patents Act 1988, this publicat ion may only be reproduced, stored or transmitted, in any
form or by any means, with the prior permis sion in writing of the publishers, or in the case of reprographic
reproduction in accordance with the terms of licences issued by the Copyright Licensing Agency. Enquiries concerning
reproduction outside those terms should be sent to the publishers.
AII trademarks found in this book are acknowledged. This acknowledgement includes:
Linus Torvalds: Linux
Microsoft Corporation: MS-DOS, Windows
XlOpen Company Limited: UNIX
The use of registered names, trademarks etc. in this publication does not imply, even in the absence of a specific
statement, that such names are exempt from the relevant laws and regulations and therefore free for general use.
The publisher makes no representation, express or implied, with regard to the accuracy of the information contained
in this book and cannot accept any legal responsibility or liability for any errors or omissions that may be made.
Acknowledgements xvi
1 Introduction 1
1.1 Getting Started . . . . . . . . 1
1.2 Solving a Quadratic Equation 3
1.3 An Object-oriented Example 4
1.4 Why Object-oriented? 6
1.5 Summary. 7
1. 6 Exercises........ 7
v
vi CONTENTS
4 Control Structure 45
4.1 Relational Operators 45
4.2 Logical Operators 47
4.3 Equal and Not Equal Operators 48
4.4 Blocks and Scope 50
4.5 Branch Statements 52
4.5.1 if Statement . 52
4.5.2 i f else Statement 54
4.5.3 switch Statement 57
4.6 Iteration Statements 59
4.6.1 while Statement . 60
4.6.2 f or Statement 61
4.6.3 do Statement . 64
4.7 break and continue Statements. 66
4.8 goto Statement 67
4.9 Comma Operator 69
4.10 Null Statement 70
4.11 Conditional Expression Operator 71
4.12 Order of Evaluation of Operands. 71
4.13 The Preprocessor 72
4.13.1 include Directive 72
4.13.2 define Directive. 74
CONTENTS vii
5 Functions 85
5.1 Introducing Functions . . . . . . . . . . 85
5.l.1 Defining and Calling Functions. 85
5.l.2 Return Type . . . . . . . . . . . 88
5.l.3 Function Declarations . . . . . . 90
5.l.4 Functions Cannot Declare Functions. 90
5.l.5 Unused Arguments 92
5.l.6 Default Arguments 93
5.l.7 Ignoring the Return Value 95
5.2 Recursion.... . . . 95
5.3 Inline Functions . . . 96
5.4 More on Scope Rules 97
5.5 Storage Class static 99
5.6 Overloading Function Names. 101
5.6.1 Ambiguity Resolution 103
5.7 Function main () . 104
5.8 Standard Library .. 104
5.9 Using Functions . . . 107
5.9.1 A Benchmark 107
5.9.2 Root Finding by Bisection 109
5.10 Summary. 112
5.11 Exercises . . . . 114
8 Classes 197
8.1 Declaring Classes 197
8.2 Class Access Specifiers 199
8.3 Accessing Members .. 199
8.4 Assigning Objects .. . 201
8.5 FUnctions and Classes . 202
8.6 Data Hiding . . . . . 206
8.7 Returning an Object 209
8.8 Reference Arguments 2ll
8.9 Pointers to Members 2ll
8.10 Pointer-to-Member Operators 213
8.ll Scope and Data Protection . 217
8.12 Static Members . . . . . . . . 219
8.12.1 Static Data Members 219
8.12.2 Static Member FUnctions 221
8.13 Constructor Functions . . . . . 223
8.14 Accessing const Class Objects. 229
8.15 Friend Functions . . . . . . . 231
8.16 Program Structure and Style 233
8.16.1 Separate Compilation 233
8.16.2 Header Files 235
8.17 Using Classes 236
8.18 Summary. 241
8.19 Exercises . .. 244
CONTENTS ix
14 Namespaces 401
14.1 N arne Clashes ......... 401
14.2 Creating a Namespace . . . . . 403
14.3 Accessing Namespace Members 404
14.4 More on Creating Namespaces 405
14.5 Namespace Aliases .. 406
14.6 The using Directive .. 407
14.7 The using Declaration 409
14.8 The Standard Library. 411
14.9 Unnamed Names paces 412
14.10 Using Namespaces . 413
14.11 Summary. 417
14.12 Exercises . . . . . . 419
CONTENTS xi
16 Templates 449
16.1 Function Templates 449
16.2 Class Templates .. 453
16.3 Static Members .. 456
16.4 Class Templates and Functions. 457
16.5 Function Template Arguments 459
16.6 Template Parameters 459
16.7 Templates and Friends . . . . 460
16.8 Specialized Templates . . . . . 462
16.9 Member Function Specialization 465
16.10 Program Structure 466
16.11 Using Templates. 467
16.12 Summary. 469
16.13 Exercises . . . 471
Bibliography 529
Index 531
Preface to the Second Edition
Since the first edition of C++ for Scientists, Engineers and Mathematicians, many
things have changed. Perhaps the most important is that the ANSI C++ Standard
was approved in 1998. The first edition of this book was incompatible with some parts
of the Standard and every effort has been made to rectify this. The facilities offered
by the C++ language have also grown enormously since the first edition. It is not just
the language itself that has grown, but the ANSI Standard also defines an extensive
range of library facilities.
I have also made two changes in emphasis since the first edition. Firstly, since there
is so much important material to cover, some less important features of the language
have been removed. The second change is to try to illustrate the language by means
of complete programs, rather than code fragments. Hopefully, this will give you more
confidence in applying new techniques.
Finally, although C++ is a bigger language than it was, it is even more fun to use.
So, enjoy it!
xiii
xiv STRUCTURE OF THIS BOOK
It is very unlikely that any application will need every C++ feature described in this
book. However, with the exception of Chapter 18, the order in which material is pre-
sented means that you can progress as far as necessary in order to meet your particular
needs, without working through the entire book. Even if a fairly complete under-
standing of C++ is required, it is worth studying the language in deliberate stages,
interspersed with projects from your own field of interest. The following stages are
suggested:
merical application and are essential for writing any significant program. Most
applications would also need an understanding of Chapter 6, which introduces
arrays. This stage is roughly equivalent to what you would have in a language
such as FORTRAN. Most C++ programs make considerable use of pointers and,
although this topic is introduced in Chapter 6, it is developed further in the
following chapter. Here you will also find a description of strings and dynamic
memory management.
2. Classes, objects, data hiding and member functions are introduced in Chapter 8,
and Chapters 9 and 10 are devoted to operator overloading, constructors and
destructors. Although by themselves such techniques are not sufficient to consti-
tute object-oriented programming, they should enable you to write safer code for
fairly large applications. After working through these chapters you should also
be able to use C++ class libraries, such as matrix algebra, complex arithmetic,
strings etc. However, you will not be able to use inheritance to extend existing
classes to meet any special needs of your own specific applications.
3. Bitwise operations are described in Chapter 11. Such operations may not be
central to your interests and you could decide to omit this chapter. However,
an understanding of how numbers are stored in memory is very useful and you
would miss the neat application to the Sieve of Eratosthenes.
4. Chapter 12 describes single inheritance. At this stage you can truly claim to be
doing object-oriented programming with the ability to construct your own classes
and to extend existing classes.
6. Chapters 14, 16 and 15 are about namespaces, templates and exception handling.
Namespaces are useful for avoiding potential name clashes in large projects and
templates provide a way of reusing code. Exception handling provides techniques
for dealing with errors, and is particularly important for errors that are detected
by library facilities. All three chapters are prerequisites for the penultimate
chapter.
7. The ANSI C++ Standard defines an important and extensive set of library fa-
cilities. Chapter 17 provides an overview of this Standard Library. Chapter 18
describes input and output, which is actually part of the Standard Library. This
means that many details of input and output are not covered until this final chap-
ter. For example, file I/O is not introduced until this stage, although you may
have applications that lead you to consult this chapter before working through
the preceding chapters. The reason for leaving details of input and output until
Chapter 18 is that it involves classes, operator overloading, constructors, destruc-
tors, inheritance, templates, exception handling etc. In fact the I/O facilities
offered by the Standard Library employ just about every idea of the preceeding
chapters. However, don't despair! If you do need facilities such as file I/O at an
XVI ACKNOWLEDGEMENTS
early stage, then you should be able to extract the necessary information without
working through the entire book!
1. Items that fit naturally into a particular chapter, but could reasonably be post-
poned until later, are marked by a single dagger (t). You would probably have to
return to such sections in order to understand later chapters and you may have to
postpone attempting some of the exercises. A typical example is Section 4.13.3
on Conditional Compilation; you will probably need to use this information some-
time, but skipping the section on a first reading will not do any harm.
2. There are two kinds of section which are sufficiently self-contained that they
can be omitted altogether without any loss of continuity and these are marked
by double daggers (tt). Some sections are only intended for reference. Other
sections will only be of importance to particular applications; for example, bitwise
operations (Chapter 11) could be crucial for a number theory application but of
no relevance to solving a differential equation.
Acknowledgements
I would like to thank Helen Arthan for conscientiously working through the various
drafts of the first edition of this book and Mark Burton for removing many technical
errors. Peter Dew and Ian Robson both provided inspiration for some of the applica-
tions.
Above all I wish to thank my wife, Janet, for her constant support, without which
neither edition of this book would have been completed.
Chapter 1
Introduction
#include <iostream>
using namespace std;
int mainO
{
cout « "This is our first C++ program.\n";
return(O);
}
This complete C++ program must go through a two-stage process before it can be
run. First of all the code needs to be compiled in order to generate instructions that
can be understood by our computer and then this collection of instructions must be
linked with libraries. 2 The exact way in which the compilation and linking is carried
out will depend on the details of the particular system. Typically, if this first program
is in the file example. cxx, then both stages may be accomplished by entering:
1
D. Capper, Introducing C++ for Scientists, Engineers and Mathematicians
© Springer-Verlag London 2001
2 CHAPTER 1. INTRODUCTION
This command is consistent with the GNU C++ compiler running under Linux. 3 How-
ever, it may be conventional on your system to use a different extension for source code
(such as . cc, . cpp, . C or . c++) and the compile and link command may be different
(perhaps CC or gxx). You may also have to use <iostream.h> in place of <iostream>.
The -0 example part of the compile and link command results in the executable code
being placed in a file called example. You should then be able to execute this file by
entering the command:
example
If you omit -0 example from the compile and link command, then the GNU compiler
will put the executable code in the file a. out. However, with other compilers the file
in which the executable code is placed may be different; for example, on an MS-DOS
or Microsoft Windows system it may be example. exe.
If you have overcome all of the system-dependent hurdles, the following output
should appear:
The lines of code that produce this output require a few words of explanation.
The first line is a comment since any code following / / on a line is ignored. A larger
program would normally be introduced by a more significant comment. The third
non-blank line is the start of a function definition. Every complete C++ program
must contain a function called main and in our example, main is the only function.
The function name is preceded by the type specifier, int, since main should return
an integer. Parentheses, (), follow the name and are used to indicate that main is a
function. In some circumstances these parentheses may contain variables, known as
arguments.
The function, main () , contains two statements; the end of each statement is denoted
by a semicolon, sometimes known as a statement terminator. The first statement
outputs a message and the second statement effectively returns control to the operating
system. The standard output stream (usually the screen) is known as cout and the «
operator is used to send a string of characters to this stream, the group of characters
between the double quotes, " ", being known as a string. In our example, the string
ends with \n, which is used to denote a new line. This technique of sending character
strings to the output stream is not strictly part of the C++ language, but is part
of a library and is one of many standard functions that are available with any C++
compiler.
Since our program is compiled before it is linked to code for the output stream, we
need to supply information about the interface to couto This information is contained
in the file, iostream, which is made available to the compiler by the instruction:
#include <iostream>
The consequence of this instruction is that the iostream file is copied (that is included)
at this point. Files such as <iostream> are usually known as header files and are
described in more detail in Section 4.13.1. The < > notation is not part of the file
3This is the environment that was used to test the code given in this book, although the code
should work with little modification in other environments .
1.2. SOLVING A QUADRATIC EQUATION 3
name, but rather an indication that the file exists in a special place known to the
compiler.
The statement:
ax2 + bx + c = 0
-b± Vb 2 - 4ac
x=
2a
which can be implemented by the following (not very robust) program:
#include <iostream>
#include <cmath> II For sqrt() function.
using namespace std;
int mainO
{
double rootl, root2, a, b, c, root;
return(O);
}
This program introduces floating point variables, which can store numbers that
include a decimal point, such a8 0.5. Notice that we use 0.5 in the above code, rather
4 CHAPTER 1. INTRODUCTION
than divide by 2.0, since multiplication is usually faster then division. The variables
root 1, root2, a, band c are defined to be floating point numbers by virtue of the type
specifier, double.
The program first uses the cout stream to send text to the output device, instructing
the user to input three coefficients. Values for a, b, and c are read from the input
stream, cin, which is usually the keyboard. For example, you could try typing:
1 -3 2
and then hit the enter key. Having obtained the values for a, b, and c, the code makes
use of the assignment, =, multiplication, *, addition, +, and subtraction, -, operators
in self-evident ways.
In general, solving a quadratic equation involves finding the square root of a number.
This is achieved by invoking the sqrt 0 function,4 which is defined for us in a system-
supplied mathematics library. Since our program is first compiled and then linked with
compiled code for the libraries, we must also include the header file, <cmath>, which
contains a function declaration for the sqrt 0 function, specifying the argument and
return types (in this case double). Notice that we really do mean <cmath>, rather
than <math>, since the sqrtO function was originally part of the C, rather than C++,
libraries. 5
On some systems it may be necessary to specify that this example requires the
mathematics library for linking. A typical form of the compile and link command in
such cases is:
but you may need to consult the compiler reference manual for your particular system.
#include "matrix.h"
using namespace std;
int maine)
{
int i, j;
matrix A(6, 4), B(4, 6), C(6, 6);
4Within the text we write a function with an empty pair of parentheses following the name. This
is to emphasize that we really do mean a function, but does not necessarily imply that the function
takes no arguments. Within a segment of code, any necessary arguments are, of course, included.
5C++ is an extension of C, a language which was invented by Kernighan and Ritchie [5] and then
adopted by ANSI (the American National Standards Institute). C++ has also been adopted by an
ANSI committee. (See [1].)
1.3. AN OBJECT-ORIENTED EXAMPLE 5
II Multiply A and B:
C = A * B;
return(O);
}
This program uses some features of C++ to perform operations on matrices. The
statement:
C = A * B;
Notice how the code closely parallels the mathematics and is not obscured by function
calls. Moreover, if we make a mistake and write:
C = B * A;
which incorrectly attempts to assign a 4 x 4 matrix to a 6 x 6 matrix, then an error
message results.
Finally, the statement:
Gout « C;
Matrices are not part of the C++ language, but are an example of a user-defined
type, or class, which can be tailored to meet the exact needs of the application. 6 For
instance, some applications may be restricted to real matrix elements, whilst others may
be complex. In some circumstances bounds-checking may be an intolerable overhead,
whereas in others it may be essential. An application may even require that matrix
elements are themselves matrices. We will learn how to construct such classes. We will
also learn how to build on existing classes in order to create new classes, thus enabling
us to reuse software without understanding its detailed design.
The three matrices, A, Band C, are instances of the matrix class and are known
as objects. This example only skims the surface of object-oriented techniques, but
the essential idea is that a matrix is considered as an entity on which we perform
operations. A matrix object encapsulates details of how the data is stored, the value
of each element, the numbers of rows and columns, etc. Moreover, the matrix class
also shields the application programmer from details of how matrix operations, such
as multiplication, are implemented.
required, we can use a function. But a function to perform other operations may be
less straightforward. For instance, a function to invert a matrix needs information on
how the matrix is stored, its size and type. It would be much easier to reuse a matrix
inversion function if it simply operated on matrices as objects, which encapsulated
details of storage, size etc. Also, rather than simply reusing the matrix class, we may
want to modify it (perhaps to introduce bounds-checking) and ideally we should be able
to make changes without tampering with the original code. Object-oriented techniques
enable us to do all of these things.
Scientists and engineers are often working at the leading edge of what is computa-
tionally possible and are also well aware that inefficiency costs money. It might seem
that efficiency is incompatible with the requirements of maintainable and reusable
code. It is also true that object-oriented techniques usually introduce a slight run-time
overhead when compared with traditional methods. However, the key to efficiency is
identifying the appropriate objects. For example, if an application manipulates matri-
ces, then it should be written in terms of matrix objects, rather than matrix elements.
The details of matrix multiplication, addition etc. are then hidden from the application
programmer. Moreover, since the details are hidden, the implementation can be made
as efficient as possible. Such increases in efficiency far outweigh any run-time overhead
due to using object-oriented techniques.
1.5 Summary
• Every program must have one (and only one) function called main () .
• Compiling and linking a program is system dependent. In this book we use the
GNU C++ compiler and the command line
g++ example.cxx
1.6 Exercises
1. Our program to solve a quadratic equation is not very robust. Try to make the
program fail in as many different ways as possible. What would you like to do to
improve the program? (We haven't covered the techniques required to actually
carry out the necessary improvements yet.)
8 CHAPTER 1. INTRODUCTION
2. Using the quadratic equation program as a guide, write a short program that
reads a, band c from the keyboard and lists the results for a+b, b*c and a/c.
Again, you should be able to input data that causes your program to fail.
Chapter 2
The most basic study of any language is lexical; without knowing the rules for con-
structing words, we cannot begin to write books, or even to construct a single sentence.
Communication is impossible. Likewise, before we can write a meaningful C++ pro-
gram, we must learn the rules for constructing "words", or more correctly tokens.
A C++ program consists of one or more files, which contain a series of characters. The
details of how characters are represented internally are dependent on the C++ compiler,
but one byte per character is normal and one of the most popular representations, the
ASCII character set, is given in Appendix A.I The allowed characters are shown in
Table 2.1. A compiler resolves (or parses) the C++ program into a series of tokens.
There are five types of token: identifiers, keywords, constants, operators and other
separators.
1 A byte is the smallest addressable element of memory and is usually eight bits. Indeed, throughout
this book a byte is assumed to be synonymous with eight bits. A bit is the smallest element of memory
and can only take the values 0 and 1. Bits and bytes are considered in more detail in Chapter 11.
9
D. Capper, Introducing C++ for Scientists, Engineers and Mathematicians
© Springer-Verlag London 2001
10 CHAPTER 2. THE LEXICAL BASIS OF C++
II This is a comment.
x = 1; II The first part of this line is not a comment.
An alternative technique is to use 1* to indicate the start of a comment that continues
until *1 is encountered. Such comments can continue over many lines:
1* This is a comment *1
1* This
is
a
longer
comment *1
This restriction is a minor nuisance, since temporarily commenting out sections of code
by means of 1* *1 is very convenient, but cannot be used if the code already contains
1* *1 style comments. This is a good reason for only using the I I style of comment
in new code. However, an alternative technique for making the compiler temporarily
ignore sections of code is given in Section 4.13.3.
Notice that blanks are not allowed within the tokens defining either style of com-
ment:
In this example, everything between the first 1* and *1 is taken as a comment and, as
a result, a, band c have arbitrary values.
Comments, blanks, vertical and horizontal tabs, form feeds and new lines are col-
lectively known as white space. White space is not allowed in any token, except in
character or string constants. The compiler ignores any white space that occurs be-
tween tokens. Such white space is effectively a separator.
2.3 Identifiers
An identifier is a sequence of some combination of letters, digits and the underscore
symbol, _. Both upper and lower case characters are valid and are distinct. However, it
isn't a very good idea to rely on the case being the only distinguishing feature between
identifiers. In both C and C++ there is a tradition of using mainly lower case, except
where some special significance is being highlighted, as with a global constant. This
tradition makes for easily readable code.
The ANSI C++ Standard doesn't impose any maximum limit on the number of
characters in an identifier. Since real computers have finite resources your computer
will have some limit, but this is very unlikely to prove a problem.
An important restriction on identifiers is that they must start with a character or
underscore rather than a digit. Some examples of valid identifiers are:
main
cout
position_l
initial_velocity
_velocity
initial __ velocity
Both of these combinations are best avoided, since leading underscores and embedded
double underscores are often generated internally by compilers or used in libraries.
Likewise, it is worth avoiding trailing underscores:
velocity_
Apart from these minor restrictions, it is good programming practice to employ names
that are meaningful in the context in which they are used, such as:
12 CHAPTER 2. THE LEXICAL BASIS OF C++
water_temperature
instead of:
T12
Meaningful names make the code self-documenting and avoid the need for excessive
and distracting comments. While some programmers use an underscore to distinguish
different parts of an identifier, others prefer to use an upper case letter:
waterTemperature
You will probably find that you like one particular style and loath the other.
2.4 Keywords
Keywords are special identifiers that have a significance defined by the language rather
than the programmer. A complete but, at this stage, rather impenetrable list is given
in Table 2.2. You are not expected to memorize this list, rather it is given in order to
warn you to only use these keywords in ways that are defined by the language. 2
There are also some alternative representations of C++ operators. These are given
in Table 2.3 and should only be used as defined by the language. For reference, the
operators that they represent together with the section where they are introduced in
this book are also given.
A few other keywords that may be reserved for some compilers are:
and these are best avoided as user-defined identifiers in order to ensure portability.
For some compilers such keywords may have a leading underscore, as in -.near.
Examples of the valid use of keywords are:
int switch; II
Attempts to declare switch to be
II
an integer variable.
char class; II
Attempts to declare class to be
II
a character variable.
i n t i; II
White space is not allowed.
INT i', II Keywords must be lower case.
2.5 Constants
Constants, which are also known as literals, can be integer, Boolean, floating point,
character or string. More details of these four types are given in the next chapter, but
they are introduced here.
14768
but not:
14 CHAPTER 2. THE LEXICAL BASIS OF C++
024
Hexadecimal (base sixteen) integer constants start with Ox (or OX) and may include
the letters a to f (or A to F, the case is not significant) as, for example:
Ox7a1f
where the value following e (or E) is the exponent. Negative floating point numbers,
such as
is a character constant and is usually represented internally by one byte. Note that' l'
is not equal to the integer 1; for instance in the ASCII character set, '1' is actually
represented by 49. (See Appendix A for more detail.) Notice also that a character
constant has the form 'a', rather than 'a'.
Certain hard to get at characters are represented by using an escape sequence,
starting with a backslash; for instance '\n' signifies a new line. The complete list of
all such sequences is given in Table 2.4. The generalized escape sequence consists of
up to three octal or as many hexadecimal digits as are required. For instance, '\61'
and '\x31' both represent the character, '1'.
2.5. CONSTANTS 15
Exercise 3
To demonstrate that both' \61' and' \x31' represent the same character,
try the following simple program:
#include <iostream>
using namespace std;
int maine)
{
char a, b;
a = '\61';
b = '\x31';
cout « a « ' , « b « '\n';
return(O);
}
Hello World
2.6 Operators
An operator is a language-defined token, consisting of one or more characters, that
instructs the computer to perform some well-defined action. An example is the assign-
ment operator, =, used in the following:
0 [] -> typeid
->* & * dynamic_cast
++ I % static_cast
+ .* « » < reinterpret_cast
<= > >= != const cast
&& II 7: throw
+= *= 1= new
%= «= »= &= delete
1= sizeof
Notice that some keywords are also operators and that multi-character operators form
a single token. Once again it should be emphasized that white space is not allowed
within a token, meaning, for instance, that + = is not a valid operator, unlike +=.
However, in contrast to some languages, two operators can follow in succession; for
instance x * -1 is equivalent to x * (-1). More detail on most of these operators will
be given later in this book.
#include <iostream>
#include <cmath>
using namespace std;int main(){double xl,x2,a,b,c,root;cout
«"Enter the coefficients a, b, c: ";cin»a»b»c;root=
sqrt(b*b-4.0*a*c);xl=O.5*(root-b)/a;x2=-O.5*(root+b)/a;cout
«"The solutions are "«xl«" and "«x2«"\n";return(O);}
However, it is up to the programmer to adopt a clear style that can easily be understood
by others. There is no unique good style, but it is worth adopting something similar
2.8. SUMMARY 17
to that used in this book. In particular it is a good idea to keep to one statement
per line (except in special circumstances) and to indent by one tab to denote blocks
of code. With this in mind, it is worth adjusting the tab on your editor to four (or
perhaps three) characters per tab position. If you don't do this, your code will march
across the page too quickly. Further hints on style will be given when more of the C++
language has been introduced.
There is one final point that should be made in this chapter. Very occasionally there
may appear to be be an ambiguity as to how one or more lines of code are resolved
by the compiler into tokens. For instance, given that both -- and - are valid C++
operators, how should
be read? The compiler resolves this ambiguity by adopting a maximal munch strategy;5
the parsing stage of the compilation process bites off the largest sequence of characters
that form a valid token. So the example above really does mean:
x = (y--) - z;
It is a good idea to resolve such apparent ambiguities by using white space or paren-
theses.
2.8 Summary
• A C++ source file consists of a sequence of tokens that are made up of one or
more characters.
• White space (including blanks, new lines, tabs etc.) is not allowed within tokens.
• There are five types of token: identifiers, keywords, constants, operators and
other separators.
5S ee [6].
18 CHAPTER 2. THE LEXICAL BASIS OF C++
2.9 Exercises
1. How many different types of token are there? Classify the following tokens:
(a) 27
(b) 11,111
(c) 'Hello world'
(d) 'a'
(e) -3.1415926535897932
(f) '\t'
(g) 25L4
(h) '\032'
Chapter 3
c++ is a typed language; that is the variables and constants that occur in a program
each have a type and this controls how they may be used and what storage is required.
For example, variables of the int type, which are used to represent integers, may require
two bytes of memory, and variables of the float type, which are used to represent
floating point numbers, may need four bytes. Furthermore, the float and int types
are represented in memory in entirely different ways. The language-defined types that
are used to represent integers, Booleans, characters and floating point numbers are
known as fundamental types and are the concern of this chapter. 1 It is also possible to
define what are known as derived types in order to manipulate objects such as matrices,
complex numbers or 3-dimensional solids. 2 Techniques for creating derived types are
described in later chapters.
The motivation for using a typed language is that the compiler can catch many
programming errors by performing type-checking. For example, if an object is declared
to be constant (by using the const keyword, which is explained later in this chapter)
then an attempt to assign a value to the object is a compile-time error since it has the
wrong type for such operations.
In this chapter we examine all of the fundamental types defined by the C++ lan-
guage, together with some of the basic operators. This will enable us to carry out the
usual arithmetic operations and to manipulate characters. Compared with some lan-
guages, the fundamental types are rather limited; for instance, unlike Fortran, complex
numbers are not defined. Although this may seem a bit restrictive for many applica-
tions, derived types can effectively extend the language indefinitely. For example,
complex arithmetic is part of the ANSI C++ Standard Library. (See Section 17.3.l.)
19
D. Capper, Introducing C++ for Scientists, Engineers and Mathematicians
© Springer-Verlag London 2001
20 CHAPTER 3. FUNDAMENTAL TYPES AND BASIC OPERATORS
int i, j, k;
We say "define" rather than "declare"; in C++ the distinction is both subtle and
important. Defining an object, as above, not only specifies the type, but also reserves
the appropriate amount of memory. As will be seen later, it is possible to make a
declaration, such as
extern int i;
without reserving any memory (which must of course be done somewhere). In a com-
plete program there must be one (and only one) definition of an object, even though
there can be many declarations. It is worth emphasizing that, although an object may
be defined in the sense of memory being allocated, its "value" can still be arbitrary.
3The integer types are signed by default. It is therefore very rare and completely redundant to
have signed int, signed long or signed short.
3.1. INTEGRAL DATA TYPES 21
int i, j, k',
i l', II Notice that every statement
j 2', II ends with a semicolon.
k 3;
Addition and subtraction of integers are carried out using the usual + and - oper-
ators, as in:
int i, j, k',
i 1;
j 2;
k 3;
i i + j;
k k - i;
Notice that "=" is the assignment rather than equality operator, so the statement:
i = i + j;
means add the current values of i and j (1 and 2) and assign the result (3) to i. The
fact that "=" is the assignment operator means that expressions such as:
i + 1 = 7; II WRONG
which look mathematically respectable , are not correct C++ statements. Conversely,
some expressions that are valid in C++, would make no sense as mathematical equa-
tions. For example, in the above code fragment, the statement:
i = i + j;
does not imply that j is zero; in fact j is 3 in this context. It is also worth pointing
out that : = is not a valid assignment operator, nor even an operator:
Our short sequence of assignment statements does not form a complete C++ pro-
gram but , following the examples in Chapter 1, we can easily rectify this situation to
produce the following code:
k 3;
i i + j;
k k - i;
cout « "i " « i «" k " << k << "\n";
returneO);
}
Notice that mainO is a function that returns the int type and in this example we
return the value o. (More discussion of this return value is given later, but in some
circumstances it may be important for the operating system to know whether or not
the program has run successfully, as indicated by 0.) We also include a statement
so that the program can actually display the result of the calculations by using the
insertion operator to send the values of i and k to the output stream. The resulting
output is:
i =3 k =0
Exercise
Enter the above program into a file on your system, making sure the file
has the appropriate extension, such as . cxx. Then compile, link and run
the program. Check that you get the expected result. Try modifying the
program to add different combinations of integers.
Since the int type occupies a fixed and finite amount of memory, only a limited
range of integers can be stored. Consequently it is possible to perform operations which
mathematically would give results above the maximum value that can be represented
or below the minimum value. Such invalid operations are known respectively as integer
overflow and integer underflow. These are demonstrated in the following program:
#include <iostream>
#include <climits>
using namespace std;
int maine)
{
int i;
i = INT_MAX + 10; II Integer overflow.
cout « "i = " « i « "\n";
i = INT_MIN - 10; II Integer underflow.
cout « "i = " « i « "\n";
returneO);
}
INT_MAX and INT_MIN are the maximum and minimum values that can be stored by
the type int and are defined in the header file, <climits>. These values depend on
the particular compiler, as does the result of underflow or overflow.
Exercise
What values are given to i for these two statements on your system? Show
that your results are consistent with the values given in <climits>.
3.1. INTEGRAL DATA TYPES 23
#include <iostream>
using namespace std;
int main()
{
int i, j, k, m, n;
i 2;
j -3;
k -4;
m= i II Assigns -6 to m.
* j;
= j k·, II Assigns 12 to n.
n
*
i 3
* 6; II Assigns 18 to i.
cout « "m " « m « "\nn = " « n « "\ni " « i «
lI\n ll ;
return(O);
}
Exercise
Check that the above program gives the results you would expect on your
system.
int k;
k = 3 I 2;
which means divide 3 by 2 and put the result in k. Since 2 does not exactly divide
3, there is a potential ambiguity as to whether k is set to 1 or 2. In fact, in common
with most languages, the C++ result is 1; integer division with both numbers positive
always truncates. The same is true when both numbers are negative, so that -3 / -2
yields 1 rather than 2. If only one number is negative, then the result depends on
the compiler: -3 I 2 could give either -1 or -2. Relying on a feature provided by a
particular compiler is not good programming practice and should be avoided if at all
possible. (In general, if you do need to use a compiler-dependent feature, then you
should have a clear comment on this in your program.)
In mathematics, dividing any non-zero number by zero gives infinity and dividing
zero by zero is undefined; in C++, any integer division by zero is undefined.
For instance, 5 % 3 yields the value 2. If both i and j are negative then the result is
negative; that is -5 % -3 yields -2. If only one of i and j is negative, then the result is
again dependent on the C++ compiler, but should be consistent with the dependency
for division. That is:
(i I j) * j + i %j
should give the value of i. Again, if j is zero the result of i % j is not defined and
may not be consistent with the (undefined) result of i I j. (Saying that a piece of
code is "undefined" means that the C++ language definition doesn't say how it should
be interpreted.) Notice that 0 % j gives 0 for any (non-zero) integer, j.
Exercise
Tryout the following program for various values of i and j (positive, neg-
ative and zero) and explain the output. What happens if you enter a non-
sense value, such as "accidentally" hitting the w key instead of 2? Why?
#include <iostream>
using namespace std;
int main()
{
int i, j, m, n, a, b;
cout « "enter an integer: ";
cin » i;
cout « "enter an integer: ";
cin» j;
m = i I j;
n = i % j;
a = m
* j; II (i I j ) * j
b a + n; II (i I j) * j + i
cout « "i " « i «" j "« j « "\n\n" «
"i I j " « m« " i %j = " « n «
"\n\nThe following result should be " « i «
":\n" « " (i I j) * j + i % j = " « b « " \n" ;
return(O);
}
In this example we use the C++ input stream, cin, so that the values of i and j can
be entered from the keyboard. The expression:
cin » i;
extracts the value of i from the input stream. The operator, », is known as an
extraction operator. It is possible to concatenate such operators so that the first few
lines can be replaced by:
cout « "enter two integers: ";
cin » i » j;
but notice that the following is not equivalent:
cin » i, j; II WRONG!
The statement does compile, but no value is assigned to j when the program is run.
3.1. INTEGRAL DATA TYPES 25
i = i + 1;
we can use:
++i; II Prefix increment operator.
or:
i++; II Postfix increment operator.
In all three cases, i is increased by one. Whereas the prefix operator increments i by
one before the value of i is used, the postfix operator increments i after its value has
been used. Either version of the increment operator has the same effect in the above
code fragments, but note that this is not true for the following program:
#include <iostream>
using namespace std;
int mainO
{
int i, j, k, m, n;
i 2;
j i;
k 3;
m i++ I k; II Assigns 0 to m.
n = ++j I k; II Assigns 1 to n.
cout « tom " « m « "\nn " « n « "\ni " « i «
"\nj =" « j «"\n";
return(O);
}
Exercise
Modify the above program so that it reads i and k from the keyboard. Try
entering a few different values of i and k, and check that you get the results
you expect for m and n.
As might be expected, there are also prefix and postfix decrement operators so that:
--i;
and:
i--;
i = i - 1;
Whereas the prefix decrement operator decreases the value of i by one before it is used
in an expression, the postfix decrement operator decreases i after the value has been
used. The use of increment and decrement operators can lead to very compact code,
but it is worth exercising some restraint otherwise the code can get difficult to read.
Exercise
Replace the increment by decrement operators in your program for the
previous exercise.
++3.142; II WRONG!
10--; II WRONG!
In any case, it is difficult to imagine how such statements could be useful.
k = i * j; I I Valid C++.
rather than:
k = i *; II WRONG: where is the second operand?
The ++ and -- operators are both unary operators, that is they require a single operand:
++x; II Unary - operator takes only one operand.
The - operator can be both a binary operator, as in:
k = i - j; II Binary - operator.
or a unary operator, as in:
k = i + jim * n - k;
3.1. INTEGRAL DATA TYPES 27
the two concepts of associativity and precedence are used to determine the order in
which the evaluation is carried out. Operator precedence controls which operator in
an expression is applied first; the associativity determines the order in which operators
with the same precedence are applied. That is, the compiler first uses operator prece-
dence to determine the order of evaluations in an expression and then any remaining
ambiguities are removed by using operator associativity.
The properties of the operators introduced so far are given in Table 3.1. Notice
that the postfix increment and decrement operators have a higher precedence than the
prefix increment and decrement operators. All operators shown in the same group have
the same precedence and associativity, but a group higher up in the table has a higher
precedence than one further down. For example, in the expression: 4
the multiplication operator has the highest precedence and is applied first, yielding:
i =3 I 4 I 2;
is evaluated as:
i = (3 I 4) I 2;
rather than:
i = (3 * 2) I 4;
Any expression inside parentheses is evaluated first, which means that: 5
i = (1 - 2) * (3 + 4);
is reduced to:
i = -1 * 7;
which assigns -7 to i. If you are in doubt about the precedence of any operator, it is
always possible to use parentheses.
Exercise
Write a program to evaluate the following expressions:
i 2 I 3 + 3 I 2;
i 2 I 3 I 3;
i 3 I 2 % 7;
i 7 % 2 * 3;
i 7 I 2 * 3;
However, it is fairly common for a compiler to define both the int and long data types
to have the same four-byte representations. The limits for a particular compiler are
again given in the <climi ts> header file.
Notice that the keyword, long, is used to define (and declare) long integers. The
definition:
5When describing the four different bracket types, the common terminology employed is: paren-
theses for ( ), braces for { }, square brackets for [], and angle brackets for < >. Note that the various
brackets must always occur in pairs.
3.1. INTEGRAL DATA TYPES 29
long int i, j, k;
long i;
i = 1L;
short i, j, k·,
i 1·, II Can easily be represented by 2 bytes.
j 2; II Can easily be represented by 2 bytes.
k i - j;
However, if the representation is less than the natural size suggested by the hardware,
then there may be a performance penalty. It is best to avoid short integers unless there
is a very good reason to do otherwise. In any case, a compiler will often use the same
number of bytes for short as for into
Notice that the keyword, short, is used to define short integers. The equivalent
definition:
short int i, j, k;
#include <iostream>
#include <climits>
using namespace std;
int mainO
{
unsigned int i;
i = UINT_MAX;
i = i + 1;
cout « "UINT_MAX + 1 " « i « "\n";
i = i - 1;
30 CHAPTER 3. FUNDAJl.lENTAL TYPES AND BASIC OPERATORS
The program gets UINLMAX (the largest unsigned appropriate for the particular com-
piler) from the header file <climits>. Adding one to UINLMAX gives zero, and sub-
tracting one from zero gives UINT .11AX.
It is not usually worth using an unsigned rather than signed integral type just to
gain a higher upper limit on the positive integers that can be stored. An example of
the resulting possible pitfalls is given in Exercise 2 of Chapter 4; an example where
using an unsigned type is worthwhile appears in Section 11.4.1.
A U (or u) is used to denote an unsigned constant, as in:
unsigned int i;
unsigned long j;
i 1U;
j = 1UL;
Any combination of U, u and L, 1 m any order can be used for an uns igned long
constant.
3.1.10 Booleans
A Boolean can have one of two values, true or false. In C++, a Boolean is represented
by the bool data type, as in:
bool b1, b2;
b1 true;
b2 = false;
We can convert between the types bool and into By definition, true takes the value 1
on conversion to type int, and false takes the value O. The rule for the conversion of
type int to bool is that 0 is converted to false and any non-zero integer corresponds
to true. So the output from:
#include <iostream>
using namespace std;
int mainO
{
bool b1, b2;
b1 = true;
b2 = false;
cout « "b1 is " « b1 « "\n" «
"b2 is " « b2 « "\n";
return(O);
}
is:
b1 is 1
b2 is 0
The operators for Booleans are introduced in Section 4.2.
3.1. INTEGRAL DATA TYPES 31
Exercise
What does the above program output? Verify the answer on your system.
double pi, c;
pi 3.1415926535897932;
c = 2.997925e8;
where the floating point assignment operator is denoted by the token, =. The expression
for c is typical of a floating point number and may be split into three parts:
2 the integer part
997925 the fractional part
8 the exponent.
A decimal point separates the integer and fractional parts, while e (E is also valid)
separates the fractional part from the exponent. A floating point constant must contain
a decimal point or an exponent or both, since otherwise there would be nothing to
distinguish it from an integer. If there is a decimal point, then either an integer or a
fractional part must be present. If there is no decimal point, then there must be both
an integer part and an exponent (but there can be no fractional part of course). Some
examples of valid floating point assignments are:
double x, y, z;
x = 1.0;
Y 0.1;
z = lel0;
x = 1. lelO;
y lle9;
z = .11ell;
Apart from the use of e or E, all of this should be straightforward to anyone familiar
with scientific notation.
3.2. FLOATING POINT DATA TYPES 33
#include <iostream>
using namespace std;
int mainO
{
double x, y, z;
x = 3.1416; II ASSignment.
Y = -x; II Unary minus.
z = -3.1416; II Unary minus.
++x; II Increment (prefix version).
y--; II Decrement (postfix version).
x = x - 1.0; II Subtraction.
Y y+1.0; II Addition.
z = x * y; II Multiplication.
z = z I 3.1416; II Division.
cout « z « "\n";
return(O);
}
All of these operators have the same precedence and associativity as for the corre-
sponding integer versions. Notice that -3.1416 is actually an expression involving a
unary minus together with a double constant and that (as you might expect) floating
point division does not truncate to an integer, unlike integer division.
Exercise
What is the final result for z in the above code? Verify your answer by
running the program.
Only a finite subset of all floating point numbers can be represented by one of
the defined types, such as double. There are many ways of representing a floating
point number by a fixed number of bytes, but most C++ compilers conform to what
is known as the IEEE standard. For such compilers a double of eight bytes gives a
range of about 10- 308 to 10 308 and an accuracy of sixteen decimal places. More details
of how floating point numbers are represented by a computer are given in Chapter II.
For the present it is worth pointing out that in numerical calculations it is very easy to
attempt to generate a number whose absolute magnitude is too big to be represented
(causing floating point overflow) or too small (causing floating point underflow). It
is also possible to attempt to perform invalid operations, such as a divide by zero.
For a C++ compiler conforming to the IEEE standard, all such meaningless results
are flagged as NaNs (Not a Number). Once a NaN is created it propagates through
the calculation, ensuring that any meaningless final answers are also suitably flagged.
However, unless there is an appropriate compiler option, a NaN is not flagged when it
is generated. Such an option is invaluable for large numerical applications.
34 CHAPTER 3. FUNDAMENTAL TYPES AND BASIC OPERATORS
Unlike some other languages, such as FORTRAN, there is no operator for raising
a number (either integer or floating point) to a power. In C++, such operations are
carried out by a function call. For small integer powers it is, in any case, usually much
faster to use repeated multiplication, as in:
float pi, c;
pi = 3.142f;
c = 2.997ge8f;
A float constant is distinguished from its double counterpart by means of the suffix f
(or F). Omitting the f does not cause an error in the above examples, as the compiler
inserts a conversion from double to float. Such omissions are quite common. Notice
that the f is appended; it does not replace the e (or E):
A long double constant is distinguished from double and float by means of the
suffix, L. The letter 1 is also valid, but is probably best avoided since 1 looks too
similar to 1. 6 You do need to append the L (or 1) or else the constant will be read as a
6For the same reason, it is best to avoid using a single 1 as a user-defined identifier.
Another Random Scribd Document
with Unrelated Content
And so it was that the heart of Elizabeth the Queen warmed again,
and dearly, towards two Huguenot exiles, and showed that in doing
justice she also had not so sour a heart towards her sex as was set
down to her credit. Yet she made one further effort to keep De la
Forêt in her service. When Michel, once again, declined, dwelt
earnestly on his duty towards the widow of his dead chief, and
begged leave to share her exile in Jersey, Elizabeth said, “On my
soul, but I did not think there was any man on earth so careless of
princes’ honors!”
To this De la Forêt replied that he had given his heart and life to one
cause, and since Montgomery had lost all, even life, the least Michel
de la Forêt could do was to see that the woman who loved him be
not unprotected in the world. Also, since he might not at this present
fight for the cause, he could speak for it; and he thanked the Queen
of England for having shown him his duty. All that he desired was to
be quiet for a space somewhere in “her high Majesty’s good realm”
till his way was clear to him.
“You would return to Jersey, then, with our friend of Rozel?”
Elizabeth said, with a gesture towards Lemprière, who, now
recovered from his wound, was present at the audience.
De la Forêt inclined his head. “If it be your high Majesty’s pleasure.”
And Lemprière of Rozel said, “He would return with myself your
noble Majesty’s friend before all the world, and Buonespoir his ship
the Honeyflower.”
Elizabeth’s lips parted in a smile, for she was warmed with the luxury
of doing good, and she answered:
“I know not what the end of this will be, whether our loyal
Lemprière will become a pirate or Buonespoir a butler to my court;
but it is too pretty a hazard to forego in a world of chance. By the
rood, but I have never, since I sat on my father’s throne, seen black
so white as I have done this past three months. You shall have your
Buonespoir, good Rozel; but if he plays pirate any more—tell him this
from his Queen—upon an English ship, I will have his head, if I must
needs send Drake of Devon to overhaul him.”
That same hour the Queen sent for Angèle, and by no leave, save
her own, arranged the wedding-day, and ordained that it should take
place at Southampton, whither the Comtesse de Montgomery had
come on her way to Greenwich to plead for the life of Michel de la
Forêt and to beg Elizabeth to save her poverty, both of which things
Elizabeth did, as the annals of her life record.
After Elizabeth—ever self-willed—had declared her way about the
marriage ceremony, looking for no reply save that of silent
obedience, she made Angèle sit at her feet and tell her whole story
again from first to last. They were alone, and Elizabeth showed to
this young refugee more of her own heart than any other woman
had ever seen. Not by words alone, for she made no long story; but
once she stooped and kissed Angèle upon the cheek, and once her
eyes filled up with tears, and they dropped upon her lap unheeded.
All the devotion shown herself as a woman had come to naught; and
it may be that this thought stirred in her now. She remembered how
Leicester and herself had parted, and how she was denied all those
soft resources of regret which were the right of the meanest women
in her realm. For, whatever she might say to her Parliament and
people, she knew that all was too late—that she would never marry,
and must go childless and uncomforted to her grave. Years upon
years of delusion of her people, of sacrifice to policy, had at last
become a self-delusion, to which her eyes were not full opened yet—
she sought to shut them tight. But these refugees, coming at the
moment of her own struggle, had changed her heart from an ever-
growing bitterness to human sympathy. When Angèle had ended her
tale once more the Queen said:
“God knows ye shall not linger in my court. Such lives have no place
here. Get you back to my Isle of Jersey, where ye may live in peace.
Here all is noise, self-seeking, and time-service. If ye twain are not
happy I will say the world should never have been made.”
Before they left Greenwich Palace—M. Aubert and Angèle, De la
Forêt, Lemprière, and Buonespoir—the Queen made Michel de la
Forêt the gift of a chaplaincy to the crown. To Monsieur Aubert she
gave a small pension, and in Angèle’s hands she placed a deed of
dower worthy of a generosity greater than her own.
At Southampton Michel and Angèle were married by royal license,
and with the Comtesse de Montgomery set sail in Buonespoir’s boat,
the Honeyflower, which brought them safe to St. Helier’s, in the Isle
of Jersey.
XX
OLLOWED several happy years for Michel and
Angèle. The protection of the Queen herself, the
chaplaincy she had given De la Forêt, the
friendship with the governor of the island, and
the boisterous tales Lemprière had told of those
days at Greenwich Palace quickened the
sympathy and held the interest of the people at
large, while the simple lives of the two won their way into the hearts
of all, even, at last, to that of De Carteret of St. Ouen’s. It was
Angèle herself who brought the two seigneurs together at her own
good table; and it needed all her tact on that occasion to prevent
the ancient foes from drinking all the wine in her cellar.
There was no parish in Jersey that did not know their goodness, but
mostly in the parishes of St. Martin’s and Rozel were their faithful
labors done. From all parts of the island people came to hear Michel
speak, though that was but seldom; and when he spoke he always
wore the sword the Queen had given him and used the Book he had
studied in her palace. It was to their home that Buonespoir the
pirate—faithful to his promise to the Queen that he would harry
English ships no more—came wounded, after an engagement with a
French boat sent to capture him, carried thither by Shadrach,
Meshach, and Abednego. It was there he died, after having drunk a
bottle of St. Ouen’s muscadella, brought secretly to him by his
unchanging friend Lemprière, so hastening the end.
The Comtesse de Montgomery, who lived in a cottage near by, came
constantly to the little house on the hill-side by Rozel Bay. She had
never loved her own children more than she did the brown-haired
child with the deep-blue eyes which was the one pledge of the great
happiness of Michel and Angèle.
Soon after this child was born M. Aubert had been put to rest in St.
Martin’s churchyard, and there his tombstone might be seen so late
as a hundred years ago. So things went softly by for seven years,
and then Madame de Montgomery journeyed to England, on
invitation of the Queen and to better fortune, and Angèle and De la
Forêt were left to their quiet life in Jersey. Sometimes this quiet was
broken by bitter news from France of fresh persecution and fresh
struggle on the part of the Huguenots. Thereafter for hours,
sometimes for days, De la Forêt would be lost in sorrowful and
restless meditation; and then he fretted against his peaceful calling
and his uneventful life. But the gracious hand of his wife and the
eyes of his child led him back to cheerful ways again.
Suddenly one day came the fearful news from England that the
plague had broken out and that thousands were dying. The flight
from London was like the flight of the children of Israel into the
desert. The dead-carts, filled with decaying bodies, rattled through
the foul streets, to drop their horrid burdens into the great pit at
Aldgate; the bells of London tolled all day and all night for the
passing of human souls. Hundreds of homes, isolated because of a
victim of the plague found therein, became ghastly breeding-places
of the disease, and then silent, disgusting graves. If a man shivered
in fear or staggered from weakness, or for very hunger turned sick,
he was marked as a victim, and despite his protests was huddled
away with the real victims to die the awful death. From every
church, where clergy were left to pray, went up the cry for salvation
from “plague, pestilence, and famine.” Scores of ships from Holland
and from France lay in the Channel, not allowed to touch the shores
of England nor permitted to return whence they came. On the very
day that news of this reached Jersey came a messenger from the
Queen of England for Michel de la Forêt to hasten to her court, for
that she had need of him, and need which would bring him honor.
Even as the young officer who brought the letter handed it to De la
Forêt in the little house on the hill-side above Rozel Bay, he was
taken suddenly ill and fell at the Camisard’s feet.
De la Forêt straightway raised him in his arms. He called to his wife,
but, bidding her not come near, he bore the doomed man away to
the lonely Ecréhos rocks lying within sight of their own doorway.
Suffering no one to accompany him, he carried the sick man to the
boat which had brought the Queen’s messenger to Rozel Bay. The
sailors of the vessel fled, and alone De la Forêt set sail for the
Ecréhos.
There, upon the black rocks, the young man died, and Michel buried
him in the shore-bed of the Maître Île. Then, after two days—for he
could bear suspense no longer—he set sail for Jersey. Upon that
journey there is no need to dwell. Any that hath ever loved a woman
and a child must understand. A deep fear held him all the way, and
when he stepped on shore at Rozel Bay he was as one who had
come from the grave, haggard and old.
Hurrying up the hill-side to his doorway, he called aloud to his wife,
to his child. Throwing open the door, he burst in. His dead child lay
upon a couch, and near by, sitting in a chair, with the sweat of the
dying on her brow, was Angèle. As he dropped on his knee beside
her, she smiled and raised her hand as if to touch him, but the hand
dropped and the head fell forward on his breast. She was gone into
a greater peace.
Once more Michel made a journey—alone—to the Ecréhos, and
there, under the ruins of the old Abbey of Val Richer, he buried the
twain he had loved. Not once in all the terrible hours had he shed a
tear; not once had his hand trembled; his face was like stone and his
eyes burned with an unearthly light.
He did not pray beside the graves. But he knelt and kissed the earth
again and again. He had doffed his robes of peace, and now wore
the garb of a soldier, armed at all points fully. Rising from his knees,
he turned his face towards Jersey.
“Only mine! Only mine!” he said, aloud, in a dry, bitter voice.
In the whole island, only his loved ones had died of the plague. The
holiness and charity and love of Michel and Angèle had ended so!
When once more he set forth upon the Channel, he turned his back
on Jersey and shaped his course towards France, having sent
Elizabeth his last excuses for declining a service which would have
given him honor, fame, and regard. He was bent upon a higher duty.
Not long did he wait for the death he craved. Next year, in a
Huguenot sortie from Anvers, he was slain.
He died with these words on his lips:
“Maintenant, Angèle!”
In due time the island people forgot them both, but the Seigneur of
Rozel caused a stone to be set up on the highest point of land that
faces France, and on the stone were carved the names of Michel and
Angèle. Having done much hard service for his country and for
England’s Queen, Lemprière at length hung up his sword and gave
his years to peace. From the Manor of Rozel he was wont to repair
constantly to the little white house, which remained as the two had
left it—his own by order of the Queen—and there, as time went on,
he spent most of his days. To the last he roared with laughter if ever
the name of Buonespoir was mentioned in his presence; he
swaggered ever before the royal court and De Carteret of St. Ouen’s;
and he spoke proudly of his friendship with the Duke’s Daughter,
who had admired the cut of his jerkin at the court of Elizabeth. But
in the house where Angèle had lived he moved about as though in
the presence of a beloved sleeper he would not awake.
Michel and Angèle had had their few years of exquisite life and love,
and had gone; Lemprière had longer measure of life and little love,
and who shall say which had more profit of breath and being? The
generations have passed away, and the Angel of Equity hath a
smiling pity as she scans the scales and the weighing of the past.
THE END
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside
the United States, check the laws of your country in addition to
the terms of this agreement before downloading, copying,
displaying, performing, distributing or creating derivative works
based on this work or any other Project Gutenberg™ work. The
Foundation makes no representations concerning the copyright
status of any work in any country other than the United States.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if
you provide access to or distribute copies of a Project
Gutenberg™ work in a format other than “Plain Vanilla ASCII” or
other format used in the official version posted on the official
Project Gutenberg™ website (www.gutenberg.org), you must,
at no additional cost, fee or expense to the user, provide a copy,
a means of exporting a copy, or a means of obtaining a copy
upon request, of the work in its original “Plain Vanilla ASCII” or
other form. Any alternate format must include the full Project
Gutenberg™ License as specified in paragraph 1.E.1.
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.F.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
ebookbell.com