We're always interested in getting feedback. E-mail us if you like
this guide, if you think that important material is omitted, if you
encounter errors in the code examples or in the documentation, if you
find any typos, or generally just if you feel like e-mailing. Mail to
Frank Brokken
or use an
e-mail form.
Please state the concerned document version, found in
the title. If you're interested in a printable
PostScript copy, use the
form, or
better yet,
pick up your own copy by ftp
from ftp.icce.rug.nl/pub/http.
cout
, analogous to stdout
,
cin
, analogous to stdin
,
cerr
, analogous to stderr
.
Syntactically these streams are not used with functions: instead, data are
read from the streams or written to them using the operators <<
, called
the insertion operator and >>
, called the extraction operator.
This is illustrated in the example below:
This program reads a number and a string from the cin
stream (usually the
keyboard) and prints these data to cout
. Concerning the streams and their
usage we remark the following:
iostream.h
.
cout
, cin
and cerr
are in fact `objects'
of a given class (more on classes later), processing the input and
output of a program. Note that the term `object', as used here, means the
set of data and functions which defines the item in question.
cin
reads data and copies the information to
variables (e.g., ival
in the above example) using the extraction
operator >>
. We will describe later how operators in C++
can perform quite different actions than what they are defined to do by the
language grammar, such as is the case here. We've seen function
overloading. In C++ operators can also have multiple
definitions, which is called operator overloading.
cin
, cout
and cerr
(i.e., >>
and <<
) also manipulate variables of
different types. In the above example cout << ival
results in the
printing of an integer value, whereas cout << "Enter a number"
results in the printing of a string. The actions of the operators
therefore depend on the type of supplied variables.
cout
is realized by inserting the
endl
symbol, rather than using the string "\n"
.
The streams cin
, cout
and cerr
are not part of C++ grammar
sec, as defined in the compiler which parses source files. The streams
are part of the definitions in the header file iostream.h
. This is
comparable to the fact that functions as printf()
are not part of the
C grammar, but were originally written by people who considered such
functions handy and collected them in a run-time library.
Whether a program uses the old-style functions like printf()
and
scanf()
or whether it employs the new-style streams is a matter of taste.
Both styles can even be mixed. A number of advantages and disadvantages is
given below:
C
functions printf()
and
scanf()
, the usage of the insertion and extraction operators
is more type-safe
.
The format strings which are used with printf()
and
scanf()
can define wrong format specifiers for their arguments,
for which the compiler sometimes can't warn. In contrast, argument
checking with cin
, cout
and cerr
is performed
by the compiler. Consequently it isn't possible to err by providing an
int
argument in places where, according to the format string, a string
argument should appear.
printf()
and scanf()
, and other
functions which use format strings, in fact implement a mini-language
which is interpreted at run-time. In contrast, the C++
compiler
knows exactly which
in- or output action to perform given which
argument.
C++
.
Again, it requires a little getting used to, coming from C,
but after that these overloaded operators feel rather comfortably.
The iostream library has a lot more to offer than just cin, cout
and
cerr
. In section 12 iostreams will be covered in greater
detail.
const
very often occurs in C++ programs, even though it
is also part of the C grammar, where it's much less used.
This keyword is a modifier which states that the value of a variable or of an
argument may not be modified. In the below example an attempt is made to
change the value of a variable ival
, which is not legal:
This example shows how ival
may be initialized to a given value in its
definition; attempts to change the value later (in an assignment) are not
permitted.
Variables which are declared const
can, in contrast to C, be used as
the specification of the size of an array, as in the following example:
A further usage of the keyword const
is seen in the declaration of
pointers, e.g., in pointer-arguments. In the declaration
buf
is a pointer variable, which points to char
s. Whatever is
pointed to by buf
may not be changed: the char
s are declared as
const
. The pointer buf
itself however may be changed. A statement as
*buf = 'a';
is therefore not allowed, while buf++
is.
In the declaration
buf
itself is a const
pointer which may not be changed. Whatever
char
s are pointed to by buf
may be changed at will.
Finally, the declaration
is also possible; here, neither the pointer nor what it points to may be changed.
The rule of thumb for the placement of the keyword const
is the
following: whatever occurs just prior to the keyword may not be changed.
The definition or declaration in which const
is used should be read
from the variable or function identifier back to the type indentifier:
``Buf is a const pointer to const characters''This rule of thumb is especially handy in cases where confusion may occur. In examples of C++ code, one often encounters the reverse:
const
preceding what should not be altered. That this may result in sloppy
code is indicated by our second example above:
What must remain constant here? According to the sloppy interpretation, the
pointer cannot be altered (since const
precedes the pointer-*). In fact,
the charvalues are the constant entities here, as will be clear when it is
tried to compile the following program:
Compilation fails on the statement *buf = 'u';
, not on the statement
buf++
.
In the above example a variable int_value
is defined. Subsequently a
reference ref
is defined, which due to its initialization addresses the
same memory location which int_value
occupies. In the definition of
ref
, the reference operator &
indicates that ref
is not
itself an integer but a reference to one. The two statements
have the same effect, as expected. At some memory location an int
value
is increased by one --- whether that location is called int_value
or
ref
does not matter.
References serve an important function in C++ as a means to pass arguments
which can be modified (`variable arguments' in Pascal-terms). E.g., in
standard C, a function which increases the value of its argument by five
but which returns nothing (void
), needs a pointer argument:
This construction can also be used in C++ but the same effect can be achieved using a reference:
The way in which C++ compilers implement references is actually by
using pointers: in other words, references in C++ are just ordinary
pointers, as far as the compiler is concerned. However, the programmer does
not need to know or to bother about levels of indirection. (Compare
this to the Pascal way: an argument which is declared as var
is in fact
also a pointer, but the programmer needn't know.)
It can be argued whether code such as the above is clear: the statement
increase
(x)
in the main()
function suggests that not x
itself but a copy is passed. Yet the value of x
changes because of
the way increase()
is defined.
Our suggestions for the usage of references as arguments to functions are therefore the following:
struct
, is passed as argument, or is returned from the function.
In these cases the copying operations tend to become
significant factors when the entire structure must be copied, and it is
preferred to use references. If the argument isn't changed by the
function, or if the caller shouldn't change the returned information,
the use of the const
keyword is appropriate and should be used.
Consider the following example:
References also can lead to extremely `ugly' code. A function can also return a reference to a variable, as in the following example:
This allows the following constructions:
It is probably superfluous to note that such constructions should not normally
be used. Nonetheless, there are situations where it is useful to return a
reference. Even though this is discussed later, we have seen an example
of this phenomenon at our previous discussion of the iostreams. In a
statement like cout << "Hello" << endl;
, the insertion operator returns
a reference to cout
. So, in this statement first the "Hello"
is
inserted into cout
, producing a reference to cout
. Via this reference
the endl
is then inserted in the cout
object, again producing a
reference to cout
. This latter reference is not further used.
A number of differences between pointers and references is pointed out in the list below:
int &ref;
is not allowed; what would ref
refer to?
external
.
These references were initialized elsewhere.
&
is used with a reference,
the expression yields the address of the variable to which the reference
applies. In contrast, ordinary pointers are variables themselves, so the
address of a pointer variable has nothing to do with the address of the
variable pointed to.
struct
s (see
section 2.4.12). Such functions are called member
functions or methods.
This section discusses the actual definition of such functions.
The code fragment below illustrates a struct
in which data fields for a
name and address are present. A function print()
is included in the
struct
definition:
The member function print()
is defined using the structure name
(person
) and the scope resolution operator (::
):
In the definition of this member function, the function name is preceded by
the struct
name followed by ::
. The code of the function shows how
the fields of the struct
can be addressed without using the type name: in
this example the function print()
prints a variable name
. Since
print()
is a part of the struct
person
, the variable name
implicitly refers to the same type.
The usage of this struct
could be, e.g.:
The advantage of member functions lies in the fact that the called function
can automatically address the data fields of the structure for which it was
invoked. As such, in the statement p.print()
the structure p
is the
`substrate': the variables name
and address
which are used in the
code of print()
refer to the same struct p
.
C++ has two special keywords which are concerned with data hiding:
private
and public
. These keywords can be inserted in the definition
of a struct
. The keyword public
defines all subsequent fields of a
structure as accessible by all code; the keyword private
defines all
subsequent fields as only accessible by the code which is part of the
struct
(i.e., only accessible for the member functions) (Besides
public
and private
, C++ defines the keyword protected
.
This keyword is not often used and it is left for the reader to
explore.). In a struct
all fields are public
, unless
explicitly stated otherwise.
With this knowledge we can expand the struct
person
:
The data fields name
and address
are only accessible for the member
functions which are defined in the struct
: these are the functions
setname()
, setaddress()
etc.. This property of the data type is
given by the fact that the fields name
and address
are preceded by
the keyword private
. As an illustration consider the following code
fragment:
The concept of data hiding is realized here in the following manner. The
actual data of a struct
person
are named only in the structure
definition. The data are accessed by the outside world by special functions,
which are also part of the definition. These member functions control all
traffic between the data fields and other parts of the program and are
therefore also called `interface' functions.
The data hiding which is thus realized is illustrated further in
figure 2.
Two examples of member functions of the struct
person
are shown
below:
In general, the power of the member functions and of the concept of data
hiding lies in the fact that the interface functions can perform special
tasks, e.g., checks for the validity of data. In the above example
setname()
copies only up to 79 characters from its argument to the data
member name
, thereby avoiding array boundary overflow.
Another example of the concept of data hiding is the following. As an
alternative to member functions which keep their data in memory (as do the
above code examples), a runtime library could be developed with interface
functions which store their data on file. The conversion of a program which
stores person
structures in memory to one that stores the data on disk
would mean the relinking of the program with a different library.
Though data hiding can be realized with structs
, more often (almost
always) classes are used instead. A class
is in principle equivalent to a
struct
except that unless specified otherwise, all members (data or
functions) are private
. As far as private
and public
are
concerned, a class
is therefore the opposite of a struct
. The
definition of a class
person
would therefore look exactly as shown
above, except for the fact that instead of the keyword struct
, class
would be used. Our typographic suggestion for class names is a capital as
first character, followed by the remainder of the name in lower case (e.g.,
Person
).
struct
s are concerned. In C it is
common to define several functions to process a struct
, which then
require a pointer to the struct
as one of their arguments. A fragment
of an imaginary C header file is given below:
In C++, the declarations of the involved functions are placed inside the
definition of the struct
or class
. The argument which denotes which
struct
is involved is no longer needed.
The struct
argument is implicit in C++. A function call in C
like
becomes in C++: