0% found this document useful (0 votes)
19 views

C Language Tutorial

The document is a tutorial on the C++ programming language that begins with an introductory "Hello World" program. It contains 6 sections that cover basics of C++, control structures, compound data types, object oriented programming, advanced concepts, and the C++ standard library. The first part walks through the "Hello World" program line-by-line to explain core C++ concepts like comments, preprocessor directives, namespaces, functions, and output streams. It notes that while code is structured across multiple lines for readability, C++ only requires statements to end with semicolons.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views

C Language Tutorial

The document is a tutorial on the C++ programming language that begins with an introductory "Hello World" program. It contains 6 sections that cover basics of C++, control structures, compound data types, object oriented programming, advanced concepts, and the C++ standard library. The first part walks through the "Hello World" program line-by-line to explain core C++ concepts like comments, preprocessor directives, namespaces, functions, and output streams. It notes that while code is structured across multiple lines for readability, C++ only requires statements to end with semicolons.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 184

C+ + La n gu a ge Tu t or ia l

Ju a n Sou lie
Apr 24, 2007
These t ut orials explain t he C+ + language from it s basics
up t o t he newest feat ures of ANSI - C+ + , including basic
concept s such as arrays or classes and advanced
concept s such as polym orphism or t em plat es. The t ut orial
is orient ed in a pract ical way, wit h working exam ple
program s in all sect ions t o st art pract icing each lesson
right away.

I . Ba sics of C+ +

1 St r u ct u r e of a Pr ogr a m ( p. 1)
2 Va r ia ble s. D a t a Type s. ( p. 6)
3 Con st a n t s ( p. 14)
4 Ope r a t or s ( p. 19)
5 Ba sic I n pu t / Ou t pu t ( p. 29)

I I . Con t r ol St r u ct u r e s

6 Con t r ol St r uct u r e s ( p. 35)


7 Fu n ct ion s ( I ) ( p. 44)
8 Fu n ct ion s ( I I ) ( p. 50)

I I I . Com pou n d D a t a Type s

9 Ar r a ys ( p. 58)
10 Ch a r a ct e r Se qu e n ce s ( p. 65)
11 Poin t e r s ( p. 69)
12 D yn a m ic M e m or y ( p. 83)
13 D a t a St r u ct u r e s ( p. 88)
14 Ot h e r D a t a Type s ( p. 95)

I V. Obj e ct Or ie n t e d Pr ogr a m m in g

15 Cla sse s ( I ) ( p. 100)


16 Cla sse s ( I I ) ( p. 111)
17 Fr ie n dsh ip a n d I n h e r it a n ce ( p. 117)
18 Polym or ph ism ( p. 126)
19 Te m pla t e s ( p. 134)

V . Adva n ce d Con ce pt s

20 N a m e spa ce s ( p. 143)
21 Ex ce pt ions ( p. 147)
22 Type Ca st in g ( p. 152)
23 Pr e pr oce ssor D ir e ct ive s ( p. 159)

VI . C+ + St a n da r d Libr a r y

2 4 I n pu t / Ou t pu t w it h File s ( p. 165)

Appendixes
2 5 Ascii Code s ( p. 175)
2 6 Boole a n Ope r a t ion s ( p. 177)
2 7 N u m e r ica l Ba se s ( p. 179)
-1-

Basics of C+ + :

1 . St r u ct u r e of a Pr ogr a m
Published by Ju a n Sou lie
Apr 24, 2007

Probably t he best way t o st art learning a program m ing


language is by writ ing a program .
Therefore, here is our first program :

// my first program in C++

#include <iostream>
using namespace std;

int main ()
{
cout << "Hello World!";
system("PAUSE"); // for DevC++
return 0;
}
Hello World!

The first panel shows t he source code for our first program .
The second one shows t he result of t he program once
com piled and execut ed. The way t o edit and com pile a
program depends on t he com piler you are using. Depending
on whet her it has a Developm ent I nt er face or not and on
it s version. Consult t he com pilers sect ion and t he m anual or
help included wit h your com piler if you have doubt s on how
t o com pile a C+ + console program .

The previous program is t he t ypical program t hat


program m er apprent ices writ e for t he first t im e, and it s
result is t he print ing on screen of t he " Hello World! "
sent ence. I t is one of t he sim plest program s t hat can be
writ t en in C+ + , but it already cont ains t he fundam ent al
com ponent s t hat every C+ + program has. We are going
t o look line by line at t he code we have j ust writ t en:

// my first program in C++


This is a com m ent line. All lines beginning wit h t wo
slash signs ( //) are considered com m ent s and do
not have any effect on t he behavior of t he program .
The program m er can use t hem t o include short
explanat ions or observat ions wit hin t he source code
it self. I n t his case, t he line is a brief descript ion of
what our program is.

#include <iostream>
Lines beginning wit h a pound sign ( #) are direct ives
for t he prepr ocessor. They are not regular code
-2-

lines wit h expressions but indicat ions for t he


com piler's preprocessor. I n t his case t he direct ive
#include <iostream> t ells t he preprocessor t o
include t he iost ream st andard file. This specific file
( iost ream ) includes t he declarat ions of t he basic
st andard input - out put library in C+ + , and it is
included because it s funct ionalit y is going t o be
used lat er in t he program .

using namespace std;


All t he elem ent s of t he st andard C+ + library are
declared wit hin what is called a nam espace, t he
nam espace wit h t he nam e st d. So in order t o access
it s funct ionalit y we declare wit h t his expression
t hat we will be using t hese ent it ies. This line is
very frequent in C+ + program s t hat use t he
st andard library, and in fact it will be included
in m ost of t he source codes included in t hese
t ut orials.

int main ()
This line corresponds t o t he beginning of t he
definit ion of t he m ain funct ion. The m ain funct ion
is t he point by where all C+ + program s st art t heir
execut ion, independent ly of it s locat ion w it hin t he
source code. I t does not m at t er whet her t here are
ot her funct ions wit h ot her nam es defined before
or aft er it - t he inst ruct ions cont ained w it hin t his
funct ion's definit ion will always be t he first ones t o
be execut ed in any C+ + program . For t hat sam e
reason, it is essent ial t hat all C+ + program s have
a main funct ion.

The word main is followed in t he code by a pair of


parent heses ( ()) . That is because it is a funct ion
declarat ion: I n C+ + , what different iat es a funct ion
declarat ion from ot her t ypes of expressions are
t hese par ent heses t hat follow it s nam e. Opt ionally,
t hese par ent heses m ay enclose a list of param et er s
wit hin t hem .

Right aft er t hese parent heses we can find t he body


of t he m ain funct ion enclosed in braces ( {}) . What
is cont ained wit hin t hese braces is what t he funct ion
does when it is execut ed.

cout << "Hello World";


This line is a C+ + st at em ent . A st at em ent is a
sim ple or com pound expr ession t hat can act ually
produce som e effect . I n fact , t his st at em ent
perform s t he only act ion t hat generat es a visible
effect in our first program .

cout represent s t he st andard out put st ream in


C+ + , and t he m eaning of t he ent ire st at em ent is t o
insert a sequence of charact ers ( in t his case t he
Hello World sequence of charact ers) int o t he
st andard out put st ream ( which usually is t he screen) .

cout is declared in t he iostream st andard file


wit hin t he std nam espace, so t hat 's why we needed
-3-

t o include t hat specific file and t o declare t hat we


were going t o use t his specific nam espace earlier
in our code.

Not ice t hat t he st at em ent ends wit h a sem icolon


charact er ( ;) . This charact er is used t o m ark t he
end of t he st at em ent and in fact it m ust be included
at t he end of all expression st at em ent s in all C+ +
program s ( one of t he m ost com m on synt ax errors
is indeed t o forget t o include som e sem icolon
aft er a st at em ent ) .

return 0;
The ret urn st at em ent causes t he m ain funct ion t o
finish. ret urn m ay be followed by a ret urn code
( in our exam ple is followed by t he ret urn code 0) .
A ret urn code of 0 for t he m ain funct ion is generally
int erpret ed as t he program worked as expect ed
wit hout any errors during it s execut ion. This is t he
m ost usual way t o end a C+ + console program .

You m ay have not iced t hat not all t he lines of t his program
perform act ions when t he code is execut ed. There w ere lines
cont aining only com m ent s ( t hose beginning by //) . There
were lines wit h direct ives for t he com piler's preprocessor
( t hose beginning by #) . Then t here were lines t hat began
t he declarat ion of a funct ion ( in t his case, t he m ain funct ion)
and, finally lines wit h st at em ent s ( like t he insert ion int o
cout) , which were all included wit hin t he block delim it ed
by t he braces ( {}) of t he m ain funct ion.

The program has been st r uct ured in different lines in order


t o be m ore readable, but in C+ + , we do not have st rict
rules on how t o separat e inst ruct ions in different lines.
For exam ple, inst ead of

int main ()
{
cout << " Hello World ";
return 0;
}

We could have writ t en:

int main () { cout << "Hello World"; return 0; }

All in j ust one line and t his would have had exact ly t he
sam e m eaning as t he prev ious code.

I n C+ + , t he separat ion bet ween st at em ent s is specified


wit h an ending sem icolon ( ;) at t he end of each one, so
t he separat ion in different code lines does not m at t er at
all for t his purpose. We can writ e m any st at em ent s per line
or writ e a single st at em ent t hat t akes m any code lines.
The division of code in different lines serves only t o m ake
it m ore legible and schem at ic for t he hum ans t hat m ay
read it .
-4-

Let us add an addit ional inst ruct ion t o our first program :

// my second program in C++

#include <iostream>

using namespace std;

int main ()
{
cout << "Hello World! ";
cout << "I'm a C++ program";
return 0;
}
Hello World! I'm a C++ program

I n t his case, we perform ed t wo insert ions int o cout in t wo


different st at em ent s. Once again, t he separat ion in
different lines of code has been done j ust t o give great er
readabilit y t o t he program , since main could have been
perfect ly valid defined t his way:

int main () { cout << " Hello World! ";


cout << " I'm a C++ program ";
return 0; }

We were also free t o divide t he code int o m ore lines if we


considered it m ore convenient :

int main ()
{
cout <<
"Hello World!";
cout
<< "I'm a C++ program";
return 0;
}

And t he result would again have been exact ly t he sam e


as in t he previous exam ples.

Preprocessor direct ives ( t hose t hat begin by #) are out of


t his general rule since t hey are not st at em ent s. They are
lines read and processed by t he prepr ocessor and do not
produce any code by t hem selves. Preprocessor direct ives
m ust be specified in t heir own line and do not have t o end
wit h a sem icolon ( ;) .

Com m e n t s
Com m ent s are part s of t he source code disregarded by t he
com piler. They sim ply do not hing. Their purpose is only t o
allow t he program m er t o insert not es or descript ions
em bedded wit hin t he source code.
-5-

C+ + support s t wo ways t o insert com m ent s:

// line comment
/* block comment */

The first of t hem , known as line com m ent , discards


everyt hing from where t he pair of slash signs ( //) is found
up t o t he end of t hat sam e line. The second one, known as
block com m ent , discards everyt hing bet ween t he
/* charact er s and t he first appearance of t he */ charact ers,
wit h t he possibilit y of including m ore t han one line.
We are going t o add com m ent s t o our second program :

/* my second program in C++


with more comments */

#include <iostream>
using namespace std;

int main ()
{
cout << "Hello World! ";

// prints Hello World!


cout << "I'm a C++ program";

// prints I'm a C++ program


return 0;
}
Hello World! I'm a C++ program

I f you include com m ent s wit hin t he source code of your


program s wit hout using t he com m ent charact ers
com binat ions //, /* or */, t he com piler will t ake t hem as
if t hey were C+ + expressions, m ost likely causing one or
several error m essages when you com pile it .
-6-

Basics of C+ + :

2 . Va r ia ble s. D a t a Type s.

The usefulness of t he " Hello World" program s shown in t he


previous sect ion is quit e quest ionable. We had t o w rit e
several lines of code, com pile t hem , and t hen execut e t he
result ing program j ust t o obt ain a sim ple sent ence writ t en
on t he screen as result . I t cert ainly would have been m uch
fast er t o t ype t he out put sent ence by ourselves. However,
program m ing is not lim it ed only t o print ing sim ple t ext s on
t he screen. I n order t o go a lit t le furt her on and t o becom e
able t o writ e program s t hat perform useful t asks t hat really
save us work we need t o int roduce t he concept of variable.

Let us t hink t hat I ask you t o ret ain t he num ber 5 in your
m ent al m em ory, and t hen I ask you t o m em orize also t he
num ber 2 at t he sam e t im e. You have j ust st ored t w o
different values in your m em ory. Now, if I ask you t o
add 1 t o t he first num ber I said, you should be ret aining
t he num bers 6 ( t hat is 5+ 1) and 2 in your m em ory. Values
t hat we could now for exam ple subt ract and obt ain 4
as result .

The whole process t hat you have j ust done wit h your
m ent al m em ory is a sim ile of what a com put er can do wit h
t wo variables. The sam e process can be expressed in C+ +
wit h t he following inst ruct ion set :

a = 5;
b = 2;
a = a + 1;
result = a - b;

Obviously, t his is a very sim ple exam ple since we have


only used t wo sm all int eger values, but consider t hat your
com put er can st ore m illions of num bers like t hese at t he
sam e t im e and conduct sophist icat ed m at hem at ical
operat ions wit h t hem .

Therefore, we can define a variable as a port ion of


m em ory t o st ore a det erm ined value.

Each variable needs an ident ifier t hat dist inguishes it from


t he ot hers, for exam ple, in t he previous code t he variable
ident ifiers were a, b and result, but we could have called
t he variables any nam es we want ed t o invent , as long as
t hey were valid ident ifiers.

I de n t ifie r s
-7-

A valid ident ifier is a sequence of one or m ore let t ers,


digit s or underscore char act ers ( _) . Neit her spaces nor
punct uat ion m arks or sym bols can be part of an ident ifier.
Only let t ers, digit s and single underscore charact ers are
valid. I n addit ion, variable ident ifiers always have t o
begin wit h a let t er. They can also begin wit h an underline
charact er ( _ ) , but in som e cases t hese m ay be reserved
for com piler specific keywords or ext er nal ident ifiers,
as well as ident ifiers cont aining t wo successive
underscore charact ers anywhere. I n no case t hey can
begin wit h a digit .

Anot her rule t hat you have t o consider when invent ing
your own ident ifiers is t hat t hey cannot m at ch any keyword
of t he C+ + language nor your com piler's specific ones,
which are reserved keywords. The st andard reserved
keywords are:

asm, auto, bool, break, case, catch, char,


class, const, const_cast, continue, default,
delete, do, double, dynamic_cast, else, enum,
explicit, export, extern, false, float, for,
friend, goto, if, inline, int, long, mutable,
namespace, new, operator, private, protected,
public, register, reinterpret_cast, return,
short, signed, sizeof, static, static_cast,
struct, switch, template, this, throw, true,
try, typedef, typeid, typename, union,
unsigned, using, virtual, void, volatile,
wchar_t, while

Addit ionally, alt ernat ive represent at ions for som e


operat ors cannot be used as ident ifiers since t hey are
reserved wor ds under som e circum st ances:

and, and_eq, bitand, bitor, compl, not,


not_eq, or, or_eq, xor, xor_eq

Your com piler m ay also include som e addit ional specific


reserved key words.

Ve r y im por t a n t : The C+ + language is a " case sensit ive"


language. That m eans t hat an ident ifier writ t en in capit al
let t ers is not equivalent t o anot her one wit h t he sam e
nam e but writ t en in sm all let t ers. Thus, for exam ple, t he
RESULT variable is not t he sam e as t he result variable
or t he Result variable. These are t hree different variable
ident ifiers.

Fu n da m e n t a l da t a t ype s
When program m ing, we st ore t he variables in our
com put er's m em ory, but t he com put er has t o know what
kind of dat a we want t o st ore in t hem , since it is not
going t o occupy t he sam e am ount of m em ory t o st ore a
sim ple num ber t han t o st ore a single let t er or a large
num ber, and t hey are not going t o be int erpret ed t he
sam e way.
-8-

byt e is t he m inim um am ount of m em ory t hat we can


m anage in C+ + . A byt e can st ore a relat ively sm all am ount
of dat a: one single charact er or a sm all int eger ( generally
an int eger bet ween 0 and 255) . I n addit ion, t he com put er
can m anipulat e m ore com plex dat a t ypes t hat com e from
grouping several byt es, such as long num bers or
non- int eger num bers.

Next you have a sum m ary of t he basic fundam ent al dat a


t ypes in C+ + , as well as t he range of values t hat can be
represent ed wit h each one:

Nam e D e scr ipt ion Size * Ra n ge *


signed: - 128 t o 127
char Charact er or sm all int eger . 1byt e
unsigned: 0 t o 255
short int signed: - 32768 t o 32767
Short I nt eger . 2byt es
( short) unsigned: 0 t o 65535
signed: - 2147483648 t o
2147483647
int I nt eger. 4byt es
unsigned: 0 t o
4294967295
signed: - 2147483648 t o
long int 2147483647
Long int eger. 4byt es
( long) unsigned: 0 t o
4294967295
Boolean value. I t can t ake one of t wo
bool 1byt e t rue or false
values: t rue or false.
float Float ing point num ber. 4byt es 3.4e + / - 38 ( 7 digit s)
double Double precision float ing point num ber. 8byt es 1.7e + / - 308 ( 15 digit s)
Long double precision float ing point
long double 8byt es 1.7e + / - 308 ( 15 digit s)
num ber.
wchar_t Wide charact er. 2byt es 1 wide charact er

* The values of t he colum ns Size and Ra n ge depend on


t he syst em t he program is com piled for. The values shown
above are t hose found on m ost 32- bit syst em s. But for
ot her syst em s, t he general specificat ion is t hat int has
t he nat ural size suggest ed by t he syst em archit ect ure
( one " word" ) and t he four int eger t ypes char, short, int
and long m ust each one be at least as large as t he one
preceding it , wit h char being always 1 byt e in size. The
sam e applies t o t he float ing point t ypes float, double
and long double, where each one m ust provide at least
as m uch precision as t he preceding one.

D e cla r a t ion of va r ia ble s


I n order t o use a variable in C+ + , we m ust first declare
it specifying which dat a t ype we want it t o be. The synt ax
t o declare a new variable is t o writ e t he specifier of t he
desired dat a t ype ( like int , bool, float ...) followed by a valid
variable ident ifier. For exam ple:

int a;
float mynumber;

These are t w o valid declarat ions of variables. The first


one declares a variable of t ype int wit h t he ident ifier a.
-9-

The second one declares a variable of t ype float wit h


t he ident ifier mynumber. Once declared, t he variables a
and mynumber can be used wit hin t he rest of t heir scope
in t he program .

I f you are going t o declare m ore t han one variable of t he


sam e t ype, you can declare all of t hem in a single st at em ent
by separat ing t heir ident ifiers wit h com m as. For exam ple:

int a, b, c;

This declares t hree variables ( a, b and c) , all of t hem of


t ype int, and has exact ly t he sam e m eaning as:

int a;
int b;
int c;

The int eger dat a t ypes char, short, long and int can
be eit her signed or unsigned depending on t he range of
num bers needed t o be represent ed. Signed t ypes can
represent bot h posit ive and negat ive values, whereas
unsigned t ypes can only represent posit ive values ( and zero) .
This can be specified by using eit her t he specifier
signed or t he specifier unsigned before t he t ype nam e.
For exam ple:

unsigned short int NumberOfSisters;


signed int MyAccountBalance;

By default , if we do not specify eit her signed or unsigned


m ost com piler set t ings will assum e t he t ype t o be signed,
t herefore inst ead of t he second declarat ion above we could
have writ t en:

int MyAccountBalance;

wit h exact ly t he sam e m eaning ( wit h or wit hout t he


keyword signed)

An except ion t o t his general rule is t he char t ype, which


exist s by it self and is considered a different fundam ent al
dat a t ype from signed char and unsigned char,
t hought t o st ore charact er s. You should use eit her signed
or unsigned if you int end t o st ore num erical values in a
char- sized variable.

short and long can be used alone as t ype specifiers.


I n t his case,t hey refer t o t heir respect ive int eger
fundam ent al t ypes: short is equivalent t o short int and
long is equivalent t o long int. The following t wo variable
declarat ions are equivalent :

short Year;
short int Year;
- 10 -

Finally, signed and unsigned m ay also be used as


st andalone t ype specifiers, m eaning t he sam e as signed
int and unsigned int respect ively. The following t wo
declarat ions are equivalent :

unsigned NextYear;
unsigned int NextYear;

To see what variable declarat ions look like in act ion wit hin
a program , we are going t o see t he C+ + code of t he
exam ple about your m ent al m em ory proposed at t he
beginning of t his sect ion:

// operating with variables

#include <iostream>
using namespace std;

int main ()
{
// declaring variables:
int a, b;
int result;

// process:
a = 5;
b = 2;
a = a + 1;
result = a - b;

// print out the result:


cout << result;

// terminate the program:


return 0;
}
4

Do not worry if som et hing else t han t he variable


declarat ions t hem selves looks a bit st range t o you.
You will see t he rest in det ail in com ing sect ions.

Scope of va r ia ble s
All t he variables t hat we int end t o use in a program m ust
have been declared wit h it s t ype specifier in an earlier
point in t he code, like we did in t he previous code at t he
beginning of t he body of t he funct ion m ain when we
declared t hat a, b, and result were of t ype int.

A variable can be eit her of global or local scope. A global


variable is a variable declared in t he m ain body of t he
source code, out side all funct ions, while a local variable
is one declared wit hin t he body of a funct ion or a block.
- 11 -

Global variables can be referred from anywhere in t he code,


even inside funct ions, whenever it is aft er it s declarat ion.

The scope of local variables is lim it ed t o t he block enclosed


in braces ( { } ) where t hey are declared. For exam ple, if
t hey are declared at t he beginning of t he body of a funct ion
( like in funct ion main) t heir scope is bet ween it s declarat ion
point and t he end of t hat funct ion. I n t he exam ple above,
t his m eans t hat if anot her funct ion exist ed in addit ion t o
main, t he local variables declared in main could not be
accessed from t he ot her funct ion and vice versa.

I n it ia liza t ion of va r ia ble s


When declaring a regular local variable, it s value is by
default undet erm ined. But you m ay want a variable t o
st ore a concret e value at t he sam e m om ent t hat it is
declared. I n order t o do t hat , you can init ialize t he
variable. There are t wo ways t o do t his in C+ + :

The first one, known as c- like, is done by appending an


equal sign followed by t he value t o which t he variable
w ill be init ialized:

type identifier = initial_value ;

For exam ple, if we want t o declare an int variable called a


init ialized wit h a value of 0 at t he m om ent in which it is
declared, we could writ e:

int a = 0;

The ot her way t o init ialize variables, known as const ruct or


init ializat ion, is done by enclosing t he init ial value bet ween
parent heses ( ()) :

type identifier (initial_value) ;


- 12 -

For exam ple:

int a (0);

Bot h ways of init ializing variables are valid and equivalent


in C+ + .

// initialization of variables

#include <iostream>
using namespace std;

int main ()
{
int a=5; //
initial value = 5
int b(2); //
initial value = 2
int result; //
initial value undetermined

a = a + 3;
result = a - b;
cout << result;

return 0;
}
6

I n t r odu ct ion t o st r in gs
Variables t hat can st ore non- num erical values t hat are
longer t han one single charact er are known as st rings.

The C+ + language library provides support for st rings


t hrough t he st andard string class. This is not a
fundam ent al t ype, but it behaves in a sim ilar way as
fundam ent al t ypes do in it s m ost basic usage.

A first difference wit h fundam ent al dat a t ypes is t hat in


order t o declare and use obj ect s ( variables) of t his t ype
we need t o include an addit ional header file in our source
code: <string> and have access t o t he std nam espace
( which we already had in all our previous program s t hanks
t o t he using namespace st at em ent ) .

// my first string
#include <iostream>
#include <string>
using namespace std;

int main ()
{
string mystring = "This is a
string";
cout << mystring;
return 0;
}
- 13 -

This is a string

As you m ay see in t he previous exam ple, st rings can be


init ialized wit h any valid st ring lit eral j ust like num erical
t ype variables can be init ialized t o any valid num erical
lit eral. Bot h init ializat ion form at s are valid wit h st rings:

string mystring = "This is a string";


string mystring ("This is a string");

St rings can also perform all t he ot her basic operat ions t hat
fundam ent al dat a t ypes can, like being declared wit hout an
init ial value and being assigned values during execut ion:

// my first string
#include <iostream>
#include <string>
using namespace std;

int main ()
{
string mystring;
mystring = "This is the initial
string content";
cout << mystring << endl;
mystring = "This is a different
string content";
cout << mystring << endl;
return 0;
}

This is the initial string content


This is a different string content

For m ore det ails on C+ + st rings, you can have a look at


t he st ring class reference.
- 14 -

Basics of C+ + :

3 . Con st a n t s

Const ant s are expressions wit h a fixed value.

Lit e r a ls
Lit erals are used t o express part icular values wit hin t he
source code of a program . We have already used t hese
previously t o give concret e values t o variables or t o
express m essages we want ed our program s t o print out ,
for exam ple, when we wrot e:

a = 5;

t he 5 in t his piece of code was a lit eral const ant .

Lit eral const ant s can be divided in I nt eger Num erals,


Float ing- Point Num erals, Charact ers, St rings and
Boolean Values.

I n t e ge r N u m e r a ls

1776
707
-273

They are num erical const ant s t hat ident ify int eger decim al
values. Not ice t hat t o express a num erical const ant we
do not have t o writ e quot es ( ") nor any special charact er.
There is no doubt t hat it is a const ant : whenever we writ e
1776 in a program , we will be referring t o t he value 1776.

I n addit ion t o decim al num bers ( t hose t hat all of us are


used t o use every day) C+ + allows t he use as lit eral
const ant s of oct al num bers ( base 8) and hexadecim al
num bers ( base 16) . I f we want t o express an oct al num ber
we have t o precede it wit h a 0 ( zero charact er) . And in
order t o expr ess a hexadecim al num ber we have t o
precede it wit h t he charact ers 0x ( zero, x) . For exam ple,
t he following lit eral const ant s are all equivalent t o
each ot her:

75 // decimal
0113 // octal
0x4b // hexadecimal
- 15 -

All of t hese represent t he sam e num ber: 75 ( sevent y- five)


expressed as a base- 10 num eral, oct al num eral and
hexadecim al num eral, respect ively.

Lit eral const ant s, like variables, are considered t o have a


specific dat a t ype. By default , int eger lit erals are of t ype
int. However, we can force t hem t o eit her be unsigned
by appending t he u charact er t o it , or long by appending l:

75 // int
75u // unsigned int
75l // long
75ul // unsigned long

I n bot h cases, t he suffix can be specified using eit her


upper or lowercase let t ers.

Floa t in g Poin t N u m be r s

They express num bers wit h decim als and/ or exponent s.


They can include eit her a decim al point , an e charact er
( t hat expresses " by t en at t he Xt h height " , where X is
an int eger value t hat follows t he e charact er) , or bot h
a decim al point and an e charact er:

3.14159 // 3.14159
6.02e23 // 6.02 x 1023
1.6e-19 // 1.6 x 10-19
3.0 // 3.0

These are four valid num bers wit h decim als expressed
in C+ + . The first num ber is PI , t he second one is t he
num ber of Avogadro, t he t hird is t he elect ric charge of
an elect ron ( an ext rem ely sm all num ber) - all of t hem
approxim at ed- and t he last one is t he num ber t hree
expressed as a float ing- point num eric lit eral.

The default t ype for float ing point lit erals is double. I f
you explicit ly want t o express a float or long double
num erical lit eral, you can use t he f or l suffixes
respect ively:

3.14159L // long double


6.02e23f // float

Any of t he let t ers t han can be part of a float ing- point


num erical const ant ( e, f, l) can be writ t en using eit her
lower or uppercase let t ers wit hout any difference in
t heir m eanings.

Ch a r a ct e r a n d st r in g lit e r a ls

There also exist non- num erical const ant s, like:


'z'
'p'
- 16 -

"Hello world"
"How do you do?"

The first t wo expressions represent single charact er


const ant s, and t he following t wo represent st ring lit erals
com posed of several charact ers. Not ice t hat t o represent
a single charact er we enclose it bet ween single quot es
( ') and t o express a st ring ( which generally consist s of
m ore t han one charact er) we enclose it bet ween double
quot es ( ") .

When writ ing bot h single charact er and st ring lit erals,
it is necessary t o put t he quot at ion m arks surrounding
t hem t o dist inguish t hem from possible variable ident ifiers
or reserved k eywords. Not ice t he difference bet w een
t hese t wo expressions:

x
'x'

x alone would refer t o a variable whose ident ifier is x,


whereas 'x' ( enclosed wit hin single quot at ion m arks)
would refer t o t he charact er const ant 'x'.

Charact er and st ring lit erals have cert ain peculiarit ies,
like t he escape codes. These are special charact ers t hat
are difficult or im possible t o express ot herwise in t he
source code of a program , like newline ( \n) or t ab ( \t) .
All of t hem are preceded by a backslash ( \) . Here you
have a list of som e of such escape codes:

\n newline
\r carriage ret urn
\t t ab
\v vert ical t ab
\b backspace
\f form feed ( page feed)
\a alert ( beep)
\' single quot e ( ')
\" double quot e ( ")
\? quest ion m ark ( ?)
\\ backslash ( \)

For exam ple:

'\n'
'\t'
"Left \t Right"
"one\ntwo\nthree"

Addit ionally, you can express any charact er by it s


num erical ASCI I code by writ ing a backslash charact er ( \)
followed by t he ASCI I code expressed as an oct al ( base- 8)
or hexadecim al ( base- 16) num ber. I n t he first case ( oct al)
- 17 -

t he digit s m ust im m ediat ely follow t he backslash


( for exam ple \23 or \40) , in t he second case ( hexadecim al) ,
an x charact er m ust be writ t en before t he digit s
t hem selves ( for exam ple \x20 or \x4A) .

St ring lit erals can ext end t o m ore t han a single line of
code by put t ing a backslash sign ( \) at t he end of each
unfinished line.

"string expressed in \
two lines"

You can also concat enat e several st ring const ant s


separat ing t hem by one or several blank spaces,
t abulat ors, newline or any ot her valid blank charact er:

"this forms" "a single" "string" "of characters"

Finally, if we want t he st ring lit eral t o be explicit ly m ade


of wide charact ers ( wchar_t) , inst ead of narrow charact ers
( char) , we can precede t he const ant wit h t he L prefix:

L"This is a wide character string"

Wide charact ers are used m ainly t o represent non- English


or exot ic charact er set s.

Boole a n lit e r a ls

There are only t wo valid Boolean values: t rue and false.


These can be expressed in C+ + as values of t ype bool
by using t he Boolean lit erals true and false.

D e fin e d con st a n t s ( # de fin e )


You can define your own nam es for const ant s t hat you
use very oft en wit hout having t o resort t o
m em ory- consum ing variables, sim ply by using t he
#define preprocessor direct ive. I t s form at is:

#define identifier value

For exam ple:

#define PI 3.14159265
#define NEWLINE '\n'

This defines t wo new const ant s: PI and NEWLINE. Once


t hey are defined, you can use t hem in t he rest of t he code
as if t hey were any ot her regular const ant , for exam ple:

// defined constants: calculate


circumference
- 18 -

#include <iostream>
using namespace std;

#define PI 3.14159
#define NEWLINE '\n'

int main ()
{
double r=5.0; // radius
double circle;

circle = 2 * PI * r;
cout << circle;
cout << NEWLINE;

return 0;
}
31.4159

I n fact t he only t hing t hat t he com piler preprocessor does


when it encount ers #define direct ives is t o lit erally
replace any occurrence of t heir ident ifier ( in t he previous
exam ple, t hese were PI and NEWLINE) by t he code t o
which t hey have been defined ( 3.14159265 and '\n'
respect ively) .

The #define direct ive is not a C+ + st at em ent but a


direct ive for t he preprocessor; t herefor e it assum es t he
ent ire line as t he direct ive and does not require a
sem icolon ( ;) at it s end. I f you append a sem icolon
charact er ( ;) at t he end, it will also be appended in all
occurrences wit hin t he body of t he program t hat t he
preprocessor replaces.

D e cla r e d con st a n t s ( con st )


Wit h t he const prefix you can declare const ant s wit h a
specific t ype in t he sam e way as you would do
wit h a variable:

const int pathwidth = 100;


const char tabulator = '\t';

Here, pathwidth and tabulator are two typed constants.


They are treated just like regular variables except that their
values cannot be modified after their definition.
- 19 -

Basics of C+ + :

4 . Ope r a t or s

Once we know of t he exist ence of variables and const ant s,


we can begin t o operat e wit h t hem . For t hat purpose,
C+ + int egrat es operat ors. Unlike ot her languages whose
operat ors are m ainly keywords, operat ors in C+ + are
m ost ly m ade of signs t hat are not part of t he alphabet
but are available in all keyboards. This m akes C+ + code
short er and m ore int ernat ional, since it relies less on
English words, but requires a lit t le of learning effort in
t he beginning.

You do not have t o m em orize all t he cont ent of t his page.


Most det ails are only provided t o serve as a lat er
reference in case you need it .

Assign m e n t ( = )
The assignm ent operat or assigns a value t o a variable.
a = 5;

This st at em ent assigns t he int eger value 5 t o t he


variable a. The part at t he left of t he assignm ent operat or
( =) is known as t he lvalue ( left value) and t he right one
as t he rvalue ( right value) . The lvalue has t o be a
variable whereas t he rvalue can be eit her a const ant ,
a variable, t he result of an operat ion or any com binat ion
of t hese. The m ost im port ant rule when assigning is
t he right - t o- left rule: The assignm ent operat ion always
t akes place from right t o left , and never t he ot her way:

a = b;

This st at em ent assigns t o variable a ( t he lvalue) t he value


cont ained in variable b ( t he rvalue) . The value t hat was
st ored unt il t his m om ent in a is not considered at all in t his
operat ion, and in fact t hat value is lost .

Consider also t hat we are only assigning t he value of b


t o a at t he m om ent of t he assignm ent operat ion.
Therefore a lat er change of b will not affect t he new
value of a.

For exam ple, let us have a look at t he following code - I


have included t he evolut ion of t he cont ent st ored in t he
variables as com m ent s:
- 20 -

// assignment operator

#include <iostream>
using namespace std;

int main ()
{
int a, b; // a:?, b:?
a = 10; // a:10, b:?
b = 4; // a:10, b:4
a = b; // a:4, b:4
b = 7; // a:4, b:7

cout << "a:";


cout << a;
cout << " b:";
cout << b;

return 0;
}
a:4 b:7

This code will give us as result t hat t he value cont ained


in a is 4 and t he one cont ained in b is 7. Not ice how a
was not affect ed by t he final m odificat ion of b, even
t hough we declared a = b earlier ( t hat is because of
t he right - t o- left rule) .

A propert y t hat C+ + has over ot her program m ing


languages is t hat t he assignm ent oper at ion can be used
as t he rvalue ( or part of an rvalue) for anot her
assignm ent operat ion. For exam ple:

a = 2 + (b = 5);

is equivalent t o:

b = 5;
a = 2 + b;

t hat m eans: first assign 5 t o variable b and t hen assign


t o a t he value 2 plus t he result of t he previous assignm ent
of b ( i.e. 5) , leaving a wit h a final value of 7.

The following expression is also valid in C+ + :

a = b = c = 5;

I t assigns 5 t o t he all t he t hree variables: a, b and c.

Ar it h m e t ic ope r a t or s ( + , - , * , / , % )
The five arit hm et ical operat ions support ed by t he C+ +
language are:

+ addit ion
- 21 -

- subt ract ion


* m ult iplicat ion
/ division
% m odulo

Operat ions of addit ion, subt ract ion, m ult iplicat ion and
division lit erally correspond wit h t heir respect ive
m at hem at ical operat ors. The only one t hat you m ight not
be so used t o see m ay be m odulo; whose operat or is t he
percent age sign ( %) . Modulo is t he operat ion t hat gives t he
rem ainder of a division of t wo values. For exam ple,
if we writ e:

a = 11 % 3;

t he variable a will cont ain t he value 2, since 2 is t he


rem ainder from dividing 11 bet ween 3.

Com pou n d a ssign m e n t ( + = , - = , * = ,


/ = , % = , > > = , < < = , &= , ^ = , | = )
When we want t o m odify t he value of a variable by
perform ing an operat ion on t he value current ly st ored in
t hat variable we can use com pound assignm ent operat ors:

e x pr e ssion is e qu iva le n t t o
value += increase; value = value + increase;
a -= 5; a = a - 5;
a /= b; a = a / b;
price *= units + 1; price = price * (units + 1);

and t he sam e for all ot her operat ors. For exam ple:

// compound assignment operators

#include <iostream>
using namespace std;

int main ()
{
int a, b=3;
a = b;
a+=2; //
equivalent to a=a+2
cout << a;
return 0;
}
5

I n cr e a se a n d de cr e a se ( + + , - - )
Short ening even m ore som e expressions, t he increase
operat or ( ++) and t he decrease operat or ( --) increase
or reduce by one t he value st ored in a variable. They are
equivalent t o +=1 and t o -=1, respect ively. Thus:
- 22 -

c++;
c+=1;
c=c+1;

are all equivalent in it s funct ionalit y: t he t hree of t hem


increase by one t he value of c.

I n t he early C com pilers, t he t hree previous expressions


probably produced different execut able code depending
on which one was used. Nowadays, t his t ype of code
opt im izat ion is generally done aut om at ically by t he
com piler, t hus t he t hree expressions should produce
exact ly t he sam e execut able code.

A charact erist ic of t his operat or is t hat it can be used bot h


as a prefix and as a suffix. That m eans t hat it can be
writ t en eit her before t he variable ident ifier ( ++a) or aft er
it ( a++) . Alt hough in sim ple expressions like a++ or ++a
bot h have exact ly t he sam e m eaning, in ot her expressions
in which t he result of t he increase or decrease oper at ion
is evaluat ed as a value in an out er expression t hey m ay
have an im port ant difference in t heir m eaning: I n t he case
t hat t he increase operat or is used as a prefix ( + + a) t he
value is increased before t he result of t he expression is
evaluat ed and t herefore t he increased value is considered
in t he out er expression; in case t hat it is used as a suffix
( a++) t he value st ored in a is increased aft er being
evaluat ed and t herefore t he value st ored before t he
increase oper at ion is evaluat ed in t he out er expression.
Not ice t he difference:

Ex a m ple 1 Ex a m ple 2
B=3; B=3;
A=++B; A=B++;
// A contains 4, B contains 4 // A contains 3, B contains 4

I n Exam ple 1, B is increased before it s value is copied t o A.


While in Exam ple 2, t he value of B is copied t o A and
t hen B is increased.

Re la t ion a l a n d e qu a lit y ope r a t or s


( = = , != , > , < , > = , < = )
I n order t o evaluat e a com parison bet ween t wo
expressions we can use t he relat ional and equalit y
operat ors. The result of a relat ional operat ion is a
Boolean value t hat can only be t rue or false, according t o
it s Boolean result .

We m ay want t o com pare t wo expressions, for exam ple,


t o know if t hey are equal or if one is great er t han t he
ot her is. Here is a list of t he relat ional and equalit y
operat ors t hat can be used in C+ + :

= = Equal t o
! = Not equal t o
> Great er t han
- 23 -

< Less t han


> = Great er t han or equal t o
< = Less t han or equal t o

Here t here ar e som e exam ples:

(7 == 5) // evaluates to false.
(5 > 4) // evaluates to true.
(3 != 2) // evaluates to true.
(6 >= 6) // evaluates to true.
(5 < 5) // evaluates to false.

Of course, inst ead of using only num eric const ant s, we


can use any valid expression, including variables.
Suppose t hat a=2, b=3 and c=6,

(a == 5) // evaluates to false since a is not equal to 5.


(a*b >= c) // evaluates to true since (2*3 >= 6) is true.
(b+4 > a*c) // evaluates to false since (3+4 > 2*6) is false.
((b=2) == a) // evaluates to true.

Be careful! The operat or = ( one equal sign) is not t he


sam e as t he operat or == ( t wo equal signs) , t he first one
is an assignm ent operat or ( assigns t he value at it s right
t o t he variable at it s left ) and t he ot her one ( ==) is t he
equalit y operat or t hat com pares whet her bot h expressions
in t he t wo sides of it are equal t o each ot her. Thus, in t he
last expression ((b=2) == a), we first assigned t he
value 2 t o b and t hen we com pared it t o a, t hat also
st ores t he value 2, so t he result of t he operat ion is t rue.

Logica l ope r a t or s ( !, & & , | | )


The Operat or ! is t he C+ + operat or t o perform t he
Boolean operat ion NOT, it has only one operand, locat ed
at it s right , and t he only t hing t hat it does is t o inverse
t he value of it , producing false if it s operand is t rue and
t rue if it s operand is false. Basically, it ret urns t he
opposit e Boolean value of evaluat ing it s operand.
For exam ple:

!(5 == 5) // evaluates to false because the expression at


its right (5 == 5) is true.
!(6 <= 4) // evaluates to true because (6 <= 4) would be
false.
!true // evaluates to false
!false // evaluates to true.

The logical operat ors && and || are used when


evaluat ing t wo expressions t o obt ain a single relat ional
result . The operat or && corresponds wit h Boolean logical
operat ion AND. This operat ion result s t rue if bot h it s t wo
operands ar e t rue, and false ot herwise. The following
panel shows t he result of operat or && evaluat ing t he
expression a && b:
- 24 -

& & OPERATOR

a b a && b
t rue t rue t rue
t rue false false
false t rue false
false false false

The operat or || corresponds wit h Boolean logical


operat ion OR. This operat ion result s t rue if eit her one of
it s t wo operands is t rue, t hus being false only when bot h
operands ar e false t hem selves. Here are t he possible
result s of a || b:

| | OPERATOR

a b a || b
t rue t rue t rue
t rue false t rue
false t rue t rue
false false false

For exam ple:

( (5 == 5) && (3 > 6) ) // evaluates to false ( true &&


false ).
( (5 == 5) || (3 > 6) ) // evaluates to true ( true ||
false ).

Con dit ion a l ope r a t or ( ? )


The condit ional operat or evaluat es an expression
ret urning a value if t hat expression is t rue and a
different one if t he expression is evaluat ed as false.
I t s form at is:

condition ? result1 : result2

I f condition is t rue t he expression will ret urn result1,


if it is not it w ill ret urn result2.

7==5 ? 4 : 3 // returns 3, since 7 is not equal to 5.


7==5+2 ? 4 : 3 // returns 4, since 7 is equal to 5+2.
5>3 ? a : b // returns the value of a, since 5 is greater
than 3.
a>b ? a : b // returns whichever is greater, a or b.
// conditional operator

#include <iostream>
using namespace std;

int main ()
{
int a,b,c;
- 25 -

a=2;
b=7;
c = (a>b) ? a : b;

cout << c;

return 0;
}
7

I n t his exam ple a was 2 and b was 7, so t he expression


being evaluat ed ( a>b) was not t rue, t hus t he first value
specified aft er t he quest ion m ark was discarded in favor
of t he second value ( t he one aft er t he colon) which was b,
wit h a value of 7.

Com m a ope r a t or ( , )
The com m a operat or ( ,) is used t o separat e t wo or m ore
expressions t hat are included where only one expression
is expect ed. When t he set of expressions has t o be
evaluat ed for a value, only t he right m ost expression is
considered.

For exam ple, t he following code:

a = (b=3, b+2);

Would first assign t he value 3 t o b, and t hen assign b+2


t o variable a. So, at t he end, variable a would cont ain t he
value 5 while variable b would cont ain value 3.

Bit w ise Ope r a t or s


( &, | , ^ , ~ , < < , > > )
Bit wise operat ors m odify variables considering t he bit
pat t erns t hat represent t he values t hey st ore.

ope r a t or a sm e qu iva le n t de scr ipt ion


& AND Bit wise AND
| OR Bit wise I nclusive OR
^ XOR Bit wise Exclusive OR
~ NOT Unary com plem ent ( bit inversion)
<< SHL Shift Left
>> SHR Shift Right

Ex plicit t ype ca st in g ope r a t or


Type cast ing operat ors allow you t o convert a dat um of
a given t ype t o anot her. There are sev eral ways t o do
t his in C+ + . The sim plest one, which has been inherit ed
from t he C language, is t o precede t he expression t o be
convert ed by t he new t ype enclosed bet ween
parent heses ( ()) :
- 26 -

int i;
float f = 3.14;
i = (int) f;

The previous code convert s t he float num ber 3.14 t o an


int eger value ( 3) , t he rem ainder is lost . Here, t he
t ypecast ing operat or was (int). Anot her way t o do t he
sam e t hing in C+ + is using t he funct ional not at ion:
preceding t he expression t o be convert ed by t he t ype
and enclosing t he expression bet ween parent heses:

i = int ( f );

Bot h ways of t ype cast ing are valid in C+ + .

size of( )
This operat or accept s one param et er, which can be eit her
a t ype or a variable it self and ret urns t he size in byt es
of t hat t ype or obj ect :
a = sizeof (char);

This will assign t he value 1 t o a because char is a


one- byt e long t ype. The value ret urned by sizeof is a
const ant , so it is always det erm ined before program
execut ion.

Ot h e r ope r a t or s
Lat er in t hese t ut orials, we will see a few m ore operat ors,
like t he ones referring t o point ers or t he specifics for
obj ect - orient ed program m ing. Each one is t reat ed in it s
respect ive sect ion.

Pr e ce de n ce of ope r a t or s
When writ ing com plex expressions wit h several operands,
we m ay have som e doubt s about which operand is
evaluat ed first and which lat er. For exam ple,
in t his expression:

a = 5 + 7 % 2

we m ay doubt if it really m eans:

a = 5 + (7 % 2) // with a result of 6, or
a = (5 + 7) % 2 // with a result of 0

The correct answer is t he first of t he t wo expressions,


wit h a result of 6. There is an est ablished order wit h t he
priorit y of each operat or, and not only t he arit hm et ic ones
( t hose whose preference com e from m at hem at ics) but for
all t he operat ors which can appear in C+ + . From great est
t o lowest priorit y, t he priorit y order is as follows:
- 27 -

Le ve l Ope r a t or D e scr ipt ion Gr ou pin g


Left - t o-
1 :: scope
right
() [] . -> ++ -- dynamic_cast
Left - t o-
2 static_cast reinterpret_cast post fix
right
const_cast typeid
++ -- ~ ! sizeof new delete unary ( prefix)
indirect ion and Right - t o-
3 * &
reference ( point ers) left
+ - unary sign operat or
Right - t o-
4 (type) t ype cast ing
left
Left - t o-
5 .* ->* point er- t o- m em ber
right
Left - t o-
6 * / % m ult iplicat ive
right
Left - t o-
7 + - addit ive
right
Left - t o-
8 << >> shift
right
Left - t o-
9 < > <= >= relat ional
right
Left - t o-
10 == != equalit y
right
Left - t o-
11 & bit wise AND
right
Left - t o-
12 ^ bit wise XOR
right
Left - t o-
13 | bit wise OR
right
Left - t o-
14 && logical AND
right
Left - t o-
15 || logical OR
right
Right - t o-
16 ?: condit ional
left
Right - t o-
17 = *= /= %= += -= >>= <<= &= ^= != assignm ent
left
Left - t o-
18 , com m a
right

Grouping defines t he precedence order in which operat ors


are evaluat ed in t he case t hat t here ar e several operat ors
of t he sam e level in an expression.

All t hese precedence levels for operat ors can be


m anipulat ed or becom e m ore legible by rem oving possible
am biguit ies using parent heses signs ( and ), as in t his
exam ple:

a = 5 + 7 % 2;

m ight be writ t en eit her as:

a = 5 + (7 % 2);
- 28 -

or

a = (5 + 7) % 2;

depending on t he operat ion t hat we want t o perform .

So if you want to write complicated expressions and you are


not completely sure of the precedence levels, always include
parentheses. It will also become a code easier to read.
- 29 -

Basics of C+ + :

5 . Ba sic I n pu t / Ou t pu t

Unt il now, t he exam ple program s of previous sect ions


provided very lit t le int eract ion wit h t he user, if any at all.
Using t he st andard input and out put library, we will be
able t o int eract wit h t he user by print ing m essages on
t he screen and get t ing t he user's input from t he keyboard.

C+ + uses a convenient abst ract ion called st ream s t o


perform input and out put operat ions in sequent ial m edia
such as t he screen or t he keyboard. A st ream is an obj ect
where a program can eit her insert or ext ract charact ers
t o/ from it . We do not really need t o care about m any
specificat ions about t he physical m edia associat ed wit h
t he st ream - we only need t o know it will accept or provide
charact ers sequent ialy.

The st andar d C+ + library includes t he header file


iostream, where t he st andard input and out put st ream
obj ect s are declared.

St a n da r d Ou t pu t ( cou t )
By default , t he st andard out put of a program is t he screen,
and t he C+ + st ream obj ect defined t o access it is cout.

cout is used in conj unct ion wit h t he insert ion operat or,
which is w rit t en as << ( t wo " less t han" signs) .

cout << "Output sentence"; // prints Output sentence on screen


cout << 120; // prints number 120 on screen
cout << x; // prints the content of x on screen

The << operat or insert s t he dat a t hat follows it int o t he


st ream preceding it . I n t he exam ples above it insert ed
t he const ant st ring Output sentence, t he num erical
const ant 120 and variable x int o t he st andard out put
st ream cout. Not ice t hat t he sent ence in t he first
inst ruct ion is enclosed bet ween double quot es ( ")
because it is a const ant st ring of charact ers. Whenever
we want t o use const ant st rings of charact ers we m ust
enclose t hem bet ween double quot es ( ") so t hat t hey
can be clearly dist inguished from variable nam es. For
exam ple, t hese t wo sent ences have very different result s:
- 30 -

cout << "Hello"; // prints Hello


cout << Hello; // prints the content of Hello variable

The insert ion operat or ( <<) m ay be used m ore t han once


in a single st at em ent :

cout << "Hello, " << "I am " << "a C++ statement";

This last st at em ent would print t he m essage


Hello, I am a C++ statement on t he screen. The
ut ilit y of repeat ing t he insert ion operat or ( <<) is
dem onst rat ed when we want t o print out a com binat ion
of variables and const ant s or m ore t han one variable:

cout << "Hello, I am " << age << " years old and my zipcode is "
<< zipcode;

I f we assum e t he age variable t o cont ain t he value 24


and t he zipcode variable t o cont ain 90064 t he out put
of t he previous st at em ent would be:

Hello, I am 24 years old and my zipcode is 90064

I t is im port ant t o not ice t hat cout does not add a line
break aft er it s out put unless we explicit ly indicat e it ,
t herefore, t he following st at em ent s:

cout << "This is a sentence.";


cout << "This is another sentence.";

will be shown on t he screen one following t he ot her


wit hout any line break bet ween t hem :

This is a sentence.This is another sentence.

even t hough we had writ t en t hem in t wo different


insert ions int o cout. I n order t o perfor m a line break on
t he out put we m ust explicit ly insert a new- line charact er
int o cout. I n C+ + a new- line charact er can be specified
as \n ( backslash, n) :

cout << "First sentence.\n ";


cout << "Second sentence.\nThird sentence.";

This produces t he following out put :

First sentence.
Second sentence.
Third sentence.

Addit ionally, t o add a new- line, you m ay also use t he endl


m anipulat or. For exam ple:
- 31 -

cout << "First sentence." << endl;


cout << "Second sentence." << endl;

would print out :

First sentence.
Second sentence.

The endl m anipulat or produces a newline charact er,


exact ly as t he insert ion of '\n' does, but it also has an
addit ional behavior when it is used wit h buffered st ream s:
t he buffer is flushed. Anyway, cout will be an unbuffered
st ream in m ost cases, so you can gener ally use bot h
t he \n escape charact er and t he endl m anipulat or in
order t o specify a new line wit hout any difference in it s
behavior.

St a n da r d I n pu t ( cin ) .
The st andar d input device is usually t he keyboard.
Handling t he st andard input in C+ + is done by applying
t he overloaded operat or of ext ract ion ( >>) on t he cin
st ream . The operat or m ust be followed by t he variable
t hat will st ore t he dat a t hat is going t o be ext ract ed
from t he st ream . For exam ple:

int age;
cin >> age;

The first st at em ent declar es a variable of t ype int called


age, and t he second one wait s for an input from cin
( t he keyboard) in order t o st ore it in t his int eger variable.

cin can only process t he input from t he keyboard once


t he RETURN key has been pressed. Therefore, even if
you request a single charact er, t he ext ract ion from cin
will not process t he input unt il t he user presses RETURN
aft er t he charact er has been int roduced.

You m ust always consider t he t ype of t he variable t hat


you are using as a cont ainer wit h cin ext ract ions. I f
you request an int eger you will get an int eger, if you
request a charact er you will get a charact er and if you
request a st ring of charact ers you will get a st ring of
charact ers.

// i/o example

#include <iostream>
using namespace std;

int main ()
{
int i;
cout << "Please enter an integer
value: ";
cin >> i;
- 32 -

cout << "The value you entered


is " << i;
cout << " and its double is " <<
i*2 << ".\n";
return 0;
}
Please enter an integer value: 702
The value you entered is 702 and
its double is 1404.

The user of a program m ay be one of t he fact ors t hat


generat e err ors even in t he sim plest program s t hat use
cin ( like t he one we have j ust seen) . Since if you request
an int eger value and t he user int roduces a nam e ( which
generally is a st ring of charact ers) , t he result m ay cause
your program t o m isoperat e since it is not what we were
expect ing from t he user. So when you use t he dat a input
provided by cin ext ract ions you will have t o t rust t hat
t he user of your program will be cooperat ive and t hat
he/ she will not int roduce his/ her nam e or som et hing sim ilar
when an int eger value is request ed. A lit t le ahead, when
we see t he stringstream class we will see a possible
solut ion for t he errors t hat can be caused by t his t ype
of user input .

You can also use cin t o request m ore t han one dat um
input from t he user:

cin >> a >> b;

is equivalent t o:

cin >> a;
cin >> b;

I n bot h cases t he user m ust give t wo dat a, one for


variable a and anot her one for variable b t hat m ay be
separat ed by any valid blank separat or : a space, a t ab
charact er or a newline.

cin a n d st r in gs
We can use cin t o get st rings wit h t he ext ract ion
operat or ( >>) as we do wit h fundam ent al dat a
t ype variables:

cin >> mystring;

However, as it has been said, cin ext ract ion st ops


reading as soon as if finds any blank space charact er ,
so in t his case we will be able t o get j ust one word for
each ext ract ion. This behavior m ay or m ay not be what
we want ; for exam ple if we want t o get a sent ence from
t he user, t his ext ract ion operat ion would not be useful.

I n order t o get ent ire lines, we can use t he funct ion


- 33 -

getline, which is t he m ore recom m endable way t o get


user input wit h cin:

// cin with strings


#include <iostream>
#include <string>
using namespace std;

int main ()
{
string mystr;
cout << "What's your name? ";
getline (cin, mystr);
cout << "Hello " << mystr <<
".\n";
cout << "What is your favorite
team? ";
getline (cin, mystr);
cout << "I like " << mystr << "
too!\n";
return 0;
}
What's your name? Juan Soulié
Hello Juan Soulié.
What is your favorite team? The
Isotopes
I like The Isotopes too!

Not ice how in bot h calls t o getline we used t he sam e


st ring ident ifier ( mystr) . What t he program does in t he
second call is sim ply t o replace t he previous cont ent
by t he new one t hat is int roduced.

st r in gst r e a m
The st andar d header file <sstream> defines a class called
stringstream t hat allows a st ring- based obj ect t o be
t reat ed as a st ream . This way we can perform ext ract ion
or insert ion operat ions from / t o st rings, which is especially
useful t o convert st rings t o num erical values and vice versa.
For exam ple, if we want t o ext ract an int eger from a
st ring we can writ e:

string mystr ("1204");


int myint;
stringstream(mystr) >> myint;

This declares a string obj ect wit h a value of "1204",


and an int obj ect . Then we use stringstream's
const ruct or t o const ruct an obj ect of t his t ype from t he
st ring obj ect . Because we can use stringstream
obj ect s as if t hey were st ream s, we can ext ract an
int eger from it as we would have done on cin by
applying t he ext ract or operat or ( >>) on it followed by a
variable of t ype int.

Aft er t his piece of code, t he variable myint will cont ain


t he num erical value 1204.
- 34 -

// stringstreams
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main ()
{
string mystr;
float price=0;
int quantity=0;

cout << "Enter price: ";


getline (cin,mystr);
stringstream(mystr) >> price;
cout << "Enter quantity: ";
getline (cin,mystr);
stringstream(mystr) >> quantity;
cout << "Total price: " <<
price*quantity << endl;
return 0;
}
Enter price: 22.25
Enter quantity: 7
Total price: 155.75

I n t his exam ple, we acquire num eric values from t he


st andard input indirect ly. I nst ead of ext ract ing num eric
values direct ly from t he st andard input , we get lines
from t he st andard input ( cin) int o a st ring obj ect ( mystr) ,
and t hen we ext ract t he int eger values from t his st ring
int o a variable of t ype int ( myint) .

Using t his m et hod, inst ead of direct ext ract ions of int eger
values, we have m ore cont rol over what happens w it h
t he input of num eric values from t he user, since we are
separat ing t he process of obt aining input from t he user
( we now sim ply ask for lines) wit h t he int erpret at ion of
t hat input . Therefore, t his m et hod is usually preferred t o
get num erical values from t he user in all program s t hat
are int ensive in user input .
- 35 -

Cont rol St ruct ures:

6 . Con t r ol St r u ct u r e s

A program is usually not lim it ed t o a linear sequence of


inst ruct ions. During it s process it m ay bifurcat e, repeat
code or t ake decisions. For t hat purpose, C+ + provides
cont rol st ruct ures t hat ser ve t o specify what has t o be
done by our program , when and under which
circum st ances.

Wit h t he int roduct ion of cont rol st ruct ures we are going
t o have t o int roduce a new concept : t he
com pound- st at em ent or block. A block is a group of
st at em ent s w hich are separat ed by sem icolons ( ; ) like
all C+ + st at em ent s, but grouped t oget her in a block
enclosed in braces: { }:

{ statement1; statement2; statement3; }

Most of t he cont rol st ruct ures t hat we will see in t his


sect ion require a generic st at em ent as part of it s synt ax.
A st at em ent can be eit her a sim ple st at em ent ( a sim ple
inst ruct ion ending wit h a sem icolon) or a com pound
st at em ent ( several inst ruct ions grouped in a block) , like
t he one j ust described. I n t he case t hat we want t he
st at em ent t o be a sim ple st at em ent , we do not need t o
enclose it in braces ( {}) . But in t he case t hat we want
t he st at em ent t o be a com pound st at em ent it m ust be
enclosed bet ween braces ( {}) , form ing a block.

Con dit ion a l st r uct u r e : if a n d e lse


The if keyword is used t o execut e a st at em ent or block
only if a condit ion is fulfilled. I t s form is:

if (condition) statement

Where condition is t he expression t hat is being


evaluat ed. I f t his condit ion is t rue, statement is
execut ed. I f it is false, statement is ignored
( not execut ed) and t he pr ogram cont inues right aft er t his
condit ional st ruct ure. For exam ple, t he following code
fragm ent print s x is 100 only if t he value st ored in
t he x variable is indeed 100:

if (x == 100)
cout << "x is 100";
- 36 -

I f we want m ore t han a single st at em ent t o be execut ed


in case t hat t he condit ion is t rue we can specify a block
using braces { }:

if (x == 100)
{
cout << "x is ";
cout << x;
}

We can addit ionally specify what we want t o happen if


t he condit ion is not fulfilled by using t he keyw ord else.
I t s form used in conj unct ion wit h if is:

if (condition) statement1 else statement2

For exam ple:

if (x == 100)
cout << "x is 100";
else
cout << "x is not 100";

print s on t he screen x is 100 if indeed x has a value


of 100, but if it has not - and only if not - it print s out x
is not 100.

The if + else st ruct ures can be concat enat ed wit h t he


int ent ion of verifying a range of values. The following
exam ple shows it s use t elling if t he value current ly st ored
in x is posit ive, negat ive or none of t hem ( i.e. zero) :

if (x > 0)
cout << "x is positive";
else if (x < 0)
cout << "x is negative";
else
cout << "x is 0";

Rem em ber t hat in case t hat we want m ore t han a single


st at em ent t o be execut ed, we m ust group t hem in a block
by enclosing t hem in braces { }.

I t e r a t ion st r u ct u r e s ( loops)
Loops have as purpose t o repeat a st at em ent a cert ain
num ber of t im es or while a condit ion is fulfilled.

Th e w h ile loop

I t s form at is:

while (expression) statement


- 37 -

and it s funct ionalit y is sim ply t o repeat st at em ent w hile


t he condit ion set in expression is t rue. For exam ple, we
are going t o m ake a progr am t o count down using a
while- loop:

// custom countdown using while

#include <iostream>
using namespace std;

int main ()
{
int n;
cout << "Enter the starting
number > ";
cin >> n;

while (n>0) {
cout << n << ", ";
--n;
}

cout << "FIRE!\n";


return 0;
}
Enter the starting number > 8
8, 7, 6, 5, 4, 3, 2, 1, FIRE!

When t he pr ogram st art s t he user is prom pt ed t o insert


a st art ing num ber for t he count down. Then t he while
loop begins, if t he value ent ered by t he user fulfills t he
condit ion n>0 ( t hat n is great er t han zero) t he block t hat
follows t he condit ion will be execut ed and repeat ed
while t he condit ion ( n>0) rem ains being t rue.

The whole process of t he previous program can be


int erpret ed according t o t he following script
( beginning in m ain) :

1. User assigns a value t o n


2. The while condit ion is checked ( n>0) . At t his
point t here are t wo posibilit ies:
* condit ion is t rue: st at em ent is execut ed
( t o st ep 3)
* condit ion is false: ignore st at em ent and
cont inue aft er it ( t o st ep 5)
3. Execut e st at em ent :
cout << n << ", ";
--n;
( print s t he value of n on t he screen and
decreases n by 1)
4. End of block. Ret urn aut om at ically t o st ep 2
5. Cont inue t he program right aft er t he block:
print FI RE! and end progr am .

When creat ing a while- loop, we m ust always consider


t hat it has t o end at som e point , t herefore we m ust
provide wit hin t he block som e m et hod t o force t he
condit ion t o becom e false at som e point , ot herwise t he
- 38 -

loop will cont inue looping forever. I n t his case we have


included --n; t hat decreases t he value of t he variable
t hat is being evaluat ed in t he condit ion ( n) by one - t his
will event ually m ake t he condit ion ( n>0) t o becom e false
aft er a cert ain num ber of loop it erat ions: t o be m ore
specific, when n becom es 0, t hat is where our while- loop
and our count down end.

Of course t his is such a sim ple act ion for our com put er
t hat t he whole count down is perform ed inst ant ly wit hout
any pract ical delay bet ween num bers.

Th e do- w h ile loop

I t s form at is:

do statement while (condition);

I t s funct ionalit y is exact ly t he sam e as t he while loop,


except t hat condition in t he do- while loop is evaluat ed
aft er t he execut ion of st at em ent inst ead of before,
grant ing at least one execut ion of statement even if
condition is never fulfilled. For exam ple, t he following
exam ple program echoes any num ber you ent er
unt il you ent er 0.

// number echoer

#include <iostream>
using namespace std;

int main ()
{
unsigned long n;
do {
cout << "Enter number (0 to
end): ";
cin >> n;
cout << "You entered: " << n
<< "\n";
} while (n != 0);
return 0;
}
Enter number (0 to end): 12345
You entered: 12345
Enter number (0 to end): 160277
You entered: 160277
Enter number (0 to end): 0
You entered: 0

The do- while loop is usually used when t he condit ion


t hat has t o det erm ine t he end of t he loop is det erm ined
wit hin t he loop st at em ent it self, like in t he previous case,
where t he user input wit hin t he block is what is used t o
det erm ine if t he loop has t o end. I n fact if you never
ent er t he value 0 in t he previous exam ple you can be
prom pt ed for m ore num bers forever.
- 39 -

Th e for loop

I t s form at is:

for (initialization; condition; increase)


statement;

and it s m ain funct ion is t o repeat statement while


condition rem ains t rue, like t he while loop. But in
addit ion, t he for loop provides specific locat ions t o
cont ain an initialization st at em ent and an increase
st at em ent . So t his loop is specially designed t o perform
a repet it ive act ion wit h a count er which is init ialized and
increased on each it erat ion.

I t works in t he following way:

1. initialization is execut ed. Generally it is an


init ial value set t ing for a count er variable.
This is execut ed only once.
2. condition is checked. I f it is t rue t he loop
cont inues, ot herwise t he loop ends and
statement is skipped ( not execut ed) .
3. statement is execut ed. As usual, it can be eit her
a single st at em ent or a block enclosed
in braces { }.
4. finally, what ever is specified in t he increase field
is execut ed and t he loop get s back t o st ep 2.

Here is an exam ple of count down using a for loop:

// countdown using a for loop


#include <iostream>
using namespace std;
int main ()
{
for (int n=10; n>0; n--) {
cout << n << ", ";
}
cout << "FIRE!\n";
return 0;
}
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
FIRE!

The initialization and increase fields are opt ional.


They can rem ain em pt y, but in all cases t he sem icolon
signs bet ween t hem m ust be writ t en. For exam ple we
could writ e: for (;n<10;) if we want ed t o specify no
init ializat ion and no increase; or for (;n<10;n++) if
we want ed t o include an increase field but no
init ializat ion ( m aybe because t he variable was already
init ialized before) .

Opt ionally, using t he com m a operat or ( ,) we can specify


m ore t han one expression in any of t he fields included
in a for loop, like in initialization, for exam ple.
- 40 -

The com m a operat or ( ,) is an expression separat or,


it serves t o separat e m ore t han one expression where
only one is generally expect ed. For exam ple, suppose
t hat we want ed t o init ialize m ore t han one variable
in our loop:

for ( n=0, i=100 ; n!=i ; n++, i-- )


{
// whatever here...
}

This loop will execut e for 50 t im es if neit her n or i are


m odified wit hin t he loop:

n st art s wit h a value of 0, and i wit h 100, t he condit ion


is n!=i ( t hat n is not equal t o i) . Because n is increased
by one and i decreased by one, t he loop's condit ion will
becom e false aft er t he 50t h loop, when bot h n and i will
be equal t o 50.

Ju m p st a t e m e n t s.

Th e br e a k st a t e m e n t

Using break we can leave a loop even if t he condit ion


for it s end is not fulfilled. I t can be used t o end an infinit e
loop, or t o force it t o end before it s nat ural end.
For exam ple, we are going t o st op t he count down before
it s nat ural end ( m aybe because of an engine check failure?) :

// break loop example

#include <iostream>
using namespace std;

int main ()
{
int n;
for (n=10; n>0; n--)
{
cout << n << ", ";
if (n==3)
{
cout << "countdown
aborted!";
break;
}
}
return 0;
}
10, 9, 8, 7, 6, 5, 4, 3,
countdown aborted!
- 41 -

Th e con t in u e st a t e m e n t

The continue st at em ent causes t he program t o skip t he


rest of t he loop in t he current it erat ion as if t he end of
t he st at em ent block had been reached, causing it t o
j um p t o t he st art of t he following it erat ion. For exam ple,
we are going t o skip t he num ber 5 in our count down:

// continue loop example


#include <iostream>
using namespace std;

int main ()
{
for (int n=10; n>0; n--) {
if (n==5) continue;
cout << n << ", ";
}
cout << "FIRE!\n";
return 0;
}
10, 9, 8, 7, 6, 4, 3, 2, 1,
FIRE!

Th e got o st a t e m e n t

goto allows t o m ake an absolut e j um p t o anot her point


in t he program . You should use t his feat ure wit h caut ion
since it s execut ion causes an uncondit ional j um p ignoring
any t ype of nest ing lim it at ions. The dest inat ion point is
ident ified by a label, which is t hen used as an argum ent
for t he got o st at em ent . A label is m ade of a valid ident ifier
followed by a colon ( :) .

Generally speaking, t his inst ruct ion has no concret e use


in st ruct ured or obj ect orient ed program m ing aside from
t hose t hat low- level program m ing fans m ay find for it .
For exam ple, here is our count down loop using goto:

// goto loop example

#include <iostream>
using namespace std;

int main ()
{
int n=10;
loop:
cout << n << ", ";
n--;
if (n>0) goto loop;
cout << "FIRE!\n";
return 0;
}
10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
FIRE!
- 42 -

Th e e x it fu n ct ion

exit is a funct ion defined in t he cstdlib library.

The purpose of exit is t o t erm inat e t he current program


wit h a specific exit code. I t s prot ot ype is:

void exit (int exitcode);

The exitcode is used by som e operat ing syst em s and


m ay be used by calling program s. By convent ion, an exit
code of 0 m eans t hat t he program finished norm ally
and any ot her value m eans t hat som e error or
unexpect ed r esult s happened.

Th e se le ct ive st r u ct u r e : sw it ch .
The synt ax of t he swit ch st at em ent is a bit peculiar. I t s
obj ect ive is t o check several possible const ant values for
an expression. Som et hing sim ilar t o what we did at t he
beginning of t his sect ion wit h t he concat enat ion of
several if and else if inst ruct ions.
I t s form is t he following:

switch (expression)
{
case constant1:
group of statements 1;
break;
case constant2:
group of statements 2;
break;
.
.
.
default:
default group of statements
}

I t works in t he following way: swit ch evaluat es


expression and checks if it is equivalent t o constant1,
if it is, it execut es group of statements 1 unt il it finds
t he break st at em ent . When it finds t his break
st at em ent t he program j um ps t o t he end of
t he switch select ive st ruct ure.

I f expression was not equal t o constant1 it will be


checked against constant2. I f it is equal t o t his, it w ill
execut e group of statements 2 unt il a break keyword
is found, and t hen will j um p t o t he end of t he switch
select ive st ruct ure.

Finally, if t he value of expression did not m at ch any


of t he previously specified const ant s ( you can include as
m any case labels as values you want t o check) , t he
program will execut e t he st at em ent s included aft er t he
- 43 -

default: label, if it exist s ( since it is opt ional) .

Bot h of t he following code fragm ent s have t he sam e


behavior:

sw it ch e x a m ple if- e lse e qu iva le n t


switch (x) {
if (x == 1) {
case 1:
cout << "x is 1";
cout << "x is 1";
}
break;
else if (x == 2) {
case 2:
cout << "x is 2";
cout << "x is 2";
}
break;
else {
default:
cout << "value of x unknown";
cout << "value of x unknown";
}
}

The switch st at em ent is a bit peculiar wit hin t he C+ +


language because it uses labels inst ead of blocks. This
forces us t o put break st at em ent s aft er t he group of
st at em ent s t hat we want t o be execut ed for a specific
condit ion. Ot herwise t he rem ainder st at em ent s - including
t hose corresponding t o ot her labels- will also be
execut ed unt il t he end of t he switch select ive block or
a break st at em ent is reached.

For exam ple, if we did not include a break st at em ent


aft er t he first group for case one, t he program will not
aut om at ically j um p t o t he end of t he switch select ive
block and it would cont inue execut ing t he rest of
st at em ent s unt il it reaches eit her a break inst ruct ion
or t he end of t he switch select ive block. This m akes
unnecessary t o include braces { } surrounding t he
st at em ent s for each of t he cases, and it can also be
useful t o execut e t he sam e block of inst ruct ions for
different possible values for t he expression being
evaluat ed. For exam ple:

switch (x) {
case 1:
case 2:
case 3:
cout << "x is 1, 2 or 3";
break;
default:
cout << "x is not 1, 2 nor 3";
}

Not ice t hat swit ch can only be used t o com pare an


expression against const ant s. Therefore we cannot put
variables as labels ( for exam ple case n: where n is a
variable) or ranges ( case (1..3):) because t hey are
not valid C+ + const ant s.

I f you need t o check ranges or values t hat are not


const ant s, use a concat enat ion of if and else if
st at em ent s.
- 44 -

Cont rol St ruct ures:

7 . Fu n ct ion s ( I )

Using funct ions we can st ruct ure our program s in a m ore


m odular way, accessing all t he pot ent ial t hat st ruct ured
program m ing can offer t o us in C+ + .

A funct ion is a group of st at em ent s t hat is execut ed


when it is called from som e point of t he program .
The following is it s form at :

type name ( parameter1, parameter2, ...) { statement }

where:

• type is t he dat a t ype specifier of t he dat a


ret urned by t he funct ion.
• name is t he ident ifier by which it will be possible
t o call t he funct ion.
• parameters ( as m any as needed) : Each
param et er consist s of a dat a t ype specifier
followed by an ident ifier, like any regular variable
declarat ion ( for exam ple: int x) and which act s
w it hin t he funct ion as a regular local variable.
They allow t o pass argum ent s t o t he funct ion
when it is called. The different param et ers are
separat ed by com m as.
• statements is t he funct ion's body. I t is a block
of st at em ent s surrounded by braces { }.

Here you have t he first funct ion exam ple:

// function example
#include <iostream>
using namespace std;

int addition (int a, int b)


{
int r;
r=a+b;
return (r);
}

int main ()
{
int z;
z = addition (5,3);
- 45 -

cout << "The result is " << z;


return 0;
}
The result is 8

I n order t o exam ine t his code, first of all rem em ber


som et hing said at t he beginning of t his t ut orial: a C+ +
program always begins it s execut ion by t he main funct ion.
So we will begin t here.

We can see how t he main funct ion begins by declaring


t he variable z of t ype int. Right aft er t hat , we see a
call t o a funct ion called addition. Paying at t ent ion we
will be able t o see t he sim ilarit y bet ween t he st ruct ure
of t he call t o t he funct ion and t he declarat ion of t he
funct ion it self som e code lines above:

The param et ers and argum ent s have a clear


correspondence. Wit hin t he main funct ion we called t o
addition passing t wo values: 5 and 3, t hat correspond
t o t he int a and int b param et ers declared for
funct ion addit ion.

At t he point at which t he funct ion is called from wit hin


main, t he cont rol is lost by main and passed t o funct ion
addition. The value of bot h argum ent s passed in t he
call ( 5 and 3) are copied t o t he local variables int a
and int b wit hin t he funct ion.

Funct ion addition declares anot her local variable


( int r) , and by m eans of t he expression r=a+b, it
assigns t o r t he result of a plus b. Because t he act ual
param et ers passed for a and b are 5 and 3 respect ively,
t he result is 8.

The following line of code:

return (r);

finalizes funct ion addition, and ret urns t he cont rol back
t o t he funct ion t hat called it in t he first place ( in t his case,
main) . At t his m om ent t he program follows it regular
course from t he sam e point at which it was int errupt ed
by t he call t o addition. But addit ionally, because t he
return st at em ent in funct ion addition specified a value:
t he cont ent of variable r ( return (r);) , which at t hat
m om ent had a value of 8. This value becom es t he value
of evaluat ing t he funct ion call.
- 46 -

So being t he value ret urned by a funct ion t he value given


t o t he funct ion call it self when it is evaluat ed, t he variable
z will be set t o t he value ret urned by addition (5, 3),
t hat is 8. To explain it anot her way, you can im agine t hat
t he call t o a funct ion ( addition (5,3)) is lit erally
replaced by t he value it ret urns ( 8) .

The following line of code in m ain is:

cout << "The result is " << z;

That , as you m ay already expect , produces t he print ing


of t he result on t he screen.

Scope of va r ia ble s

The scope of variables declared wit hin a funct ion or any


ot her inner block is only t heir own funct ion or t heir own
block and cannot be used out side of t hem . For exam ple,
in t he previous exam ple it would have been im possible
t o use t he variables a, b or r direct ly in funct ion main
since t hey were variables local t o funct ion addition.
Also, it would have been im possible t o use t he variable
z direct ly wit hin funct ion addition, since t his was a
variable local t o t he funct ion main.

Therefore, t he scope of local variables is lim it ed t o t he


sam e block level in which t hey are declared. Nevert heless,
we also have t he possibilit y t o declare global variables;
These are visible from any point of t he code, inside and
out side all funct ions. I n order t o declar e global variables
you sim ply have t o declare t he variable out side any
funct ion or block; t hat m eans, direct ly in t he body
- 47 -

of t he program .

And here is anot her exam ple about funct ions:

// function example
#include <iostream>
using namespace std;

int subtraction (int a, int b)


{
int r;
r=a-b;
return (r);
}

int main ()
{
int x=5, y=3, z;
z = subtraction (7,2);
cout << "The first result is "
<< z << '\n';
cout << "The second result is
" << subtraction (7,2) << '\n';
cout << "The third result is "
<< subtraction (x,y) << '\n';
z= 4 + subtraction (x,y);
cout << "The fourth result is
" << z << '\n';
return 0;
}
The first result is 5
The second result is 5
The third result is 2
The fourth result is 6

I n t his case we have creat ed a funct ion called


subtraction. The only t hing t hat t his funct ion does is t o
subt ract bot h passed param et ers and t o ret urn t he result .

Nevert heless, if we exam ine funct ion main we will see


t hat we have m ade several calls t o funct ion subtraction.
We have used som e different calling m et hods so t hat you
see ot her ways or m om ent s when a funct ion can be called.

I n order t o fully underst and t hese exam ples you m ust


consider once again t hat a call t o a funct ion could be
replaced by t he value t hat t he funct ion call it self is going
t o ret urn. For exam ple, t he first case ( t hat you should
already know because it is t he sam e pat t ern t hat we
have used in previous exam ples) :

z = subtraction (7,2);
cout << "The first result is " << z;

I f we replace t he funct ion call by t he value it ret urns


( i.e., 5) , we would have:
- 48 -

z = 5;
cout << "The first result is " << z;

As well as

cout << "The second result is " << subtraction (7,2);

has t he sam e result as t he previous call, but in t his case


we m ade t he call t o subtraction direct ly as an insert ion
param et er for cout. Sim ply consider t hat t he result is t he
sam e as if we had writ t en:

cout << "The second result is " << 5;

since 5 is t he value ret urned by subtraction (7,2).

I n t he case of:

cout << "The third result is " << subtraction (x,y);

The only new t hing t hat we int roduced is t hat t he


param et ers of subtraction are variables inst ead of
const ant s. That is perfect ly valid. I n t his case t he values
passed t o funct ion subtraction are t he values of x
and y, t hat are 5 and 3 respect ively, giving 2 as result .

The fourt h case is m ore of t he sam e. Sim ply not e t hat


inst ead of:

z = 4 + subtraction (x,y);

we could have writ t en:

z = subtraction (x,y) + 4;

wit h exact ly t he sam e result . I have swit ched places so


you can see t hat t he sem icolon sign ( ;) goes at t he end
of t he whole st at em ent . I t does not necessarily have t o
go right aft er t he funct ion call. The explanat ion m ight be
once again t hat you im agine t hat a funct ion can be
replaced by it s ret urned v alue:

z = 4 + 2;
z = 2 + 4;

Fu n ct ion s w it h n o t ype .
Th e u se of void.
I f you rem em ber t he synt ax of a funct ion declarat ion:

type name ( argument1, argument2 ...) statement


- 49 -

you will see t hat t he declarat ion begins wit h a type,


t hat is t he t ype of t he funct ion it self ( i.e., t he t ype of t he
dat um t hat will be ret urned by t he funct ion wit h t he ret urn
st at em ent ) . But what if we want t o ret urn no value?

I m agine t hat we want t o m ake a funct ion j ust t o show


a m essage on t he screen. We do not need it t o ret urn
any value. I n t his case we should use t he void t ype
specifier for t he funct ion. This is a special specifier t hat
indicat es absence of t ype.

// void function example


#include <iostream>
using namespace std;

void printmessage ()
{
cout << "I'm a function!";
}

int main ()
{
printmessage ();
return 0;
}
I'm a function!

void can also be used in t he funct ion's param et er list t o


explicit ly specify t hat we want t he funct ion t o t ake no
act ual param et ers when it is called. For exam ple, funct ion
printmessage could have been declared as:

void printmessage (void)


{
cout << "I'm a function!";
}

Alt hough it is opt ional t o specify void in t he param et er


list . I n C+ + , a param et er list can sim ply be left blank if
we want a funct ion wit h no param et ers.

What you m ust always rem em ber is t hat t he form at for


calling a funct ion includes specifying it s nam e and
enclosing it s param et ers bet ween parent heses. The
non- exist ence of param et ers does not exem pt us from
t he obligat ion t o writ e t he parent heses. For t hat reason
t he call t o printmessage is:

printmessage ();

The parent heses clearly indicat e t hat t his is a call t o a


funct ion and not t he nam e of a variable or som e ot her
C+ + st at em ent . The following call would have been
incorrect :

printmessage;
- 50 -

Cont rol St ruct ures:

8 . Fu n ct ion s ( I I )
Ar gu m e n t s pa sse d by va lu e
a n d by r e fe r e n ce .
Unt il now, in all t he funct ions we have seen, t he
argum ent s passed t o t he funct ions have been passed
by value. This m eans t hat when calling a funct ion wit h
param et ers, what we have passed t o t he funct ion were
copies of t heir values but never t he variables t hem selves.
For exam ple, suppose t hat we called our first funct ion
addition using t he following code:

int x=5, y=3, z;


z = addition ( x , y );

What we did in t his case was t o call t o funct ion addit ion
passing t he values of x and y, i.e. 5 and 3 respect ively,
but not t he variables x and y t hem selves.

This way, when t he funct ion addit ion is called, t he value


of it s local variables a and b becom e 5 and 3 respect ively,
but any m odificat ion t o eit her a or b wit hin t he funct ion
addit ion will not have any effect in t he values of x and y
out side it , because variables x and y were not
t hem selves passed t o t he funct ion, but only copies of
t heir values at t he m om ent t he funct ion was called.

But t here m ight be som e cases where you need t o


m anipulat e from inside a funct ion t he value of an ext ernal
variable. For t hat purpose we can use argum ent s passed
by reference, as in t he funct ion duplicat e of t he following
exam ple:

// passing parameters by
reference
#include <iostream>
using namespace std;

void duplicate (int& a, int& b,


int& c)
{
- 51 -

a*=2;
b*=2;
c*=2;
}

int main ()
{
int x=1, y=3, z=7;
duplicate (x, y, z);
cout << "x=" << x << ", y=" <<
y << ", z=" << z;
return 0;
}
x=2, y=6, z=14

The first t hing t hat should call your at t ent ion is t hat in t he
declarat ion of duplicate t he t ype of each param et er was
followed by an am persand sign ( &) . This am persand is
what specifies t hat t heir corresponding argum ent s are t o
be passed by reference inst ead of by value.

When a variable is passed by reference we are not


passing a copy of it s value, but we are som ehow passing
t he variable it self t o t he funct ion and any m odificat ion
t hat we do t o t he local variables will have an effect in
t heir count erpart variables passed as argum ent s in t he
call t o t he funct ion.

To explain it in anot her way, we associat e a, b and c wit h


t he argum ent s passed on t he funct ion call ( x, y and z)
and any change t hat we do on a wit hin t he funct ion will
affect t he value of x out side it . Any change t hat we do
on b will affect y, and t he sam e wit h c and z.

That is why our program 's out put , t hat shows t he values
st ored in x, y and z aft er t he call t o duplicate, shows
t he values of all t he t hree variables of main doubled.

I f when declaring t he following funct ion:

void duplicate (int& a, int& b, int& c)

we had declared it t his way:

void duplicate (int a, int b, int c)

i.e., wit hout t he am persand signs ( &) , we would have


not passed t he variables by reference, but a copy of
t heir values inst ead, and t herefore, t he out put on
screen of our program would have been t he values of x,
y and z wit hout having been m odified.
- 52 -

Passing by reference is also an effect ive way t o allow a


funct ion t o ret urn m ore t han one value. For exam ple,
here is a funct ion t hat ret urns t he previous and next
num bers of t he first param et er passed.

// more than one returning value


#include <iostream>
using namespace std;

void prevnext (int x, int& prev,


int& next)
{
prev = x-1;
next = x+1;
}

int main ()
{
int x=100, y, z;
prevnext (x, y, z);
cout << "Previous=" << y << ",
Next=" << z;
return 0;
}
Previous=99, Next=101

D e fa u lt va lu e s in pa r a m e t e r s.
When declaring a funct ion we can specify a default value
for each param et er. This value will be used if t he
corresponding argum ent is left blank when calling t o t he
funct ion. To do t hat , we sim ply have t o use t he
assignm ent operat or and a value for t he argum ent s in
t he funct ion declarat ion. I f a value for t hat param et er is
not passed w hen t he funct ion is called, t he default value
is used, but if a value is specified t his default value is
ignored and t he passed value is used inst ead.
For exam ple:

// default values in functions


#include <iostream>
using namespace std;

int divide (int a, int b=2)


{
int r;
r=a/b;
return (r);
}

int main ()
{
cout << divide (12);
cout << endl;
cout << divide (20,4);
return 0;
}
6
5
- 53 -

As we can see in t he body of t he program t here are t wo


calls t o funct ion divide. I n t he first one:

divide (12)

we have only specified one argum ent , but t he funct ion


divide allows up t o t wo. So t he funct ion divide has
assum ed t hat t he second param et er is 2 since t hat is
what we have specified t o happen if t his param et er
was not passed ( not ice t he funct ion declarat ion, which
finishes wit h int b=2, not j ust int b) . Therefore t he
result of t his funct ion call is 6 ( 12/2) .

I n t he second call:

divide (20,4)

t here are t wo param et ers, so t he default value for b


( int b=2) is ignored and b t akes t he value passed as
argum ent , t hat is 4, m aking t he result ret urned equal
t o 5 ( 20/4) .

Ove r loa de d fu n ct ion s.


I n C+ + t wo different funct ions can have t he sam e nam e
if t heir param et er t ypes or num ber are different . That
m eans t hat you can give t he sam e nam e t o m ore t han
one funct ion if t hey have eit her a different num ber of
param et ers or different t ypes in t heir param et ers.
For exam ple:

// overloaded function
#include <iostream>
using namespace std;

int operate (int a, int b)


{
return (a*b);
}

float operate (float a, float b)


{
return (a/b);
}

int main ()
{
int x=5,y=2;
float n=5.0,m=2.0;
cout << operate (x,y);
cout << "\n";
cout << operate (n,m);
cout << "\n";
return 0;
}
10
- 54 -

2.5

I n t his case we have defined t wo funct ions wit h t he


sam e nam e, operate, but one of t hem accept s t w o
param et ers of t ype int and t he ot her one accept s t hem
of t ype float. The com piler knows which one t o call in
each case by exam ining t he t ypes passed as argum ent s
when t he funct ion is called. I f it is called wit h t wo int s as
it s argum ent s it calls t o t he funct ion t hat has t wo int
param et ers in it s prot ot ype and if it is called wit h t wo
float s it will call t o t he one which has t wo float
param et ers in it s prot ot ype.

I n t he first call t o operate t he t wo argum ent s passed


are of t ype int, t herefore, t he funct ion wit h t he first
prot ot ype is called; This funct ion ret urns t he result of
m ult iplying bot h param et ers. While t he second call
passes t wo argum ent s of t ype float, so t he funct ion
wit h t he second prot ot ype is called. This one has a
different behavior: it divides one param et er by t he ot her.
So t he behavior of a call t o operate depends on t he
t ype of t he argum ent s passed because t he funct ion has
been overloaded.

Not ice t hat a funct ion cannot be overloaded only by it s


ret urn t ype. At least one of it s param et ers m ust have a
different t ype.

in lin e fu n ct ion s.
The inline specifier indicat es t he com piler t hat inline
subst it ut ion is preferred t o t he usual funct ion call
m echanism for a specific funct ion. This does not change
t he behavior of a funct ion it self, but is used t o suggest
t o t he com piler t hat t he code generat ed by t he funct ion
body is insert ed at each point t he funct ion is called,
inst ead of being insert ed only once and perform a
regular call t o it , which generally involves som e addit ional
overhead in running t im e.

The form at for it s declarat ion is:

inline type name ( arguments ... ) { instructions ... }

and t he call is j ust like t he call t o any ot her funct ion.


You do not have t o include t he inline keyword when
calling t he funct ion, only in it s declarat ion.

Most com pilers already opt im ize code t o generat e inline


funct ions when it is m ore convenient . This specifier only
indicat es t he com piler t hat inline is preferred for t his
funct ion.

Re cu r sivit y.
Recursivit y is t he propert y t hat funct ions have t o be
called by t hem selves. I t is useful for m any t asks, like
sort ing or calculat e t he fact orial of num bers. For exam ple,
- 55 -

t o obt ain t he fact orial of a num ber ( n! ) t he m at hem at ical


form ula would be:

n! = n * (n-1) * (n-2) * (n-3) ... * 1

m ore concret ely, 5! ( fact orial of 5) would be:

5! = 5 * 4 * 3 * 2 * 1 = 120

and a recursive funct ion t o calculat e t his in C+ + could be:

// factorial calculator
#include <iostream>
using namespace std;

long factorial (long a)


{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
}

int main ()
{
long number;
cout << "Please type a number:
";
cin >> number;
cout << number << "! = " <<
factorial (number);
return 0;
}
Please type a number: 9
9! = 362880

Not ice how in funct ion factorial we included a call t o


it self, but only if t he argum ent passed was great er t han
1, since ot herwise t he funct ion would perform an infinit e
recursive loop in which once it arrived t o 0 it would
cont inue m ult iplying by all t he negat ive num bers ( pr obably
provoking a st ack overflow error on runt im e) .

This funct ion has a lim it at ion because of t he dat a t ype we


used in it s design ( long) for m ore sim plicit y. The result s
given will not be valid for values m uch great er t han 10!
or 15! , depending on t he syst em you com pile it .

D e cla r in g fu n ct ion s.
Unt il now, we have defined all of t he funct ions before
t he first appearance of calls t o t hem in t he source code.
These calls were generally in funct ion main which we
have always left at t he end of t he source code. I f you
t ry t o repeat som e of t he exam ples of funct ions
described so far, but placing t he funct ion main before
any of t he ot her funct ions t hat were called from wit hin it ,
you will m ost likely obt ain com piling errors. The reason is
- 56 -

t hat t o be able t o call a funct ion it m ust have been


declared in som e earlier point of t he code, like we have
done in all our exam ples.

But t here is an alt ernat ive way t o avoid writ ing t he whole
code of a funct ion before it can be used in m ain or in
som e ot her funct ion. This can be achieved by declaring
j ust a prot ot ype of t he funct ion before it is used, inst ead
of t he ent ire definit ion. This declarat ion is short er t han
t he ent ire definit ion, but significant enough for t he
com piler t o det erm ine it s ret urn t ype and t he t ypes of
it s param et ers.

I t s form is:

type name ( argument_type1, argument_type2, ...);

I t is ident ical t o a funct ion definit ion, except t hat it does


not include t he body of t he funct ion it self ( i.e., t he
funct ion st at em ent s t hat in norm al definit ions are
enclosed in braces { }) and inst ead of t hat we end t he
prot ot ype declarat ion wit h a m andat ory sem icolon ( ;) .

The param et er enum erat ion does not need t o include


t he ident ifiers, but only t he t ype specifiers. The inclusion
of a nam e for each param et er as in t he funct ion
definit ion is opt ional in t he prot ot ype declarat ion.
For exam ple, we can declare a funct ion called
protofunction wit h t wo int param et ers wit h any of
t he following declarat ions:

int protofunction (int first, int second);


int protofunction (int, int);

Anyway, including a nam e for each variable m akes t he


prot ot ype m ore legible.

// declaring functions
prototypes
#include <iostream>
using namespace std;

void odd (int a);


void even (int a);

int main ()
{
int i;
do {
cout << "Type a number (0 to
exit): ";
cin >> i;
odd (i);
} while (i!=0);
return 0;
}

void odd (int a)


{
- 57 -

if ((a%2)!=0) cout << "Number


is odd.\n";
else even (a);
}

void even (int a)


{
if ((a%2)==0) cout << "Number
is even.\n";
else odd (a);
}
Type a number (0 to exit): 9
Number is odd.
Type a number (0 to exit): 6
Number is even.
Type a number (0 to exit): 1030
Number is even.
Type a number (0 to exit): 0
Number is even.

This exam ple is indeed not an exam ple of efficiency. I am


sure t hat at t his point you can already m ake a progr am
wit h t he sam e result , but using only half of t he code lines
t hat have been used in t his exam ple. Anyway t his
exam ple illust rat es how prot ot yping works. Moreover, in
t his concret e exam ple t he prot ot yping of at least one of
t he t wo funct ions is necessary in order t o com pile t he
code wit hout errors.

The first t hings t hat we see are t he declarat ion of


funct ions odd and even:

void odd (int a);


void even (int a);

This allows t hese funct ions t o be used before t hey are


defined, for exam ple, in main, which now is locat ed
where som e people find it t o be a m ore logical place
for t he st art of a program : t he beginning of t he source
code.

Anyway, t he reason why t his program needs at least


one of t he funct ions t o be declared before it is defined
is because in odd t here is a call t o even and in even
t here is a call t o odd. I f none of t he t wo funct ions had
been pr eviously declared, a com pilat ion error would
happen, since eit her odd would not not be visible from
even ( because it has st ill not been declared) , or even
would not be visible from odd ( for t he sam e reason) .

Having t he prot ot ype of all funct ions t oget her in t he


sam e place wit hin t he source code is found pract ical by
som e program m ers, and t his can be easily achieved by
declaring all funct ions prot ot ypes at t he beginning of
a program .
- 58 -

Com pound Dat a Types:

9 . Ar r a ys
An array is a series of elem ent s of t he sam e t ype placed
in cont iguous m em ory locat ions t hat can be individually
referenced by adding an index t o a unique ident ifier.

That m eans t hat , for exam ple, we can st ore 5 values of


t ype int in an array wit hout having t o declare 5 different
variables, each one wit h a different ident ifier. I nst ead of
t hat , using an array we can st ore 5 different values of
t he sam e t ype, int for exam ple, wit h a unique ident ifier.

For exam ple, an array t o cont ain 5 int eger values of t ype
int called billy could be represent ed like t his:

where each blank panel represent s an elem ent of t he


array, t hat in t his case are int eger values of t ype int.
These elem ent s are num bered from 0 t o 4 since in arrays
t he first index is always 0, independent ly of it s lengt h.

Like a regular variable, an array m ust be declared


before it is used. A t ypical declarat ion for an array
in C+ + is:

type name [elements];

where type is a valid t ype ( like int, float...) , name is


a valid ident ifier and t he elements field ( which is always
enclosed in square bracket s []) , specifies how m any of
t hese elem ent s t he array has t o cont ain.

Therefore, in order t o declare an array called billy as


t he one shown in t he above diagram it is as sim ple as:

int billy [5];

N OTE: The elements field wit hin bracket s [] which


represent s t he num ber of elem ent s t he array is going
t o hold, m ust be a const ant value, since arrays are
blocks of non- dynam ic m em ory whose size m ust be
det erm ined before execut ion. I n order t o creat e arrays
wit h a variable lengt h dynam ic m em ory is needed,
- 59 -

w hich is explained lat er in t hese t ut orials.

I n it ia lizin g a r r a ys.
When declaring a regular array of local scope ( wit hin a
funct ion, for exam ple) , if we do not specify ot herwise,
it s elem ent s will not be init ialized t o any value by default ,
so t heir cont ent will be undet erm ined unt il we st ore som e
value in t hem . The elem ent s of global and st at ic arrays,
on t he ot her hand, are aut om at ically init ialized wit h t heir
default values, which for all fundam ent al t ypes t his
m eans t hey are filled wit h zeros.

I n bot h cases, local and global, when we declare an


array, we have t he possibilit y t o assign init ial values t o
each one of it s elem ent s by enclosing t he values in
braces { }. For exam ple:

int billy [5] = { 16, 2, 77, 40, 12071 };

This declarat ion would have creat ed an array like t his:

The am ount of values bet ween braces { } m ust not be


larger t han t he num ber of elem ent s t hat we declare for
t he array bet ween square bracket s [ ]. For exam ple,
in t he exam ple of array billy we have declared t hat
it has 5 elem ent s and in t he list of init ial values wit hin
braces { } we have specified 5 values, one for each
elem ent .

When an init ializat ion of values is provided for an array,


C+ + allows t he possibilit y of leaving t he square bracket s
em pt y [ ]. I n t his case, t he com piler will assum e a size
for t he array t hat m at ches t he num ber of values
included bet ween braces { }:

int billy [] = { 16, 2, 77, 40, 12071 };

Aft er t his declarat ion, array billy would be 5 int s long,


since we have provided 5 init ializat ion values.

Acce ssing t h e va lu e s of a n a r r a y.
I n any point of a program in which an array is visible, we
can access t he value of any of it s elem ent s individually
as if it was a norm al variable, t hus being able t o bot h
read and m odify it s value. The form at is as sim ple as:

name[index]

Following t he previous exam ples in which billy had 5


elem ent s and each of t hose elem ent s was of t ype int,
t he nam e which we can use t o refer t o each elem ent is
- 60 -

t he following:

For exam ple, t o st ore t he value 75 in t he t hird elem ent


of billy, we could writ e t he following st at em ent :

billy[2] = 75;

and, for exam ple, t o pass t he value of t he t hird elem ent


of billy t o a variable called a, we could writ e:

a = billy[2];

Therefore, t he expression billy[2] is for all purposes


like a variable of t ype int.

Not ice t hat t he t hird elem ent of billy is specified


billy[2], since t he first one is billy[0], t he second
one is billy[1], and t herefore, t he t hird one is
billy[2]. By t his sam e reason, it s last elem ent is
billy[4]. Therefore, if we writ e billy[ 5] , we would be
accessing t he sixt h elem ent of billy and t herefore
exceeding t he size of t he array.

I n C+ + it is synt act ically correct t o exceed t he valid range


of indices for an array. This can creat e problem s, since
accessing out - of- range elem ent s do not cause com pilat ion
errors but can cause runt im e errors. The reason why t his
is allowed will be seen furt her ahead when we begin t o
use point ers.

At t his point it is im port ant t o be able t o clearly


dist inguish bet ween t he t wo uses t hat bracket s [ ]
have relat ed t o arrays. They perform t wo different t asks:
one is t o specify t he size of arrays when t hey are
declared; and t he second one is t o specify indices for
concret e array elem ent s. Do not confuse t hese t wo
possible uses of bracket s [ ] wit h arrays.

int billy[5]; // declaration of a new array


billy[2] = 75; // access to an element of the array.

I f you read carefully, you will see t hat a t ype specifier


always precedes a variable or array declarat ion, while
it never precedes an access.

Som e ot her valid operat ions wit h arrays:

billy[0] = a;
billy[a] = 75;
b = billy [a+2];
- 61 -

billy[billy[a]] = billy[2] + 5;
// arrays example
#include <iostream>
using namespace std;

int billy [] = {16, 2, 77, 40,


12071};
int n, result=0;

int main ()
{
for ( n=0 ; n<5 ; n++ )
{
result += billy[n];
}
cout << result;
return 0;
}
12206

M u lt idim e n sion a l a r r a ys
Mult idim ensional arrays can be described as " arrays of
arrays" . For exam ple, a bidim ensional array can be
im agined as a bidim ensional t able m ade of elem ent s,
all of t hem of a sam e uniform dat a t ype.

jimmy represent s a bidim ensional array of 3 per 5


elem ent s of t ype int. The way t o declare t his array in
C+ + would be:

int jimmy [3][5];

and, for exam ple, t he way t o reference t he second


elem ent vert ically and fourt h horizont ally in an
expression would be:

jimmy[1][3]

( rem em ber t hat array indices always begin by zero) .


- 62 -

Mult idim ensional arrays are not lim it ed t o t wo indices


( i.e., t wo dim ensions) . They can cont ain as m any indices
as needed. But be careful! The am ount of m em ory
needed for an array rapidly increases wit h each
dim ension. For exam ple:

char century [100][365][24][60][60];

declares an array wit h a char elem ent for each second


in a cent ury, t hat is m ore t han 3 billion chars. So t his
declarat ion would consum e m ore t han 3 gigabyt es of
m em ory!

Mult idim ensional arrays are j ust an abst ract ion for
program m ers, since we can obt ain t he sam e result s wit h
a sim ple array j ust by put t ing a fact or bet ween it s indices:

int jimmy [3][5]; // is equivalent to


int jimmy [15]; // (3 * 5 = 15)

Wit h t he only difference t hat wit h m ult idim ensional


arrays t he com piler rem em bers t he dept h of each
im aginary dim ension for us. Take as exam ple t hese t wo
pieces of code, wit h bot h exact ly t he sam e result . One
uses a bidim ensional array and t he ot her one uses
a sim ple array:

m u lt idim e n sion a l a r r a y pse u do- m u lt idim e n sion a l a r r a y


#define WIDTH 5 #define WIDTH 5
#define HEIGHT 3 #define HEIGHT 3

int jimmy [HEIGHT][WIDTH]; int jimmy [HEIGHT * WIDTH];


int n,m; int n,m;

int main () int main ()


{ {
for (n=0;n<HEIGHT;n++) for (n=0;n<HEIGHT;n++)
for (m=0;m<WIDTH;m++) for (m=0;m<WIDTH;m++)
{ {
jimmy[n][m]=(n+1)*(m+1); jimmy[n*WIDTH+m]=(n+1)*(m+1);
} }
return 0; return 0;
} }

None of t he t wo source codes above pr oduce any out put


on t he screen, but bot h assign values t o t he m em ory
block called j im m y in t he following way:

We have used " defined const ant s" ( #define) t o sim plify
possible fut ure m odificat ions of t he program . For exam ple,
in case t hat we decided t o enlarge t he array t o a height
- 63 -

of 4 inst ead of 3 it could be done sim ply by changing


t he line:

#define HEIGHT 3

t o:

#define HEIGHT 4

wit h no need t o m ake any ot her m odificat ions t o


t he program .

Ar r a ys a s pa r a m e t e r s
At som e m om ent we m ay need t o pass an array t o a
funct ion as a param et er. I n C+ + it is not possible t o
pass a com plet e block of m em ory by value as a
param et er t o a funct ion, but we are allowed t o pass
it s address. I n pract ice t his has alm ost t he sam e
effect and it is a m uch fast er and m ore efficient operat ion.

I n order t o accept arrays as param et er s t he only t hing


t hat we have t o do when declaring t he funct ion is t o
specify in it s param et ers t he elem ent t ype of t he array,
an ident ifier and a pair of void bracket s []. For exam ple,
t he following funct ion:

void procedure (int arg[])

accept s a par am et er of t ype " array of int" called arg.


I n order t o pass t o t his funct ion an array declared as:

int myarray [40];

it would be enough t o writ e a call like t his:

procedure (myarray);

Here you have a com plet e exam ple:

// arrays as parameters
#include <iostream>
using namespace std;

void printarray (int arg[], int


length) {
for (int n=0; n<length; n++)
cout << arg[n] << " ";
cout << "\n";
}

int main ()
{
int firstarray[] = {5, 10,
15};
- 64 -

int secondarray[] = {2, 4, 6,


8, 10};
printarray (firstarray,3);
printarray (secondarray,5);
return 0;
}
5 10 15
2 4 6 8 10

As you can see, t he first param et er ( int arg[]) accept s


any array whose elem ent s are of t ype int, what ever it s
lengt h. For t hat reason we have included a second
param et er t hat t ells t he funct ion t he lengt h of each array
t hat we pass t o it as it s first param et er . This allows
t he for loop t hat print s out t he array t o know t he range
t o it erat e in t he passed array wit hout going out of range.

I n a funct ion declarat ion it is also possible t o include


m ult idim ensional arrays. The form at for a t ridim ensional
array param et er is:

base_type[][depth][depth]

for exam ple, a funct ion wit h a m ult idim ensional array as
argum ent could be:

void procedure (int myarray[][3][4])

Not ice t hat t he first bracket s [] are left blank while t he


following ones are not . This is so because t he com piler
m ust be able t o det erm ine wit hin t he funct ion which is
t he dept h of each addit ional dim ension.

Arrays, bot h sim ple or m ult idim ensional, passed as


funct ion param et ers are a quit e com m on source of errors
for novice program m ers. I recom m end t he reading of t he
chapt er about Point ers for a bet t er underst anding on
how arrays operat e.
- 65 -

Com pound Dat a Types:

1 0 . Ch a r a ct e r Se qu e n ce s

As you m ay already know, t he C+ + St andard Librar y


im plem ent s a powerful st ring class, which is very useful
t o handle and m anipulat e st rings of charact ers. However,
because st rings are in fact sequences of charact ers, we
can represent t hem also as plain arrays of char
elem ent s.

For exam ple, t he following array:

char jenny [20];

is an array t hat can st ore up t o 20 elem ent s of t ype


char. I t can be repr esent ed as:

Therefore, in t his array, in t heory, we can st ore


sequences of charact ers up t o 20 charact ers long. But
we can also st ore short er sequences. For exam ple,
jenny could st ore at som e point in a program eit her t he
sequence "Hello" or t he sequence
"Merry christmas", since bot h are short er t han
20 charact er s.

Therefore, since t he array of charact ers can st ore short er


sequences t han it s t ot al lengt h, a special charact er is
used t o signal t he end of t he valid sequence:
t he null charact er, whose lit eral const ant can be
writ t en as '\0' ( backslash, zero) .

Our array of 20 elem ent s of t ype char, called jenny,


can be repr esent ed st oring t he charact ers sequences
"Hello" and "Merry Christmas" as:

Not ice how aft er t he valid cont ent a null charact er ( '\0')
has been included in order t o indicat e t he end of t he
sequence. The panels in gray color represent char
- 66 -

elem ent s wit h undet erm ined values.

I n it ia liza t ion of n u ll- t e r m in a t e d


ch a r a ct e r se qu e n ce s
Because arrays of charact ers are ordinary arrays t hey
follow all t heir sam e rules. For exam ple, if we want t o
init ialize an array of charact ers wit h som e predet er m ined
sequence of charact ers we can do it j ust like any
ot her array:

char myword[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

I n t his case we would have declared an array of 6


elem ent s of t ype char init ialized wit h t he charact ers t hat
form t he word "Hello" plus a null charact er '\0' at
t he end. But arrays of char elem ent s have an addit ional
m et hod t o init ialize t heir values: using st ring lit erals.

I n t he expressions we have used in som e exam ples in


previous chapt ers, const ant s t hat repr esent ent ire
st rings of charact ers have already showed up several
t im es. These are specified enclosing t he t ext t o becom e
a st ring lit eral bet ween double quot es ( " ) . For exam ple:

"the result is: "

is a const ant st ring lit eral t hat we have probably


used already.

Double quot ed st rings ( ") are lit eral const ant s whose
t ype is in fact a null- t erm inat ed array of charact ers. So
st ring lit erals enclosed bet ween double quot es always
have a null charact er ( '\0') aut om at ically appended
at t he end.

Therefore we can init ialize t he array of char elem ent s


called myword wit h a null- t erm inat ed sequence of
charact ers by eit her one of t hese t wo m et hods:

char myword [] = { 'H', 'e', 'l', 'l', 'o', '\0' };


char myword [] = "Hello";

I n bot h cases t he array of charact ers myword is declared


wit h a size of 6 elem ent s of t ype char: t he 5 charact ers
t hat com pose t he word "Hello" plus a final null charact er
( '\0') which specifies t he end of t he sequence and t hat ,
in t he second case, when using double quot es ( ") it is
appended aut om at ically.

Please not ice t hat w e are t alking about init ializing an


array of charact ers in t he m om ent it is being declared,
and not about assigning values t o t hem once t hey have
already been declared. I n fact because t his t ype of
null- t erm inat ed arrays of charact ers ar e regular arrays
we have t he sam e rest rict ions t hat we have wit h any
- 67 -

ot her array, so we are not able t o copy blocks of dat a


wit h an assignm ent operat ion.

Assum ing mystext is a char[] variable, expressions


wit hin a source code like:

mystext = "Hello";
mystext[] = "Hello";

would not be valid, like neit her would be:

mystext = { 'H', 'e', 'l', 'l', 'o', '\0' };

The reason for t his m ay becom e m ore com prehensible


once you know a bit m ore about point ers, since t hen it
will be clarified t hat an array is in fact a const ant point er
point ing t o a block of m em ory.

Usin g n u ll- t e r m in a t e d
se qu e n ce s of ch a r a ct e r s
Null- t erm inat ed sequences of charact ers are t he nat ural
way of t reat ing st rings in C+ + , so t hey can be used as
such in m any procedures. I n fact , regular st ring lit erals
have t his t ype ( char[]) and can also be used in m ost
cases.

For exam ple, cin and cout support null- t erm inat ed
sequences as valid cont ainers for sequences of
charact ers, so t hey can be used direct ly t o ext ract
st rings of charact ers from cin or t o insert t hem int o
cout. For exam ple:

// null-terminated sequences of
characters
#include <iostream>
using namespace std;

int main ()
{
char question[] = "Please,
enter your first name: ";
char greeting[] = "Hello, ";
char yourname [80];
cout << question;
cin >> yourname;
cout << greeting << yourname
<< "!";
return 0;
}
Please, enter your first name:
John
Hello, John!
- 68 -

As you can see, we have declared t hree arrays of char


elem ent s. The first t wo were init ialized wit h st ring lit eral
const ant s, while t he t hird one was left uninit ialized. I n
any case, we have t o speficify t he size of t he array: in
t he first t wo ( question and greeting) t he size was
im plicit ly defined by t he lengt h of t he lit eral const ant
t hey were init ialized t o. While for yourname we have
explicit ly specified t hat it has a size of 80 chars.

Finally, sequences of charact ers st ored in char arrays


can easily be convert ed int o string obj ect s j ust by
using t he assignm ent operat or:

string mystring;
char myntcs[]="some text";
mystring = myntcs;
- 69 -

Com pound Dat a Types:

1 1 . Poin t e r s

We have already seen how variables are seen as


m em ory cells t hat can be accessed using t heir ident ifiers.
This way we did not have t o care about t he physical
locat ion of our dat a wit hin m em ory, we sim ply used it s
ident ifier whenever we want ed t o refer t o our variable.

The m em ory of your com put er can be im agined as a


succession of m em ory cells, each one of t he m inim al size
t hat com put ers m anage ( one byt e) . These single- byt e
m em ory cells are num bered in a consecut ive way, so as,
wit hin any block of m em ory, every cell has t he sam e
num ber as t he previous one plus one.

This way, each cell can be easily locat ed in t he m em ory


because it has a unique address and all t he m em ory
cells follow a successive pat t ern. For exam ple, if we are
looking for cell 1776 we know t hat it is going t o be right
bet ween cells 1775 and 1777, exact ly one t housand
cells aft er 776 and exact ly one t housand cells before
cell 2776.

Re fe r e n ce ope r a t or ( & )
As soon as we declare a variable, t he am ount of m em ory
needed is assigned for it at a specific locat ion in m em ory
( it s m em ory address) . We generally do not act ively
decide t he ex act locat ion of t he variable wit hin t he panel
of cells t hat we have im agined t he m em ory t o be
- Fort unat ely, t hat is a t ask aut om at ically perform ed by
t he operat ing syst em during runt im e. However, in som e
cases we m ay be int erest ed in knowing t he addr ess
where our variable is being st ored during runt im e in
order t o oper at e wit h relat ive posit ions t o it .

The addr ess t hat locat es a variable wit hin m em ory is


what we call a reference t o t hat variable. This reference
t o a variable can be obt ained by preceding t he ident ifier
of a variable wit h an am persand sign ( &) , known as
reference operat or, and which can be lit erally t ranslat ed
as " address of" . For exam ple:

ted = &andy;

This would assign t o ted t he address of variable andy,


since when preceding t he nam e of t he variable andy wit h
- 70 -

t he reference operat or ( &) we are no longer t alking about


t he cont ent of t he variable it self, but about it s reference
( i.e., it s address in m em ory) .

For now on we are going t o assum e t hat andy is placed


during runt im e in t he m em ory address 1776. This num ber
( 1776) is j ust and arbit rary assum pt ion we are invent ing
right now in order t o help clarify som e concept s in t his
t ut orial, but in realit y, we cannot know before runt im e
t he real value t he addr ess of a variable will have in
m em ory.

Consider t he following code fragm ent :

andy = 25;
fred = andy;
ted = &andy;

The values cont ained in each variable aft er t he execut ion


of t his, are shown in t he following diagram :

First , we have assigned t he value 25 t o andy ( a variable


whose address in m em ory we have assum ed t o be 1776) .

The second st at em ent copied t o fred t he cont ent of


variable andy ( which is 25) . This is a st andard
assignm ent operat ion, as we have done so m any
t im es before.

Finally, t he t hird st at em ent copies t o ted not t he value


cont ained in andy but a reference t o it ( i.e., it s address,
which we have assum ed t o be 1776) . The reason is t hat
in t his t hird assignm ent operat ion we have preceded t he
ident ifier andy wit h t he reference oper at or ( &) , so we
were no longer referring t o t he value of andy but t o it s
reference ( it s address in m em ory) .

The variable t hat st ores t he reference t o anot her variable


( like ted in t he previous exam ple) is what we call
a point er. Point ers are a very powerful feat ure of t he
C+ + language t hat has m any uses in advanced
program m ing. Fart her ahead, we will see how t his t ype
of variable is used and declared.

D e r e fe r e n ce ope r a t or ( * )
We have j ust seen t hat a variable which st ores a
reference t o anot her variable is called a point er. Point ers
- 71 -

are said t o " point t o" t he variable whose reference t hey


st ore.

Using a point er we can direct ly access t he value st ored


in t he variable which it point s t o. To do t his, we sim ply
have t o precede t he point er's ident ifier wit h an ast erisk
( * ) , which act s as derefer ence operat or and t hat can be
lit erally t ranslat ed t o " value point ed by" .

Therefore, following wit h t he values of t he previous


exam ple, if we writ e:

beth = *ted;

( t hat we could read as: " beth equal t o value point ed


by ted" ) beth would t ake t he value 25, since ted is
1776, and t he value point ed by 1776 is 25.

You m ust clearly different iat e t hat t he expression ted


refers t o t he value 1776, while *ted ( wit h an ast erisk
* preceding t he ident ifier) refers t o t he value st ored at
address 1776, which in t his case is 25. Not ice t he
difference of including or not including t he dereference
operat or ( I have included an explanat ory com m ent ary
of how each of t hese t wo expressions could be read) :

beth = ted; // beth equal to ted ( 1776 )


beth = *ted; // beth equal to value pointed by ted ( 25 )

Not ice t he difference bet ween t he refer ence and


derefer ence operat ors:

• & is t he reference operat or and can be read


as " address of"
• * is t he dereference operat or and can be read
as " value point ed by"
Thus, t hey have com plem ent ary ( or opposit e) m eanings.
A variable referenced wit h & can be dereferenced wit h *.

Earlier we perform ed t he following t wo assignm ent


operat ions:
- 72 -

andy = 25;
ted = &andy;

Right aft er t hese t wo st at em ent s, all of t he following


expressions would give t rue as result :

andy == 25
&andy == 1776
ted == 1776
*ted == 25

The first expression is quit e clear considering t hat t he


assignm ent operat ion perform ed on andy was andy=25.
The second one uses t he reference operat or ( &) , which
ret urns t he address of variable andy, which we assum ed
it t o have a value of 1776. The t hird one is som ewhat
obvious since t he second expression was t rue and t he
assignm ent operat ion perform ed on ted was ted=&andy.
The fourt h expression uses t he derefer ence operat or ( *)
t hat , as we have j ust seen, can be read as " value
point ed by" , and t he value point ed by ted is indeed 25.

So, aft er all t hat , you m ay also infer t hat for as long as
t he address point ed by ted rem ains unchanged t he
following expression will also be t rue:

*ted == andy

D e cla r in g va r ia ble s of poin t e r t ype s


Due t o t he abilit y of a point er t o direct ly refer t o t he
value t hat it point s t o, it becom es necessary t o specify
in it s declarat ion w hich dat a t ype a point er is going
point t o. I t is not t he sam e t hing t o point t o a char t han
t o point t o an int or a float.

The declarat ion of point ers follows t his form at :

type * name;

where type is t he dat a t ype of t he value t hat t he point er


is int ended t o point t o. This t ype is not t he t ype of t he
point er it self! but t he t ype of t he dat a t he point er point s
t o. For exam ple:

int * number;
char * character;
float * greatnumber;

These are t hr ee declarat ions of point ers. Each one is


int ended t o point t o a different dat a t ype, but in fact all
of t hem are point ers and all of t hem will occupy t he sam e
am ount of space in m em ory ( t he size in m em ory of a
point er depends on t he plat form where t he code is going
t o run) . Nevert heless, t he dat a t o which t hey point t o do
not occupy t he sam e am ount of space nor are of t he
- 73 -

sam e t ype: t he first one point s t o an int, t he second


one t o a char and t he last one t o a float. Therefore,
alt hough t hese t hree exam ple variables are all of t hem
point ers which occupy t he sam e size in m em ory, t hey
are said t o have different t ypes: int*, char* and
float* respect ively, depending on t he t ype t hey
point t o.

I want t o em phasize t hat t he ast erisk sign ( *) t hat we


use when declaring a point er only m eans t hat it is a
point er ( it is part of it s t ype com pound specifier) , and
should not be confused wit h t he dereference operat or
t hat we have seen a bit earlier, but which is also writ t en
wit h an ast erisk ( *) . They are sim ply t wo different t hings
represent ed wit h t he sam e sign.

Now have a look at t his code:

// my first pointer
#include <iostream>
using namespace std;

int main ()
{
int firstvalue, secondvalue;
int * mypointer;

mypointer = &firstvalue;
*mypointer = 10;
mypointer = &secondvalue;
*mypointer = 20;
cout << "firstvalue is " <<
firstvalue << endl;
cout << "secondvalue is " <<
secondvalue << endl;
return 0;
}
firstvalue is 10
secondvalue is 20

Not ice t hat even t hough we have never direct ly set a


value t o eit her firstvalue or secondvalue, bot h end
up wit h a value set indirect ly t hrough t he use of
mypointer. This is t he procedure:

First , we have assigned as value of mypointer a


reference t o firstvalue using t he reference operat or
( &) . And t hen we have assigned t he value 10 t o t he
m em ory locat ion point ed by mypointer, t hat because
at t his m om ent is point ing t o t he m em ory locat ion of
firstvalue, t his in fact m odifies t he value
of firstvalue.

I n order t o dem onst rat e t hat a point er m ay t ake several


different values during t he sam e program I have
repeat ed t he process wit h secondvalue and t hat sam e
point er, mypointer.
- 74 -

Here is an exam ple a lit t le bit m ore elaborat ed:

// more pointers
#include <iostream>
using namespace std;

int main ()
{
int firstvalue = 5,
secondvalue = 15;
int * p1, * p2;

p1 = &firstvalue; // p1 =
address of firstvalue
p2 = &secondvalue; // p2 =
address of secondvalue
*p1 = 10; // value
pointed by p1 = 10
*p2 = *p1; // value
pointed by p2 = value pointed by
p1
p1 = p2; // p1 = p2
(value of pointer is copied)
*p1 = 20; // value
pointed by p1 = 20

cout << "firstvalue is " <<


firstvalue << endl;
cout << "secondvalue is " <<
secondvalue << endl;
return 0;
}
firstvalue is 10
secondvalue is 20

I have included as a com m ent on each line how t he code


can be read: am persand ( &) as " address of" and ast erisk
( *) as " value point ed by" .

Not ice t hat t here are expr essions wit h point ers p1 and p2,
bot h wit h and wit hout dereference operat or ( *) . The
m eaning of an expression using t he dereference
operat or ( *) is very different from one t hat does not :
When t his operat or precedes t he point er nam e, t he
expression refers t o t he value being point ed, while
when a point er nam e appears wit hout t his operat or,
it refers t o t he value of t he point er it self ( i.e. t he
address of what t he point er is point ing t o) .

Anot her t hing t hat m ay call your at t ent ion is t he line:

int * p1, * p2;

This declares t he t wo point ers used in t he previous


exam ple. But not ice t hat t here is an ast erisk ( * ) for each
point er, in order for bot h t o have t ype int* ( point er
t o int) .
- 75 -

Ot herwise, t he t ype for t he second variable declared in


t hat line would have been int ( and not int*) because
of precedence relat ionships. I f we had writ t en:

int * p1, p2;

p1 would indeed have int* t ype, but p2 would have


t ype int ( spaces do not m at t er at all for t his purpose) .
This is due t o operat or precedence rules. But anyway,
sim ply rem em bering t hat you have t o put one ast er isk
per point er is enough for m ost point er users.

Poin t e r s a n d a r r a ys
The concept of array is very m uch bound t o t he one of
point er. I n fact , t he ident ifier of an array is equivalent
t o t he address of it s first elem ent , as a point er is
equivalent t o t he address of t he first elem ent t hat it
point s t o, so in fact t hey are t he sam e concept .
For exam ple, supposing t hese t wo declarat ions:

int numbers [20];


int * p;

The following assignm ent operat ion would be valid:

p = numbers;

Aft er t hat , p and numbers would be equivalent and


would have t he sam e propert ies. The only difference is
t hat we could change t he value of point er p by anot her
one, whereas numbers will always point t o t he first of
t he 20 elem ent s of t ype int wit h which it was defined.
Therefore, unlike p, which is an ordinary point er,
numbers is an array, and an array can be considered
a const ant point er. Therefore, t he following allocat ion
would not be valid:

numbers = p;

Because numbers is an array, so it operat es as a


const ant point er, and we cannot assign values t o
const ant s.

Due t o t he charact erist ics of variables, all expressions


t hat include point ers in t he following exam ple are
perfect ly valid:

// more pointers
#include <iostream>
using namespace std;

int main ()
{
int numbers[5];
int * p;
- 76 -

p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
return 0;
}
10, 20, 30, 40, 50,

I n t he chapt er about arrays we used br acket s ( [])


several t im es in order t o specify t he index of an elem ent
of t he array t o which we want ed t o refer. Well, t hese
bracket sign operat ors [] are also a dereference
operat or known as offset operat or. They dereference t he
variable t hey follow j ust as * does, but t hey also add t he
num ber bet w een bracket s t o t he address being
derefer enced. For exam ple:

a[5] = 0; // a [offset of 5] = 0
*(a+5) = 0; // pointed by (a+5) = 0

These t wo ex pressions are equivalent and valid bot h


if a is a point er or if a is an array.

Poin t e r in it ia liza t ion


When declaring point ers we m ay want t o explicit ly
specify which variable we want t hem t o point t o:

int number;
int *tommy = &number;

The behavior of t his code is equivalent t o:

int number;
int *tommy;
tommy = &number;

When a point er init ializat ion t akes place we are always


assigning t he reference value t o where t he point er
point s ( tommy) , never t he value being point ed ( *tommy) .
You m ust consider t hat at t he m om ent of declaring a
point er, t he ast erisk ( *) indicat es only t hat it is a point er,
it is not t he dereference operat or ( alt hough bot h use t he
sam e sign: * ) . Rem em ber , t hey are t wo different
funct ions of one sign. Thus, we m ust t ake care not t o
confuse t he previous code wit h:

int number;
int *tommy;
*tommy = &number;

t hat is incorrect , and anyway would not have m uch


sense in t his case if you t hink about it .
- 77 -

As in t he case of arrays, t he com piler allows t he special


case t hat we want t o init ialize t he cont ent at which t he
point er point s wit h const ant s at t he sam e m om ent t he
point er is declared:

char * terry = "hello";

I n t his case, m em ory space is reserved t o cont ain


"hello" and t hen a point er t o t he first charact er of t his
m em ory block is assigned t o terry. I f we im agine t hat
"hello" is st ored at t he m em ory locat ions t hat st art at
addresses 1702, we can represent t he previous
declarat ion as:

I t is im port ant t o indicat e t hat terry cont ains t he value


1702, and not 'h' nor "hello", alt hough 1702 indeed
is t he address of bot h of t hese.

The point er terry point s t o a sequence of charact ers


and can be r ead as if it was an array ( rem em ber t hat
an array is j ust like a const ant point er) . For exam ple,
we can access t he fift h elem ent of t he array wit h any
of t hese t wo expression:

*(terry+4)
terry[4]

Bot h expressions have a value of 'o' ( t he fift h elem ent


of t he array) .

Poin t e r a r it h m e t ics
To conduct arit hm et ical operat ions on point ers is a lit t le
different t han t o conduct t hem on regular int eger dat a
t ypes. To begin wit h, only addit ion and subt ract ion
operat ions are allowed t o be conduct ed wit h t hem , t he
ot hers m ake no sense in t he world of point ers. But bot h
addit ion and subt ract ion have a different behavior wit h
point ers according t o t he size of t he dat a t ype t o which
t hey point .

When we saw t he different fundam ent al dat a t ypes,


we saw t hat som e occupy m ore or less space t han
ot hers in t he m em ory. For exam ple, let 's assum e t hat in
a given com piler for a specific m achine, char t akes 1
byt e, short t akes 2 byt es and long t akes 4.

Suppose t hat we define t hree point ers in t his com piler:


- 78 -

char *mychar;
short *myshort;
long *mylong;

and t hat we know t hat t hey point t o m em ory locat ions


1000, 2000 and 3000 respect ively.

So if we writ e:

mychar++;
myshort++;
mylong++;

mychar, as you m ay expect , would cont ain t he value 1001.


But not so obviously, myshort would cont ain t he value
2002, and mylong would cont ain 3004, even t hough
t hey have each been increased only once. The reason
is t hat when adding one t o a point er we are m aking it
t o point t o t he following elem ent of t he sam e t ype wit h
which it has been defined, and t herefore t he size in
byt es of t he t ype point ed is added t o t he point er.

This is applicable bot h when adding and subt ract ing any
num ber t o a point er. I t would happen exact ly t he sam e
if we writ e:

mychar = mychar + 1;
myshort = myshort + 1;
mylong = mylong + 1;

Bot h t he increase ( ++) and decr ease ( --) operat or s


have great er operat or pr ecedence t han t he derefer ence
operat or ( *) , but bot h have a special behavior when
used as suffix ( t he expression is evaluat ed wit h t he
value it had before being increased) . Therefore, t he
following expression m ay lead t o confusion:

*p++

Because ++ has great er pr ecedence t han *, t his


- 79 -

expression is equivalent t o *(p++). Therefore, what it


does is t o increase t he value of p ( so it now point s t o
t he next elem ent ) , but because + + is used as post fix
t he whole expression is evaluat ed as t he value point ed
by t he original reference ( t he address t he point er
point ed t o before being increased) .

Not ice t he difference wit h:

(*p)++

Here, t he expression would have been evaluat ed as t he


value point ed by p increased by one. The value of p ( t he
point er it self) would not be m odified ( what is being
m odified is what it is being point ed t o by t his point er) .

I f we writ e:

*p++ = *q++;

Because ++ has a higher precedence t han *, bot h p and


q are increased, but because bot h increase operat ors
( ++) are used as post fix and not prefix, t he value
assigned t o *p is *q before bot h p and q are increased.
And t hen bot h are increased. I t would be roughly
equivalent t o:

*p = *q;
++p;
++q;

Like always, I recom m end you t o use parent heses ()


in order t o avoid unexpect ed result s and t o give m ore
legibilit y t o t he code.

Poin t e r s t o poin t e r s
C+ + allows t he use of point ers t hat point t o point ers,
t hat t hese, in it s t urn, point t o dat a ( or even t o ot her
point ers) . I n order t o do t hat , we only need t o add an
ast erisk ( *) for each level of reference in t heir
declarat ions:

char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;

This, supposing t he random ly chosen m em ory locat ions


for each variable of 7230, 8092 and 10502, could
be repr esent ed as:
- 80 -

The value of each variable is writ t en inside each cell;


under t he cells are t heir respect ive addr esses in m em ory.

The new t hing in t his exam ple is variable c, which can be


used in t hree different levels of indirect ion, each one of
t hem would correspond t o a different value:

• c has t ype char** and a value of 8092


• *c has t ype char* and a value of 7230
• **c has t ype char and a value of 'z'

void poin t e r s
The void t ype of point er is a special t ype of point er. I n
C+ + , void represent s t he absence of t ype, so void
point ers are point ers t hat point t o a value t hat has no
t ype ( and t hus also an undet erm ined lengt h and
undet erm ined derefer ence proper t ies) .

This allows void point ers t o point t o any dat a t ype, from
an int eger value or a float t o a st ring of charact ers. But
in exchange t hey have a great lim it at ion: t he dat a
point ed by t hem cannot be direct ly dereferenced ( which
is logical, since we have no t ype t o der eference t o) , and
for t hat reason we will always have t o change t he t ype
of t he void point er t o som e ot her point er t ype t hat
point s t o a concret e dat a t ype before dereferencing it .
This is done by perform ing t ype- cast ings.

One of it s uses m ay be t o pass generic param et ers


t o a funct ion:

// increaser
#include <iostream>
using namespace std;

void increase (void* data, int


size)
{
switch (size)
{
case sizeof(char) :
(*((char*)data))++; break;
case sizeof(int) :
(*((int*)data))++; break;
}
}

int main ()
- 81 -

{
char a = 'x';
int b = 1602;
increase (&a,sizeof(a));
increase (&b,sizeof(b));
cout << a << ", " << b <<
endl;
return 0;
}
y, 1603

sizeof is an operat or int egrat ed in t he C+ + language


t hat ret urns t he size in byt es of it s param et er. For
non- dynam ic dat a t ypes t his value is a const ant .
Therefore, for exam ple, sizeof(char) is 1, because
char t ype is one byt e long.

N u ll poin t e r
A null point er is a regular point er of any point er t ype
w hich has a special value t hat indicat es t hat it is not
point ing t o any valid reference or m em ory address. This
value is t he result of t ype- cast ing t he int eger value zero
t o any point er t ype.

int * p;
p = 0; // p has a null pointer value

Do not confuse null point ers wit h void point ers. A null
point er is a value t hat any point er m ay t ake t o
represent t hat it is point ing t o " nowhere" , while a
void point er is a special t ype of point er t hat can point
t o som ewhere wit hout a specific t ype. One refers t o t he
value st ored in t he point er it self and t he ot her t o t he
t ype of dat a it point s t o.

Poin t e r s t o fu n ct ion s
C+ + allows operat ions wit h point ers t o funct ions. The
t ypical use of t his is for passing a funct ion as an
argum ent t o anot her funct ion, since t hese cannot be
passed der eferenced. I n order t o declar e a point er t o a
funct ion we have t o declare it like t he prot ot ype of t he
funct ion except t hat t he nam e of t he funct ion is
enclosed bet ween parent heses () and an ast erisk ( *)
is insert ed before t he nam e:

// pointer to functions
#include <iostream>
using namespace std;

int addition (int a, int b)


{ return (a+b); }

int subtraction (int a, int b)


{ return (a-b); }

int operation (int x, int y, int


- 82 -

(*functocall)(int,int))
{
int g;
g = (*functocall)(x,y);
return (g);
}

int main ()
{
int m,n;
int (*minus)(int,int) =
subtraction;

m = operation (7, 5,
addition);
n = operation (20, m, minus);
cout <<n;
return 0;
}
8

I n t he exam ple, minus is a point er t o a funct ion t hat has


t wo param et ers of t ype int. I t is im m ediat ely assigned
t o point t o t he funct ion subtraction, all in a single line:

int (* minus)(int,int) = subtraction;


- 83 -

Com pound Dat a Types:

1 2 . D yn a m ic M e m or y
Unt il now, in all our program s, we have only had as
m uch m em ory available as we declared for our variables,
having t he size of all of t hem t o be det erm ined in t he
source code, before t he ex ecut ion of t he program . But ,
what if we need a variable am ount of m em ory t hat can
only be det erm ined during runt im e? For exam ple, in t he
case t hat we need som e user input t o det erm ine t he
necessary am ount of m em ory space.

The answer is dynam ic m em ory, for which C+ + int egrat es


t he operat ors new and delete.

Ope r a t or s n e w a n d n e w [ ]
I n order t o request dynam ic m em ory we use t he oper at or
new. new is followed by a dat a t ype specifier and - if a
sequence of m ore t han one elem ent is required- t he
num ber of t hese wit hin bracket s []. I t ret urns a point er
t o t he beginning of t he new block of m em ory allocat ed.
I t s form is:

pointer = new type


pointer = new type [number_of_elements]

The first expression is used t o allocat e m em ory t o


cont ain one single elem ent of t ype type. The second one
is used t o assign a block ( an array) of elem ent s of t ype
type, where number_of_elements is an int eger value
represent ing t he am ount of t hese. For exam ple:

int * bobby;
bobby = new int [5];

I n t his case, t he syst em dynam ically assigns space for


five elem ent s of t ype int and ret urns a point er t o t he
first elem ent of t he sequence, which is assigned t o bobby.
Therefore, now, bobby point s t o a valid block of m em ory
wit h space for five elem ent s of t ype int.
- 84 -

The first elem ent point ed by bobby can be accessed


eit her wit h t he expression bobby[0] or t he expression
*bobby. Bot h are equivalent as has been explained in
t he sect ion about point ers. The second elem ent can be
accessed eit her wit h bobby[1] or *(bobby+1) and
so on...

You could be wondering t he difference bet ween declaring


a norm al array and assigning dynam ic m em ory t o a point er,
as we have j ust done. The m ost im port ant difference is
t hat t he size of an array has t o be a const ant value,
which lim it s it s size t o what we decide at t he m om ent
of designing t he program , before it s execut ion, whereas
t he dynam ic m em ory allocat ion allows us t o assign
m em ory during t he execut ion of t he program ( runt im e)
using any variable or const ant value as it s size.

The dynam ic m em ory request ed by our program is


allocat ed by t he syst em from t he m em ory heap. However,
com put er m em ory is a lim it ed resource, and it can be
exhaust ed. Therefore, it is im port ant t o have som e
m echanism t o check if our request t o allocat e m em ory
was successful or not .

C+ + provides t wo st andard m et hods t o check if t he


allocat ion was successful:

One is by handling except ions. Using t his m et hod an


except ion of t ype bad_alloc is t hrown when t he
allocat ion fails. Except ions are a powerful C+ + feat ure
explained lat er in t hese t ut orials. But for now you should
know t hat if t his except ion is t hrown and it is not
handled by a specific handler, t he program execut ion
is t erm inat ed.

This except ion m et hod is t he default m et hod used by


new, and is t he one used in a declarat ion like:

bobby = new int [5];

// if it fails an exception is thrown

The ot her m et hod is known as nothrow, and what


happens when it is used is t hat when a m em ory
allocat ion fails, inst ead of t hrowing a bad_alloc
except ion or t erm inat ing t he program , t he point er
ret urned by new is a null point er, and t he program
cont inues it s execut ion.

This m et hod can be specified by using a special obj ect


called nothrow as param et er for new:

bobby = new (nothrow) int [5];

I n t his case, if t he allocat ion of t his block of m em ory


failed, t he failure could be det ect ed by checking if bobby
t ook a null point er value:
- 85 -

int * bobby;
bobby = new (nothrow) int [5];
if (bobby == 0) {
// error assigning memory. Take measures.
};

This nothrow m et hod requires m ore work t han t he


except ion m et hod, since t he value ret urned has t o be
checked aft er each and every m em ory allocat ion, but I
will use it in our exam ples due t o it s sim plicit y. Anyway
t his m et hod can becom e t edious for larger proj ect s,
where t he except ion m et hod is generally preferred. The
except ion m et hod will be explained in det ail lat er in t his
t ut orial.

Ope r a t or de le t e a n d de le t e [ ]
Since t he necessit y of dynam ic m em ory is usually lim it ed
t o specific m om ent s wit hin a program , once it is no longer
needed it should be freed so t hat t he m em ory becom es
available again for ot her request s of dy nam ic m em ory.
This is t he purpose of t he operat or delete,
whose form at is:

delete pointer;
delete [] pointer;

The first expression should be used t o delet e m em ory


allocat ed for a single elem ent , and t he second one for
m em ory allocat ed for arrays of elem ent s.

The value passed as argum ent t o delet e m ust be eit her


a point er t o a m em ory block previously allocat ed wit h
new, or a null point er ( in t he case of a null point er,
delete produces no effect ) .

// rememb-o-matic
#include <iostream>
using namespace std;

int main ()
{
int i,n;
int * p;
cout << "How many numbers
would you like to type? ";
cin >> i;
p= new (nothrow) int[i];
if (p == 0)
cout << "Error: memory could
not be allocated";
else
{
for (n=0; n<i; n++)
{
cout << "Enter number: ";
cin >> p[n];
}
- 86 -

cout << "You have entered:


";
for (n=0; n<i; n++)
cout << p[n] << ", ";
delete[] p;
}
return 0;
}
How many numbers would you like
to type? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067,
8, 32,

Not ice how t he value wit hin bracket s in t he new


st at em ent is a variable value ent ered by t he user
( i) , not a const ant value:

p= new (nothrow) int[i];

But t he user could have ent ered a value for i so big t hat
our syst em could not handle it . For exam ple, when I
t ried t o give a value of 1 billion t o t he " How m any
num bers" quest ion, m y syst em could not allocat e t hat
m uch m em ory for t he program and I got t he t ext m essage
we prepar ed for t his case ( Error: memory could not
be allocated) . Rem em ber t hat in t he case t hat we
t ried t o allocat e t he m em ory wit hout specifying t he
not hrow param et er in t he new expression, an except ion
would be t hrown, which if it 's not handled t erm inat es
t he program .

I t is a good pract ice t o always check if a dynam ic m em ory


block was successfully allocat ed. Ther efore, if you use
t he nothrow m et hod, you should always check t he
value of t he point er ret urned. Ot herwise, use t he
except ion m et hod, even if you do not handle t he
except ion. This way, t he program will t erm inat e at t hat
point wit hout causing t he unexpect ed r esult s of
cont inuing execut ing a code t hat assum es a block of
m em ory t o have been allocat ed when in fact it has not .

D yn a m ic m e m or y in AN SI - C
Operat ors new and delete are exclusive of C+ + . They
are not available in t he C language. But using pure C
language, dynam ic m em ory can also be used t hrough
t he funct ions m alloc, calloc, realloc and free, defined in
t he <cstdlib> header file, and since C+ + is a superset
of C, t hese funct ions are also available t o C+ +
program m ers ( see cst dlib for m ore info) .

The m em ory blocks allocat ed by t hese funct ions are not


necessarily com pat ible wit h t hose ret urned by new, so
- 87 -

each one should be m anipulat ed wit h it s own set of


funct ions or operat ors.
- 88 -

Com pound Dat a Types:

1 3 . D a t a St r u ct u r e s

We have already learned how groups of sequent ial dat a


can be used in C+ + . But t his is som ewhat rest rict ive,
since in m any occasions what we want t o st ore are not
m ere sequences of elem ent s all of t he sam e dat a t y pe,
but set s of different elem ent s wit h different dat a t ypes.

D a t a st r u ct u r e s
A dat a st ruct ure is a group of dat a elem ent s grouped
t oget her under one nam e. These dat a elem ent s,
known as m em bers, can have different t ypes and
different lengt hs. Dat a st ruct ures are declared in C+ +
using t he following synt ax:

st ruct st ruct ure_nam e {


m em ber_t y pe1 m em ber _nam e1;
m em ber_t y pe2 m em ber _nam e2;
m em ber_t y pe3 m em ber _nam e3;
.
.
} obj ect _nam es;

where structure_name is a nam e for t he st ruct ure t ype,


object_name can be a set of valid ident ifiers for obj ect s
t hat have t he t ype of t his st ruct ure. Wit hin braces { }
t here is a list wit h t he dat a m em bers, each one is
specified wit h a t ype and a valid ident ifier as it s nam e.

The first t hing we have t o know is t hat a dat a st ruct ure


creat es a new t ype: Once a dat a st ruct ure is declared,
a new t ype wit h t he ident ifier specified as
structure_name is creat ed and can be used in t he rest
of t he program as if it was any ot her t ype. For exam ple:

struct product {
int weight;
float price;
} ;

product apple;
product banana, melon;

We have first declared a st ruct ure t ype called product


wit h t wo m em bers: weight and price, each of a
- 89 -

different fundam ent al t ype. We have t hen used t his


nam e of t he st ruct ure t ype ( product) t o declare t hree
obj ect s of t hat t ype: apple, banana and melon as we
would have done wit h any fundam ent al dat a t ype.

Once declared, product has becom e a new valid t ype


nam e like t he fundam ent al ones int, char or short
and from t hat point on we are able t o declare obj ect s
( variables) of t his com pound new t ype, like we have
done wit h apple, banana and melon.

Right at t he end of t he struct declarat ion, and before


t he ending sem icolon, we can use t he opt ional field
object_name t o direct ly declare obj ect s of t he st ruct ure
t ype. For exam ple, we can also declare t he st ruct ure
obj ect s apple, banana and melon at t he m om ent we
define t he dat a st ruct ure t ype t his way:

struct product {
int weight;
float price;
} apple, banana, melon;

I t is im port ant t o clearly different iat e bet ween what is


t he st ruct ure t ype nam e, and what is an obj ect ( variable)
t hat has t his st ruct ure t ype. We can inst ant iat e m any
obj ect s ( i.e. variables, like apple, banana and melon)
from a single st ruct ure t ype ( product) .

Once we have declared our t hree obj ect s of a det er m ined


st ruct ure t ype ( apple, banana and melon) we can
operat e direct ly wit h t heir m em bers. To do t hat we use
a dot ( .) insert ed bet ween t he obj ect nam e and t he
m em ber nam e. For exam ple, we could operat e wit h any
of t hese elem ent s as if t hey were st andard variables of
t heir respect ive t ypes:

apple.weight
apple.price
banana.weight
banana.price
melon.weight
melon.price

Each one of t hese has t he dat a t ype cor responding t o


t he m em ber t hey refer t o: apple.weight,
banana.weight and melon.weight are of t ype int,
while apple.price, banana.price and melon.price
are of t ype float.

Let 's see a real exam ple where you can see how a
st ruct ure t ype can be used in t he sam e way as
fundam ent al t ypes:

// example about structures


#include <iostream>
#include <string>
- 90 -

#include <sstream>
using namespace std;

struct movies_t {
string title;
int year;
} mine, yours;

void printmovie (movies_t


movie);

int main ()
{
string mystr;

mine.title = "2001 A Space


Odyssey";
mine.year = 1968;

cout << "Enter title: ";


getline (cin,yours.title);
cout << "Enter year: ";
getline (cin,mystr);
stringstream(mystr) >>
yours.year;

cout << "My favorite movie


is:\n ";
printmovie (mine);
cout << "And yours is:\n ";
printmovie (yours);
return 0;
}

void printmovie (movies_t movie)


{
cout << movie.title;
cout << " (" << movie.year <<
")\n";
}
Enter title: Alien
Enter year: 1979

My favorite movie is:


2001 A Space Odyssey (1968)
And yours is:
Alien (1979)

The exam ple shows how we can use t he m em bers of


an obj ect as regular variables. For exam ple, t he m em ber
yours.year is a valid variable of t ype int, and
mine.title is a valid variable of t ype string.

The obj ect s mine and yours can also be t reat ed as


valid variables of t ype movies_t, for exam ple we have
passed t hem t o t he funct ion printmovie as we would
have done wit h regular variables. Therefore, one of t he
m ost im port ant advant ages of dat a st ruct ures is t hat
we can eit her refer t o t heir m em bers individually or t o
t he ent ire st ruct ure as a block wit h only one ident ifier.
- 91 -

Dat a st ruct ures are a feat ure t hat can be used t o


represent dat abases, especially if we consider t he
possibilit y of building arrays of t hem :

// array of structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

#define N_MOVIES 3

struct movies_t {
string title;
int year;
} films [N_MOVIES];

void printmovie (movies_t


movie);

int main ()
{
string mystr;
int n;

for (n=0; n<N_MOVIES; n++)


{
cout << "Enter title: ";
getline
(cin,films[n].title);
cout << "Enter year: ";
getline (cin,mystr);
stringstream(mystr) >>
films[n].year;
}

cout << "\nYou have entered


these movies:\n";
for (n=0; n<N_MOVIES; n++)
printmovie (films[n]);
return 0;
}

void printmovie (movies_t movie)


{
cout << movie.title;
cout << " (" << movie.year <<
")\n";
}
Enter title: Blade Runner
Enter year: 1982
Enter title: Matrix
Enter year: 1999
Enter title: Taxi Driver
Enter year: 1976

You have entered these movies:


Blade Runner (1982)
Matrix (1999)
Taxi Driver (1976)
- 92 -

Poin t e r s t o st r u ct u r e s
Like any ot her t ype, st ruct ures can be point ed by it s
own t ype of point ers:

struct movies_t {
string title;
int year;
};

movies_t amovie;
movies_t * pmovie;

Here amovie is an obj ect of st ruct ure t ype movies_t,


and pmovie is a point er t o point t o obj ect s of st ruct ure
t ype movies_t. So, t he following code would also be
valid:

pmovie = &amovie;

The value of t he point er pmovie would be assigned t o a


reference t o t he obj ect amovie ( it s m em ory address) .

We will now go wit h anot her exam ple t hat includes


point ers, which will serve t o int roduce a new operat or:
t he arrow operat or ( ->) :

// pointers to structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct movies_t {
string title;
int year;
};

int main ()
{
string mystr;

movies_t amovie;
movies_t * pmovie;
pmovie = &amovie;

cout << "Enter title: ";


getline (cin, pmovie->title);
cout << "Enter year: ";
getline (cin, mystr);
(stringstream) mystr >>
pmovie->year;

cout << "\nYou have


entered:\n";
cout << pmovie->title;
- 93 -

cout << " (" << pmovie->year


<< ")\n";

return 0;
}
Enter title: Invasion of the
body snatchers
Enter year: 1978

You have entered:


Invasion of the body snatchers
(1978)

The previous code includes an im port ant int roduct ion:


t he arrow operat or ( ->) . This is a dereference operat or
t hat is used exclusively wit h point ers t o obj ect s wit h
m em bers. This operat or serves t o access a m em ber of
an obj ect t o which we have a reference.
I n t he exam ple we used:

pmovie->title

Which is for all purposes equivalent t o:

(*pmovie).title

Bot h expressions pmovie->title and


(*pmovie).title are valid and bot h m ean t hat we are
evaluat ing t he m em ber title of t he dat a st ruct ure
point ed by a point er called pmovie. I t m ust be clearly
different iat ed from :

*pmovie.title

which is equivalent t o:

*(pmovie.title)

And t hat would access t he value point ed by a


hypot het ical point er m em ber called title of t he st ruct ure
obj ect pmovie ( which in t his case would not be a point er) .
The following panel sum m arizes possible com binat ions of
point ers and st ruct ure m em bers:

Ex pr e ssion W h a t is e va lu a t e d Equ iva le n t


a.b Mem ber b of obj ect a
a- > b Mem ber b of obj ect point ed by a ( * a) .b
* a.b Value point ed by m em ber b of obj ect a * ( a.b)

N e st in g st r u ct u r e s
St ruct ures can also be nest ed so t hat a valid elem ent of
a st ruct ure can also be on it s t urn anot her st ruct ure.
- 94 -

struct movies_t {
string title;
int year;
};

struct friends_t {
string name;
string email;
movies_t favorite_movie;
} charlie, maria;

friends_t * pfriends = &charlie;

Aft er t he previous declarat ion we could use any of t he


following expressions:

charlie.name
maria.favorite_movie.title
charlie.favorite_movie.year
pfriends->favorite_movie.year

( where, by t he way, t he last t wo expressions refer


t o t he sam e m em ber) .
- 95 -

Com pound Dat a Types:

1 4 . Ot h e r D a t a Type s

D e fin e d da t a t ype s ( t ype de f)


C+ + allows t he definit ion of our own t ypes based on
ot her exist ing dat a t ypes. We can do t his using t he
keyword typedef, whose form at is:

typedef existing_type new_type_name ;

where existing_type is a C+ + fundam ent al or


com pound t ype and new_type_name is t he nam e for t he
new t ype we are defining. For exam ple:

typedef char C;
typedef unsigned int WORD;
typedef char * pChar;
typedef char field [50];

I n t his case we have defined four dat a t ypes: C, WORD,


pChar and field as char, unsigned int, char* and
char[50] respect ively, t hat we could perfect ly use in
declarat ions lat er as any ot her valid t ype:

C mychar, anotherchar, *ptc1;


WORD myword;
pChar ptc2;
field name;

typedef does not creat e different t ypes. I t only creat es


synonym s of exist ing t ypes. That m eans t hat t he t ype of
myword can be considered t o be eit her WORD or
unsigned int, since bot h are in fact t he sam e t ype.

typedef can be useful t o define an alias for a t ype t hat


is frequent ly used wit hin a program . I t is also useful t o
define t ypes when it is possible t hat we will need t o
change t he t ype in lat er versions of our program , or if a
t ype you want t o use has a nam e t hat is t oo long or
confusing.

Un ion s
Unions allow one sam e port ion of m em ory t o be
accessed as different dat a t ypes, since all of t hem are in
- 96 -

fact t he sam e locat ion in m em ory. I t s declarat ion and


use is sim ilar t o t he one of st ruct ures but it s funct ionalit y
is t ot ally different :

union union_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;

All t he elem ent s of t he union declarat ion occupy t he


sam e physical space in m em ory. I t s size is t he one of t he
great est elem ent of t he declarat ion. For exam ple:

union mytypes_t {
char c;
int i;
float f;
} mytypes;

defines t hree elem ent s:

mytypes.c
mytypes.i
mytypes.f

each one wit h a different dat a t ype. Since all of t hem are
referring t o t he sam e locat ion in m em ory, t he m odificat ion
of one of t he elem ent s will affect t he value of all of t hem .
We cannot st ore different values in t hem independent
from each ot her.

One of t he uses a union m ay have is t o unit e an


elem ent ary t ype wit h an array or st ruct ures of sm aller
elem ent s. For exam ple:

union mix_t {
long l;
struct {
short hi;
short lo;
} s;
char c[4];
} mix;

defines t hree nam es t hat allow t o access t he sam e


group of 4 byt es: mix.l, mix.s and mix.c and which
we can use according t o how we want t o access t hese
byt es, as if t hey were a single long- t ype dat a, as if
t hey were t wo short elem ent s or as an array of char
elem ent s, respect ively. I have m ixed t ypes, arrays and
st ruct ures in t he union so t hat you can see t he different
ways t hat we can access t he dat a. For a lit t le- endian
syst em ( m ost PC plat form s) , t his union could be
represent ed as:
- 97 -

The exact alignm ent and order of t he m em bers of a


union in m em ory is plat form dependant . Therefore be
aware of possible port abilit y issues wit h t his t ype of use.

Anonym ous u nions


I n C+ + we have t he opt ion t o declare anonym ous unions.
I f we declare a union wit hout any nam e, t he union will
be anonym ous and we will be able t o access it s m em bers
direct ly by t heir m em ber nam es. For exam ple, look at t he
difference bet ween t hese t wo st ruct ure declarat ions:

st r u ct u r e w it h r e gu la r u n ion st r u ct u r e w it h a n on ym ou s u n ion
struct { struct {
char title[50]; char title[50];
char author[50]; char author[50];
union { union {
float dollars; float dollars;
int yens; int yens;
} price; };
} book; } book;

The only difference bet ween t he t wo pieces of code is


t hat in t he first one we have given a nam e t o t he union
( price) and in t he second one we have not . The
difference is seen when we access t he m em bers
dollars and yens of an obj ect of t his t ype. For an
obj ect of t he first t ype, it would be:

book.price.dollars
book.price.yens

whereas for an obj ect of t he second t y pe, it would be:

book.dollars
book.yens

Once again I rem ind you t hat because it is a union and


not a st ruct , t he m em bers dollars and yens occupy t he
sam e physical space in t he m em ory so t hey cannot be
used t o st ore t wo different values sim ult aneously. You
can set a value for price in dollars or in yens, but
not in bot h.

En u m e r a t ion s ( e n u m )
Enum erat ions creat e new dat a t ypes t o cont ain
som et hing different t hat is not lim it ed t o t he values
- 98 -

fundam ent al dat a t ypes m ay t ake. I t s form is t he


following:

enum enumeration_name {
value1,
value2,
value3,
.
.
} object_names;

For exam ple, we could creat e a new t ype of variable


called color t o st ore colors wit h t he following
declarat ion:

enum colors_t {black, blue, green, cyan,

red, purple, yellow, white};

Not ice t hat we do not include any fundam ent al dat a t ype
in t he declarat ion. To say it som ehow, we have creat ed
a whole new dat a t ype from scrat ch wit hout basing it on
any ot her exist ing t ype. The possible values t hat
variables of t his new t ype color_t m ay t ake are t he
new const ant values included wit hin braces. For exam ple,
once t he colors_t enum erat ion is declared t he following
expressions will be valid:

colors_t mycolor;

mycolor = blue;
if (mycolor == green) mycolor = red;

Enum erat ions are t ype com pat ible wit h num eric
variables, so t heir const ant s are always assigned an
int eger num erical value int ernally. I f it is not specified,
t he int eger value equivalent t o t he first possible value is
equivalent t o 0 and t he following ones follow a + 1
progression. Thus, in our dat a t ype colors_t t hat we
have defined above, black would be equivalent t o 0,
blue would be equivalent t o 1, green t o 2, and so on.

We can explicit ly specify an int eger value for any of t he


const ant values t hat our enum erat ed t ype can t ake.
I f t he const ant value t hat follows it is not given an
int eger value, it is aut om at ically assum ed t he sam e value
as t he previous one plus one. For exam ple:

enum months_t { january=1, february, march,

april, may, june, july,

august, september, october,

november, december} y2k;

I n t his case, variable y2k of enum erat ed t ype months_t


can cont ain any of t he 12 possible values t hat go from
- 99 -

january t o december and t hat are equivalent t o values


bet ween 1 and 12 ( not bet ween 0 and 11, since we
have m ade january equal t o 1) .
- 100 -

Obj ect Orient ed Program m ing:

1 5 . Cla sse s ( I )

A class is an expanded concept of a dat a st ruct ure:


inst ead of holding only dat a, it can hold bot h dat a and
funct ions.

An obj ect is an inst ant iat ion of a class. I n t erm s of


variables, a class would be t he t ype, and an obj ect
would be t he variable.

Classes are generally declared using t he keyword class,


wit h t he following form at :

class class_name {
access_specifier_1:
member1;
access_specifier_2:
member2;
...
} object_names;

Where class_name is a valid ident ifier for t he class,


object_names is an opt ional list of nam es for obj ect s of
t his class. The body of t he declarat ion can cont ain
m em bers, t hat can be eit her dat a or funct ion declarat ions,
and opt ionally access specifiers.

All is very sim ilar t o t he declarat ion on dat a st ruct ures,


except t hat we can now include also funct ions and
m em bers, but also t his new t hing called access specifier.
An access specifier is one of t he following t hree
keywords: private, public or protected. These
specifiers m odify t he access right s t hat t he m em ber s
following t hem acquire:

• private m em bers of a class are accessible only


from wit hin ot her m em ber s of t he sam e class or
from t heir friends.
• protected m em bers are accessible from
m em bers of t heir sam e class and from t heir friends,
but also from m em bers of t heir derived classes.
• Finally, public m em bers are accessible from
anywhere where t he obj ect is visible.

By default , all m em bers of a class declared wit h t he


class keyword have privat e access for all it s m em bers.
Therefore, any m em ber t hat is declared before one ot her
class specifier aut om at ically has privat e access.
- 101 -

For exam ple:

class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void);
} rect;

Declares a class ( i.e., a t ype) called CRectangle and an


obj ect ( i.e., a variable) of t his class called rect. This
class cont ains four m em bers: t wo dat a m em bers of t ype
int ( m em ber x and m em ber y) wit h privat e access
( because privat e is t he default access level) and t wo
m em ber funct ions wit h public access: set_values()
and area(), of which for now we have only included
t heir declarat ion, not t heir definit ion.

Not ice t he difference bet ween t he class nam e and t he


obj ect nam e: I n t he previous exam ple, CRectangle was
t he class nam e ( i.e., t he t ype) , whereas rect was an
obj ect of t ype CRectangle. I t is t he sam e relat ionship
int and a have in t he following declarat ion:

int a;

where int is t he t ype nam e ( t he class) and a is t he


variable nam e ( t he obj ect ) .

Aft er t he previous declarat ions of CRectangle and rect,


we can refer wit hin t he body of t he program t o any of
t he public m em bers of t he obj ect rect as if t hey were
norm al funct ions or norm al variables, j ust by put t ing t he
obj ect 's nam e followed by a dot ( .) and t hen t he nam e
of t he m em ber. All very sim ilar t o what we did wit h plain
dat a st ruct ur es before. For exam ple:

rect.set_values (3,4);
myarea = rect.area();

The only m em bers of rect t hat we cannot access from


t he body of our program out side t he class are x and y,
since t hey have privat e access and t hey can only be
referred from wit hin ot her m em bers of t hat sam e class.

Here is t he com plet e exam ple of class CRect angle:

// classes example
#include <iostream>
using namespace std;

class CRectangle {
int x, y;
public:
void set_values (int,int);
int area () {return (x*y);}
};
- 102 -

void CRectangle::set_values (int


a, int b) {
x = a;
y = b;
}

int main () {
CRectangle rect;
rect.set_values (3,4);
cout << "area: " <<
rect.area();
return 0;
}
area: 12

The m ost im port ant new t hing in t his code is t he operat or


of scope ( ::, t wo colons) included in t he definit ion of
set_values(). I t is used t o define a m em ber of a class
from out side t he class declarat ion it self.

You m ay not ice t hat t he definit ion of t he m em ber funct ion


area() has been included direct ly wit hin t he definit ion of
t he CRectangle class given it s ext rem e sim plicit y,
whereas set_values() has only it s prot ot ype declared
w it hin t he class, but it s definit ion is out side it . I n t his
out side declarat ion, we m ust use t he operat or of scope
( ::) t o specify t hat we are defining a funct ion t hat is a
m em ber of t he class CRectangle and not a regular
global funct ion.

The scope operat or ( ::) specifies t he class t o which t he


m em ber being declared belongs, grant ing exact ly t he
sam e scope propert ies as if t his funct ion definit ion was
direct ly included wit hin t he class definit ion. For exam ple,
in t he funct ion set_values() of t he previous code, we
have been able t o use t he variables x and y, which are
privat e m em bers of class CRectangle, which m eans
t hey are only accessible from ot her m em bers of t heir
class.

The only difference bet ween defining a class m em ber


funct ion com plet ely wit hin it s class and t o include only
t he prot ot ype and lat er it s definit ion, is t hat in t he first
case t he funct ion will aut om at ically be considered an
inline m em ber funct ion by t he com piler, while in t he
second it will be a norm al ( not - inline) class m em ber
funct ion, which in fact supposes no difference in behavior.

Mem ber s x and y have privat e access ( rem em ber t hat if


not hing else is said, all m em bers of a class defined wit h
keyword class have privat e access) . By declaring t hem
privat e we deny access t o t hem from anywhere out side
t he class. This m akes sense, since we have already
defined a m em ber funct ion t o set values for t hose
m em bers wit hin t he obj ect : t he m em ber funct ion
set_values(). Therefore, t he rest of t he program does
not need t o have direct access t o t hem . Perhaps in a so
sim ple exam ple as t his, it is difficult t o see an ut ilit y in
prot ect ing t hose t wo variables, but in great er proj ect s
- 103 -

it m ay be very im port ant t hat values cannot be m odified


in an unexpect ed way ( unexpect ed from t he point of
view of t he obj ect ) .

One of t he great er advant ages of a class is t hat , as any


ot her t ype, we can declare several obj ect s of it . For
exam ple, following wit h t he previous exam ple of class
CRectangle, we could have declared t he obj ect rectb
in addit ion t o t he obj ect rect:

// example: one class, two


objects
#include <iostream>
using namespace std;

class CRectangle {
int x, y;
public:
void set_values (int,int);
int area () {return (x*y);}
};

void CRectangle::set_values (int


a, int b) {
x = a;
y = b;
}

int main () {
CRectangle rect, rectb;
rect.set_values (3,4);
rectb.set_values (5,6);
cout << "rect area: " <<
rect.area() << endl;
cout << "rectb area: " <<
rectb.area() << endl;
return 0;
}
rect area: 12
rectb area: 30

I n t his concret e case, t he class ( t ype of t he obj ect s) t o


w hich w e are t alking about is CRectangle, of which t here
are t wo inst ances or obj ect s: rect and rectb. Each one
of t hem has it s own m em ber variables and m em ber
funct ions.

Not ice t hat t he call t o rect.area() does not give t he


sam e result as t he call t o rectb.area(). This is because
each obj ect of class CRect angle has it s own variables
x and y, as t hey, in som e way, have also t heir own
funct ion m em bers set_value() and area() t hat each
uses it s obj ect 's own variables t o oper at e.

That is t he basic concept of obj ect - orient ed program m ing:


Dat a and funct ions are bot h m em bers of t he obj ect . We
no longer use set s of global variables t hat we pass from
one funct ion t o anot her as param et ers, but inst ead we
handle obj ect s t hat have t heir own dat a and funct ions
- 104 -

em bedded as m em bers. Not ice t hat we have not had t o


give any param et ers in any of t he calls t o rect.area or
rectb.area. Those m em ber funct ions direct ly used t he
dat a m em ber s of t heir respect ive obj ect s rect and rectb.

Con st r u ct or s a n d de st r u ct or s
Obj ect s generally need t o init ialize variables or assign
dynam ic m em ory during t heir process of creat ion t o
becom e oper at ive and t o avoid ret urning unexpect ed
values during t heir execut ion. For exam ple, what would
happen if in t he previous exam ple we called t he m em ber
funct ion area() before having called funct ion
set_values()? Probably we would have got t en an
undet erm ined result since t he m em ber s x and y would
have never been assigned a value.

I n order t o avoid t hat , a class can include a special


funct ion called constructor, which is aut om at ically
called whenever a new obj ect of t his class is creat ed.
This const ruct or funct ion m ust have t he sam e nam e as
t he class, and cannot have any ret urn t ype;
not even void.

We are going t o im plem ent CRectangle including a


const ruct or:

// example: class constructor


#include <iostream>
using namespace std;

class CRectangle {
int width, height;
public:
CRectangle (int,int);
int area () {return
(width*height);}
};

CRectangle::CRectangle (int a,
int b) {
width = a;
height = b;
}

int main () {
CRectangle rect (3,4);
CRectangle rectb (5,6);
cout << "rect area: " <<
rect.area() << endl;
cout << "rectb area: " <<
rectb.area() << endl;
return 0;
}
rect area: 12
rectb area: 30

As you can see, t he result of t his exam ple is ident ical t o


- 105 -

t he previous one. But now we have rem oved t he m em ber


funct ion set_values(), and have included inst ead a
const ruct or t hat perform s a sim ilar act ion: it init ializes t he
values of x and y wit h t he param et ers t hat are
passed t o it .

Not ice how t hese argum ent s are passed t o t he


const ruct or at t he m om ent at which t he obj ect s of t his
class are creat ed:

CRectangle rect (3,4);


CRectangle rectb (5,6);

Const ruct ors cannot be called explicit ly as if t hey were


regular m em ber funct ions. They are only execut ed when
a new obj ect of t hat class is creat ed.

You can also see how neit her t he const ruct or prot ot ype
declarat ion ( wit hin t he class) nor t he lat t er const ruct or
definit ion include a ret urn value; not even void.

The dest ruct or fulfills t he opposit e funct ionalit y. I t is


aut om at ically called when an obj ect is dest royed, eit her
because it s scope of exist ence has finished ( for exam ple,
if it was defined as a local obj ect wit hin a funct ion and
t he funct ion ends) or because it is an obj ect dynam ically
assigned and it is released using t he operat or delet e.

The dest ruct or m ust have t he sam e nam e as t he class,


but preceded wit h a t ilde sign ( ~) and it m ust also
ret urn no value.

The use of dest ruct ors is especially suit able when an


obj ect assigns dynam ic m em ory during it s lifet im e and at
t he m om ent of being dest royed we want t o release t he
m em ory t hat t he obj ect was allocat ed.

// example on constructors and


destructors
#include <iostream>
using namespace std;

class CRectangle {
int *width, *height;
public:
CRectangle (int,int);
~CRectangle ();
int area () {return (*width
* *height);}
};

CRectangle::CRectangle (int a,
int b) {
width = new int;
height = new int;
*width = a;
*height = b;
}
- 106 -

CRectangle::~CRectangle () {
delete width;
delete height;
}

int main () {
CRectangle rect (3,4), rectb
(5,6);
cout << "rect area: " <<
rect.area() << endl;
cout << "rectb area: " <<
rectb.area() << endl;
return 0;
}
rect area: 12
rectb area: 30

Ove r loa din g Con st r u ct or s


Like any ot her funct ion, a const ruct or can also be
overloaded wit h m ore t han one funct ion t hat have t he
sam e nam e but different t ypes or num ber of param et ers.
Rem em ber t hat for overloaded funct ions t he com piler will
call t he one whose param et ers m at ch t he argum ent s
used in t he funct ion call. I n t he case of const ruct ors,
which are aut om at ically called when an obj ect is creat ed,
t he one execut ed is t he one t hat m at ches t he argum ent s
passed on t he obj ect declarat ion:

// overloading class
constructors
#include <iostream>
using namespace std;

class CRectangle {
int width, height;
public:
CRectangle ();
CRectangle (int,int);
int area (void) {return
(width*height);}
};

CRectangle::CRectangle () {
width = 5;
height = 5;
}

CRectangle::CRectangle (int a,
int b) {
width = a;
height = b;
}

int main () {
CRectangle rect (3,4);
CRectangle rectb;
cout << "rect area: " <<
rect.area() << endl;
cout << "rectb area: " <<
- 107 -

rectb.area() << endl;


return 0;
}
rect area: 12
rectb area: 25

I n t his case, rectb was declared wit hout any argum ent s,
so it has been init ialized wit h t he const ruct or t hat has no
param et ers, w hich init ializes bot h width and height
wit h a value of 5.

I m por t a n t : Not ice how if we declare a new obj ect and


we want t o use it s default const ruct or ( t he one wit hout
param et ers) , we do not include parent heses ():

CRectangle rectb; // right


CRectangle rectb(); // wrong!

D e fa u lt con st r u ct or
I f you do not declare any const ruct ors in a class definit ion,
t he com piler assum es t he class t o have a default
const ruct or wit h no argum ent s. Therefore, aft er declaring
a class like t his one:

class CExample {
public:
int a,b,c;
void multiply (int n, int m) { a=n; b=m; c=a*b; };
};

The com piler assum es t hat CExample has a default


const ruct or, so you can declare obj ect s of t his class by
sim ply declaring t hem wit hout any argum ent s:

CExample ex;

But as soon as you declare your own const ruct or for a


class, t he com piler no longer provides an im plicit default
const ruct or. So you have t o declare all obj ect s of t hat
class according t o t he const ruct or prot ot ypes you
defined for t he class:

class CExample {
public:
int a,b,c;
CExample (int n, int m) { a=n; b=m; };
void multiply () { c=a*b; };
};

Here we have declared a const ruct or t hat t akes t wo


param et ers of t ype int . Therefore t he following obj ect
declarat ion would be correct :

CExample ex (2,3);
- 108 -

But ,

CExample ex;

Would not be correct , since we have declared t he class


t o have an explicit const ruct or, t hus replacing t he default
const ruct or.

But t he com piler not only creat es a default const ruct or


for you if you do not specify your own. I t provides t hree
special m em ber funct ions in t ot al t hat are im plicit ly
declared if you do not declare your own. These are t he
copy const ruct or, t he copy assignm ent operat or, and t he
default dest r uct or.

The copy const ruct or and t he copy assignm ent oper at or


copy all t he dat a cont ained in anot her obj ect t o t he dat a
m em bers of t he current obj ect . For CExample, t he copy
const ruct or im plicit ly declared by t he com piler would be
som et hing sim ilar t o:

CExample::CExample (const CExample& rv) {


a=rv.a; b=rv.b; c=rv.c;
}

Therefore, t he t wo following obj ect declarat ions would


be correct :

CExample ex (2,3);
CExample ex2 (ex); // copy constructor (data copied from ex)

Poin t e r s t o cla sse s


I t is perfect ly valid t o creat e point ers t hat point t o classes.
We sim ply have t o consider t hat once declared, a class
becom es a v alid t ype, so we can use t he class nam e as
t he t ype for t he point er. For exam ple:

CRectangle * prect;

is a point er t o an obj ect of class CRectangle.

As it happened wit h dat a st ruct ures, in order t o refer


direct ly t o a m em ber of an obj ect point ed by a point er
we can use t he arrow operat or ( ->) of indirect ion. Here
is an exam ple wit h som e possible com binat ions:

// pointer to classes example


#include <iostream>
using namespace std;

class CRectangle {
int width, height;
public:
void set_values (int, int);
- 109 -

int area (void) {return


(width * height);}
};

void CRectangle::set_values (int


a, int b) {
width = a;
height = b;
}

int main () {
CRectangle a, *b, *c;
CRectangle * d = new
CRectangle[2];
b= new CRectangle;
c= &a;
a.set_values (1,2);
b->set_values (3,4);
d->set_values (5,6);
d[1].set_values (7,8);
cout << "a area: " << a.area()
<< endl;
cout << "*b area: " << b-
>area() << endl;
cout << "*c area: " << c-
>area() << endl;
cout << "d[0] area: " <<
d[0].area() << endl;
cout << "d[1] area: " <<
d[1].area() << endl;
delete[] d;
delete b;
return 0;
}
a area: 2
*b area: 12
*c area: 2
d[0] area: 30
d[1] area: 56

Next you have a sum m ary on how can you read som e
point er and class operat ors ( *, &, ., ->, [ ]) t hat appear
in t he previous exam ple:

e x pr e ssion ca n be r e a d a s
*x point ed by x
&x address of x
x.y m em ber y of obj ect x
x- > y m em ber y of obj ect point ed by x
( * x) .y m em ber y of obj ect point ed by x ( equivalent t o t he previous one)
x[ 0] first obj ect point ed by x
x[ 1] second obj ect point ed by x
x[ n] ( n+ 1) t h obj ect point ed by x

Be sure t hat you underst and t he logic under all of t hese


expressions before proceeding wit h t he next sect ions.
I f you have doubt s, read again t his sect ion and/ or
- 110 -

dat a st ruct ur es.

Cla sse s de fin e d w it h st r u ct a n d u n ion


Classes can be defined not only wit h keyword class,
but also wit h keywords struct and union.

The concept s of class and dat a st ruct ur e are so sim ilar


t hat bot h keywords have in C+ + t he exact sam e
funct ionalit y except t hat t he m em bers of classes
declared wit h keyword struct have public access by
default , inst ead of privat e access, as classes declared
wit h keyword class have. That is t he only difference.
For all ot her purposes bot h keywords are equivalent .

The concept under unions is different from t han of


struct and class, since unions only st ore one dat a
m em ber at a t im e, but t hey are also classes and t hus can
also hold funct ion m em bers. The default access in
union classes is public.
- 111 -

Obj ect Orient ed Program m ing:

1 6 . Cla sse s ( I I )
Ove r loa din g ope r a t or s
C+ + incorporat es t he opt ion t o use st andard operat ors
t o perform operat ions wit h classes in addit ion t o wit h
fundam ent al t ypes. For exam ple:

int a, b, c;
a = b + c;

This is obviously valid code in C+ + , since t he different


variables of t he addit ion are all fundam ent al t ypes.
Nevert heless, it is not so obvious t hat we could perform
an operat ion sim ilar t o t he following one:

struct {
string product;
float price;
} a, b, c;
a = b + c;

I n fact , t his will cause a com pilat ion error, since we have
not defined t he behavior our class should have wit h
addit ion operat ions. However, t hanks t o t he C+ + feat ure
t o overload operat ors, we can design classes able t o
perform oper at ions using st andard operat ors. Here is a
list of all t he operat ors t hat can be overloaded:

Ove r loa da ble ope r a t or s


+ - * / = < > += -= *= /= << >>
<<= >>= == != <= >= ++ -- % & ^ ! |
~ &= ^= |= && || %= [] () , ->* -> new
delete new[] delete[]

To overload an operat or in order t o use it wit h classes


we declare operat or funct ions, which are regular funct ions
whose nam es are t he operator keyword followed by
t he operat or sign t hat we want t o overload.
The form at is:

type operator sign (parameters) { /*...*/ }

Here you have an exam ple t hat overloads t he addit ion


operat or ( +) . We are going t o creat e a class t o st ore
bidim ensional vect ors and t hen we are going t o add t wo
of t hem : a(3,1) and b(1,2). The addit ion of t wo
bidim ensional vect ors is an operat ion as sim ple as adding
- 112 -

t he t wo x coordinat es t o obt ain t he result ing x coordinat e


and adding t he t wo y coordinat es t o obt ain t he result ing
y. I n t his case t he result will be (3+1,1+2) = (4,3).

// vectors: overloading
operators example
#include <iostream>
using namespace std;

class CVector {
public:
int x,y;
CVector () {};
CVector (int,int);
CVector operator +
(CVector);
};

CVector::CVector (int a, int b)


{
x = a;
y = b;
}

CVector CVector::operator+
(CVector param) {
CVector temp;
temp.x = x + param.x;
temp.y = y + param.y;
return (temp);
}

int main () {
CVector a (3,1);
CVector b (1,2);
CVector c;
c = a + b;
cout << c.x << "," << c.y;
return 0;
}
4,3

I t m ay be a lit t le confusing t o see so m any t im es t he


CVector ident ifier. But , consider t hat som e of t hem refer
t o t he class nam e ( t ype) CVector and som e ot hers are
funct ions wit h t hat nam e ( const ruct ors m ust have t he
sam e nam e as t he class) . Do not confuse t hem :

CVector (int, int);


// function name CVector (constructor)
CVector operator+ (CVector);
// function returns a CVector

The funct ion operator+ of class CVector is t he one t hat


is in charge of overloading t he addit ion operat or ( +) . This
funct ion can be called eit her im plicit ly using t he operat or,
or explicit ly using t he funct ion nam e:
- 113 -

c = a + b;
c = a.operator+ (b);

Bot h expressions are equivalent .

Not ice also t hat we have included t he em pt y const r uct or


( wit hout param et ers) and we have defined it wit h an
em pt y block:

CVector () { };

This is necessary, since we have explicit ly declared


anot her const ruct or:

CVector (int, int);

And when we explicit ly declare any const ruct or, wit h any
num ber of param et ers, t he default const ruct or wit h no
param et ers t hat t he com piler can declare aut om at ically
is not declared, so we need t o declare it ourselves in
order t o be able t o const ruct obj ect s of t his t ype wit hout
param et ers. Ot herwise, t he declarat ion:

CVector c;

included in main() would not have been valid.

Anyway, I have t o warn you t hat an em pt y block is a bad


im plem ent at ion for a const ruct or, since it does not fulfill
t he m inim um funct ionalit y t hat is generally expect ed from
a const ruct or, which is t he init ializat ion of all t he m em ber
variables in it s class. I n our case t his const ruct or leaves
t he variables x and y undefined. Therefore, a m ore
advisable definit ion would have been som et hing
sim ilar t o t his:

CVector () { x=0; y=0; };

which in order t o sim plify and show only t he point of t he


code I have not included in t he exam ple.

As well as a class includes a default const ruct or and a


copy const ruct or even if t hey are not declared, it also
includes a default definit ion for t he assignm ent oper at or
( =) wit h t he class it self as param et er. The behavior
which is defined by default is t o copy t he whole cont ent
of t he dat a m em bers of t he obj ect passed as argum ent
( t he one at t he right side of t he sign) t o t he one at
t he left side:

CVector d (2,3);
CVector e;
e = d; // copy assignment operator
- 114 -

operat or m em ber funct ion im plem ent ed by default .


Of course, you can redefine it t o any ot her funct ionalit y
t hat you want , like for exam ple, copy only cert ain class
m em bers or perform addit ional init ializat ion procedures.

The overload of operat ors does not force it s operat ion


t o bear a relat ion t o t he m at hem at ical or usual m eaning
of t he operat or, alt hough it is recom m ended. For ex am ple,
t he code m ay not be very int uit ive if you use operator
+ t o subt ract t wo classes or operator== t o fill wit h zeros
a class, alt hough it is perfect ly possible t o do so.

Alt hough t he prot ot ype of a funct ion operator+ can


seem obvious since it t akes what is at t he right side of
t he operat or as t he param et er for t he operat or m em ber
funct ion of t he obj ect at it s left side, ot her operat ors
m ay not be so obvious. Here you have a t able wit h a
sum m ary on how t he different operat or funct ions have
t o be declared ( replace @ by t he operat or in each case) :

Ex pr e ssion Ope r a t or M e m be r fu n ct ion Globa l fu n ct ion


@a + - * & ! ~ + + -- A: : operat or @( ) operat or@( A)
a@ + + -- A: : operat or @( int ) operat or@( A,int )
+ - * / % ^ & | < > = = != < = > =
a@b A: : operat or @ ( B) operat or@( A,B)
< < > > && | | ,
= + = - = * = / = % = ^ = &= | = < < =
a@b A: : operat or @ ( B) -
> > = []
A: : operat or( ) ( B,
a( b, c...) () -
C...)
a- > x -> A: : operat or- > ( ) -

Where a is an obj ect of class A, b is an obj ect of class B


and c is an obj ect of class C.

You can see in t his panel t hat t here are t wo ways t o


overload som e class operat ors: as a m em ber funct ion
and as a global funct ion. I t s use is indist inct , nevert heless
I rem ind you t hat funct ions t hat are not m em bers of a
class cannot access t he pr ivat e or prot ect ed m em bers of
t hat class unless t he global funct ion is it s friend
( friendship is explained lat er) .

Th e k e yw or d t h is
The keyword this represent s a point er t o t he obj ect
whose m em ber funct ion is being execut ed.
I t is a point er t o t he obj ect it self.

One of it s uses can t o check if a param et er passed t o a


m em ber funct ion is t he obj ect it self. For exam ple,

// this
#include <iostream>
using namespace std;

class CDummy {
public:
int isitme (CDummy& param);
- 115 -

};

int CDummy::isitme (CDummy&


param)
{
if (&param == this) return
true;
else return false;
}

int main () {
CDummy a;
CDummy* b = &a;
if ( b->isitme(a) )
cout << "yes, &a is b";
return 0;
}
yes, &a is b

I t is also frequent ly used in operator= m em ber funct ions


t hat ret urn obj ect s by reference ( avoiding t he use of
t em porary obj ect s) . Following wit h t he vect or's exam ples
seen before we could have writ t en an operator= funct ion
sim ilar t o t his one:

CVector& CVector::operator= (const CVector& param)


{
x=param.x;
y=param.y;
return *this;
}

I n fact t his funct ion is very sim ilar t o t he code t hat t he


com piler generat es im plicit ly for t his class if we do not
include an operator= m em ber funct ion t o copy obj ect s
of t his class.

St a t ic m e m be r s
A class can cont ain st at ic m em bers, eit her dat a or
funct ions.

St at ic dat a m em bers of a class are also known as


" class variables" , because t here is only one unique value
for all t he obj ect s of t hat sam e class. Their cont ent is not
different from one obj ect of t his class t o anot her.

For exam ple, it m ay be used for a variable wit hin a class


t hat can cont ain a count er wit h t he num ber of obj ect s
of t hat class t hat have been creat ed, as in t he
following exam ple:

// static members in classes


#include <iostream>
using namespace std;

class CDummy {
public:
- 116 -

static int n;
CDummy () { n++; };
~CDummy () { n--; };
};

int CDummy::n=0;

int main () {
CDummy a;
CDummy b[5];
CDummy * c = new CDummy;
cout << a.n << endl;
delete c;
cout << CDummy::n << endl;
return 0;
}
7
6

I n fact , st at ic m em bers have t he sam e propert ies as


global variables but t hey enj oy class scope. For t hat
reason, and t o avoid t hem t o be declared several t im es,
we can only include t he prot ot ype ( it s declarat ion) in t he
class declarat ion but not it s definit ion ( it s init ializat ion) .
I n order t o init ialize a st at ic dat a- m em ber we m ust
include a form al definit ion out side t he class, in t he global
scope, as in t he previous exam ple:

int CDummy::n=0;

Because it is a unique variable value for all t he obj ect s


of t he sam e class, it can be referred t o as a m em ber of
any obj ect of t hat class or even direct ly by t he class
nam e ( of course t his is only valid for st at ic m em bers) :

cout << a.n;


cout << CDummy::n;

These t wo calls included in t he previous exam ple are


referring t o t he sam e variable: t he st at ic variable n
wit hin class CDummy shared by all obj ect s of t his class.

Once again, I rem ind you t hat in fact it is a global variable.


The only difference is it s nam e and possible access
rest rict ions out side it s class.

Just as we m ay include st at ic dat a wit hin a class, we can


also include st at ic funct ions. They represent t he sam e:
t hey are global funct ions t hat are called as if t hey were
obj ect m em bers of a given class. They can only refer t o
st at ic dat a, in no case t o non- st at ic m em bers of t he class,
as well as t hey do not allow t he use of t he keyword this,
since it m akes reference t o an obj ect point er and t hese
funct ions in fact are not m em bers of any obj ect but direct
m em bers of t he class.
- 117 -

Obj ect Orient ed Program m ing:

1 7 . Fr ie n dsh ip a n d
I n h e r it a n ce

Fr ie n d fu n ct ion s
I n principle, privat e and prot ect ed m em bers of a class
cannot be accessed from out side t he sam e class in
which t hey are declared. However, t his rule does not
affect friends.

Friends are funct ions or classes declared as such.

I f we want t o declare an ext ernal funct ion as friend of a


class, t hus allowing t his funct ion t o have access t o t he
privat e and prot ect ed m em bers of t his class, we do it by
declaring a prot ot ype of t his ext ernal funct ion wit hin t he
class, and preceding it wit h t he keyword friend:

// friend functions
#include <iostream>
using namespace std;

class CRectangle {
int width, height;
public:
void set_values (int, int);
int area () {return (width *
height);}
friend CRectangle duplicate
(CRectangle);
};

void CRectangle::set_values (int


a, int b) {
width = a;
height = b;
}

CRectangle duplicate (CRectangle


rectparam)
{
CRectangle rectres;
rectres.width =
rectparam.width*2;
rectres.height =
- 118 -

rectparam.height*2;
return (rectres);
}

int main () {
CRectangle rect, rectb;
rect.set_values (2,3);
rectb = duplicate (rect);
cout << rectb.area();
return 0;
}
24

The duplicate funct ion is a friend of CRectangle. From


wit hin t hat funct ion we have been able t o access t he
m em bers width and height of different obj ect s of t ype
CRectangle, which are privat e m em bers. Not ice t hat
neit her in t he declarat ion of duplicate() nor in it s
lat er use in main() have we considered duplicate a
m em ber of class CRectangle. I t isn't ! I t sim ply has
access t o it s privat e and prot ect ed m em bers wit hout
being a m em ber.

The friend funct ions can serve, for exam ple, t o conduct
operat ions bet ween t wo different classes. Generally,
t he use of friend funct ions is out of an obj ect - orient ed
program m ing m et hodology, so whenever possible it is
bet t er t o use m em bers of t he sam e class t o perform
operat ions wit h t hem . Such as in t he previous exam ple,
it would have been short er t o int egrat e duplicate()
wit hin t he class CRectangle.

Fr ie n d cla sse s
Just as we have t he possibilit y t o define a friend funct ion,
we can also define a class as friend of anot her one,
grant ing t hat second class access t o t he prot ect ed and
privat e m em bers of t he first one.

// friend class
#include <iostream>
using namespace std;

class CSquare;

class CRectangle {
int width, height;
public:
int area ()
{return (width * height);}
void convert (CSquare a);
};

class CSquare {
private:
int side;
public:
void set_side (int a)
{side=a;}
- 119 -

friend class CRectangle;


};

void CRectangle::convert
(CSquare a) {
width = a.side;
height = a.side;
}

int main () {
CSquare sqr;
CRectangle rect;
sqr.set_side(4);
rect.convert(sqr);
cout << rect.area();
return 0;
}
16

I n t his exam ple, we have declared CRectangle as a


friend of CSquare so t hat CRectangle m em ber funct ions
could have access t o t he prot ect ed and privat e m em bers
of CSquare, m ore concret ely t o CSquare::side, which
describes t he side widt h of t he square.

You m ay also see som et hing new at t he beginning of t he


program : an em pt y declar at ion of class CSquare. This is
necessary because wit hin t he declarat ion of CRectangle
we refer t o CSquare ( as a param et er in convert()) . The
definit ion of CSquare is included lat er, so if we did not
include a previous em pt y declarat ion for CSquare t his
class would not be visible from wit hin t he definit ion of
CRectangle.

Consider t hat friendships are not corresponded if we do


not explicit ly specify so. I n our exam ple, CRectangle is
considered as a friend class by CSquare, but CRectangle
does not consider CSquare t o be a friend, so CRectangle
can access t he prot ect ed and privat e m em bers of
CSquare but not t he reverse way. Of course, we could
have declared also CSquare as friend of CRectangle
if we want ed t o.

Anot her propert y of friendships is t hat t hey are


not t ransit ive: The friend of a friend is not considered t o
be a friend unless explicit ly specified.

I n h e r it a n ce be t w e e n cla sse s
A key feat ure of C+ + classes is inherit ance. I nherit ance
allows t o creat e classes which are derived from ot her
classes, so t hat t hey aut om at ically include som e of it s
" parent 's" m em bers, plus it s own. For exam ple, we are
going t o suppose t hat we want t o declare a series of
classes t hat describe polygons like our CRectangle, or
like CTriangle. They have cert ain com m on propert ies,
such as bot h can be described by m eans of only t wo
sides: height and base.
- 120 -

This could be represent ed in t he world of classes wit h a


class CPolygon from which we would derive t he t wo
ot her ones: CRectangle and CTriangle.

The class CPolygon would cont ain m em bers t hat are


com m on for bot h t ypes of polygon. I n our case: width
and height. And CRectangle and CTriangle would
be it s derived classes, wit h specific feat ures t hat are
different from one t ype of polygon t o t he ot her.

Classes t hat are derived from ot hers inherit all t he


accessible m em bers of t he base class. That m eans t hat if
a base class includes a m em ber A and we derive it t o
anot her class wit h anot her m em ber called B, t he der ived
class will cont ain bot h m em bers A and B.

I n order t o derive a class from anot her, we use a colon


( :) in t he declarat ion of t he derived class using t he
following form at :

class derived_class_name: public base_class_name


{ /*...*/ };

Where derived_class_name is t he nam e of t he derived


class and base_class_name is t he nam e of t he class on
which it is based. The public access specifier m ay be
replaced by any one of t he ot her access specifiers
protected and private. This access specifier describes
t he m inim um access level for t he m em bers t hat are
inherit ed from t he base class.

// derived classes
#include <iostream>
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b;}
};

class CRectangle: public


CPolygon {
public:
- 121 -

int area ()
{ return (width *
height); }
};

class CTriangle: public CPolygon


{
public:
int area ()
{ return (width * height /
2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
rect.set_values (4,5);
trgl.set_values (4,5);
cout << rect.area() << endl;
cout << trgl.area() << endl;
return 0;
}
20
10

The obj ect s of t he classes CRectangle and CTriangle


each cont ain m em bers inherit ed from CPolygon. These
are: width, height and set_values().

The protected access specifier is sim ilar t o private.


I t s only difference occurs in fact wit h inherit ance. When
a class inherit s from anot her one, t he m em bers of t he
derived class can access t he prot ect ed m em bers
inherit ed from t he base class, but not it s privat e
m em bers.

Since we want ed width and height t o be accessible


from m em bers of t he derived classes CRectangle and
CTriangle and not only by m em bers of CPolygon, we
have used protected access inst ead of private.

We can sum m arize t he different access t ypes accor ding


t o who can access t hem in t he following way:

Acce ss pu blic pr ot e ct e d pr iva t e


m em bers of t he sam e class yes yes yes
m em bers of derived classes yes yes no
not m em bers yes no no

Where " not m em bers" represent any access from


out side t he class, such as from main(), from anot her
class or from a funct ion.

I n our exam ple, t he m em bers inherit ed by CRectangle


and CTriangle have t he sam e access perm issions as
t hey had in t heir base class CPolygon:
- 122 -

CPolygon::width // protected access


CRectangle::width // protected access

CPolygon::set_values() // public access


CRectangle::set_values() // public access

This is because we have used t he public keyword t o


define t he inherit ance relat ionship on each of t he
derived classes:

class CRectangle: public CPolygon { ... }

This public keyword aft er t he colon ( :) denot es t he


m inim um access level for all t he m em bers inherit ed from
t he class t hat follows it ( in t his case CPolygon) . Since
public is t he m ost accessible level, by specifying t his
keyword t he derived class will inherit all t he m em bers
wit h t he sam e levels t hey had in t he base class.

I f we specify a m ore rest rict ive access level like


protected, all public m em bers of t he base class are
inherit ed as prot ect ed in t he derived class. Whereas if
we specify t he m ost rest rict ing of all access levels:
private, all t he base class m em bers are inherit ed
as privat e.

For exam ple, if daughter was a class derived from


mother t hat we defined as:

class daughter: protected mother;

This would set protected as t he m axim um access level


for t he m em bers of daughter t hat it inherit ed from
mother. That is, all m em bers t hat were public in mother
would becom e prot ect ed in daughter. Of course, t his
would not rest rict daughter t o declare it s own public
m em bers. That m axim um access level is only set for t he
m em bers inherit ed from mother.

I f we do not explicit ly specify any access level for t he


inherit ance, t he com piler assum es privat e for classes
declared wit h class keyword and public for t hose
declared wit h struct.

W h a t is in h e r it e d fr om
t h e ba se cla ss?
I n principle, a derived class inherit s every m em ber of a
base class except :

• it s const ruct or and it s dest ruct or


• it s operat or= ( ) m em bers
• it s friends
- 123 -

class are not inherit ed t hem selves, it s default const ruct or


( i.e., it s const ruct or wit h no param et ers) and it s
dest ruct or ar e always called when a new obj ect of a
derived class is creat ed or dest royed.

I f t he base class has no default const ruct or or you want


t hat an overloaded const r uct or is called when a new
derived obj ect is creat ed, you can specify it in each
const ruct or definit ion of t he derived class:

derived_constructor_name (parameters)
: base_constructor_name (parameters) {...}

For exam ple:

// constructors and derived


classes
#include <iostream>
using namespace std;

class mother {
public:
mother ()
{ cout << "mother: no
parameters\n"; }
mother (int a)
{ cout << "mother: int
parameter\n"; }
};

class daughter : public mother {


public:
daughter (int a)
{ cout << "daughter: int
parameter\n\n"; }
};

class son : public mother {


public:
son (int a) : mother (a)
{ cout << "son: int
parameter\n\n"; }
};

int main () {
daughter cynthia (0);
son daniel(0);

return 0;
}
mother: no parameters
daughter: int parameter

mother: int parameter


son: int parameter

Not ice t he difference bet ween which mother's const ruct or


is called when a new daughter obj ect is creat ed and
- 124 -

t he const ruct or declarat ion of daughter and son:

daughter (int a)

// nothing specified: call default


son (int a) : mother (a)

// constructor specified: call this

M u lt iple in h e r it a n ce
I n C+ + it is perfect ly possible t hat a class inherit s
m em bers from m ore t han one class. This is done by sim ply
separat ing t he different base classes wit h com m as in t he
derived class declarat ion. For exam ple, if we had a specific
class t o print on screen ( COutput) and we want ed our
classes CRectangle and CTriangle t o also inherit it s
m em bers in addit ion t o t hose of CPolygon we could writ e:

class CRectangle: public CPolygon, public COutput;


class CTriangle: public CPolygon, public COutput;

here is t he com plet e exam ple:

// multiple inheritance
#include <iostream>
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b;}
};

class COutput {
public:
void output (int i);
};

void COutput::output (int i) {


cout << i << endl;
}

class CRectangle: public


CPolygon, public COutput {
public:
int area ()
{ return (width *
height); }
};

class CTriangle: public


CPolygon, public COutput {
public:
int area ()
- 125 -

{ return (width * height /


2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
rect.set_values (4,5);
trgl.set_values (4,5);
rect.output (rect.area());
trgl.output (trgl.area());
return 0;
}
20
10
- 126 -

Obj ect Orient ed Program m ing:

1 8 . Polym or ph ism

Before get t ing int o t his sect ion, it is recom m ended t hat
you have a proper underst anding of point ers and class
inherit ance. I f any of t he following st at em ent s seem
st range t o you, you should review t he indicat ed
sect ions:

St a t e m e n t : Ex pla in e d in :
int a: : b( c) { } ; Classes
a- > b Point ers
class a: public b; Friendship and inherit ance

Poin t e r s t o ba se cla ss
One of t he key feat ures of derived classes is t hat a
point er t o a derived class is t ype- com pat ible wit h a
point er t o it s base class. Polym orphism is t he art of
t aking advant age of t his sim ple but powerful and
versat ile feat ure, t hat brings Obj ect Orient ed
Met hodologies t o it s full pot ent ial.

We are going t o st art by rewrit ing our program about t he


rect angle and t he t riangle of t he previous sect ion t aking
int o considerat ion t his point er com pat ibilit y propert y:

// pointers to base class


#include <iostream>
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b; }
};

class CRectangle: public


CPolygon {
public:
int area ()
{ return (width *
height); }
};
- 127 -

class CTriangle: public CPolygon


{
public:
int area ()
{ return (width * height /
2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = &rect;
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << rect.area() << endl;
cout << trgl.area() << endl;
return 0;
}
20
10

I n funct ion main, we creat e t wo point ers t hat point t o


obj ect s of class CPolygon ( ppoly1 and ppoly2) . Then
we assign references t o rect and trgl t o t hese
point ers, and because bot h are obj ect s of classes
derived from CPolygon, bot h are valid assignat ions.

The only lim it at ion in using *ppoly1 and *ppoly2 inst ead
of rect and trgl is t hat bot h *ppoly1 and *ppoly2 are
of t ype CPolygon* and t herefore we can only use t hese
point ers t o refer t o t he m em bers t hat CRectangle and
CTriangle inherit from CPolygon. For t hat reason
when we call t he area() m em bers at t he end of t he
program we have had t o use direct ly t he obj ect s rect
and trgl inst ead of t he point ers *ppoly1 and *ppoly2.

I n order t o use area() wit h t he point ers t o class


CPolygon, t his m em ber should also have been declared
in t he class CPolygon, and not only in it s derived classes,
but t he problem is t hat CRectangle and CTriangle
im plem ent different versions of area, t herefore we
cannot im plem ent it in t he base class. This is when
virt ual m em bers becom e handy:

Vir t u a l m e m be r s
A m em ber of a class t hat can be redefined in it s derived
classes is known as a virt ual m em ber. I n order t o declare
a m em ber of a class as virt ual, we m ust precede it s
declarat ion wit h t he keyword virtual:

// virtual members
#include <iostream>
using namespace std;

class CPolygon {
protected:
- 128 -

int width, height;


public:
void set_values (int a, int
b)
{ width=a; height=b; }
virtual int area ()
{ return (0); }
};

class CRectangle: public


CPolygon {
public:
int area ()
{ return (width *
height); }
};

class CTriangle: public CPolygon


{
public:
int area ()
{ return (width * height /
2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon poly;
CPolygon * ppoly1 = &rect;
CPolygon * ppoly2 = &trgl;
CPolygon * ppoly3 = &poly;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly3->set_values (4,5);
cout << ppoly1->area() <<
endl;
cout << ppoly2->area() <<
endl;
cout << ppoly3->area() <<
endl;
return 0;
}
20
10
0

Now t he t hree classes ( CPolygon, CRectangle and


CTriangle) have all t he sam e m em ber s: width, height,
set_values() and area().

The m em ber funct ion area() has been declared as


virt ual in t he base class because it is lat er redefined in
each derived class. You can verify if you want t hat if you
rem ove t his virtual keyword from t he declarat ion of
area() wit hin CPolygon, and t hen you run t he program
t he result will be 0 for t he t hree polygons inst ead of 20,
10 and 0. That is because inst ead of calling t he
corresponding area() funct ion for each obj ect
- 129 -

( CRectangle::area(), CTriangle::area() and


CPolygon::area(), respect ively) , CPolygon::area()
will be called in all cases since t he calls are via a point er
whose t ype is CPolygon*.

Therefore, what t he virtual keyword does is t o allow


a m em ber of a derived class wit h t he sam e nam e as one
in t he base class t o be appropriat ely called from a point er,
and m ore precisely when t he t ype of t he point er is a
point er t o t he base class but is point ing t o an obj ect of
t he derived class, as in t he above exam ple.

A class t hat declares or inherit s a virt ual funct ion is


called a polym orphic class.

Not e t hat despit e of it s virt ualit y, we have also been


able t o declare an obj ect of t ype CPolygon and t o call
it s own area() funct ion, which always ret urns 0.

Abst r a ct ba se cla sse s


Abst ract base classes are som et hing very sim ilar t o our
CPolygon class of our previous exam ple. The only
difference is t hat in our previous exam ple we have
defined a valid area() funct ion wit h a m inim al
funct ionalit y for obj ect s t hat were of class CPolygon
( like t he obj ect poly) , whereas in an abst ract base
classes we could leave t hat area() m em ber funct ion
wit hout im plem ent at ion at all. This is done by
appending =0 ( equal t o zero) t o t he funct ion declarat ion.

An abst ract base CPolygon class could look like t his:

// abstract class CPolygon


class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area () =0;
};

Not ice how we appended =0 t o virtual int area ()


inst ead of specifying an im plem ent at ion for t he funct ion.
This t ype of funct ion is called a pure virt ual funct ion, and
all classes t hat cont ain at least one pure virt ual funct ion
are abst ract base classes.

The m ain difference bet ween an abst ract base class and
a regular polym orphic class is t hat because in abst ract
base classes at least one of it s m em bers lacks
im plem ent at ion we cannot creat e inst ances ( obj ect s)
of it .

But a class t hat cannot inst ant iat e obj ect s is not t ot ally
useless; We can creat e point ers t o it and t ake
advant age of all it s polym orphic abilit ies. Therefore a
- 130 -

declarat ion like:

CPolygon poly;

would not be valid for t he abst ract base class we have


j ust declared, because t ries t o inst ant iat e an obj ect .
Nevert heless, t he following point ers:

CPolygon * ppoly1;
CPolygon * ppoly2;

would be perfect ly valid.

This is so for as long as CPolygon includes a pure virt ual


funct ion and t herefore it 's an abst ract base class.
However, point ers t o t his abst ract base class can be
used t o point t o obj ect s of derived classes.

Here you have t he com plet e exam ple:

// abstract base class


#include <iostream>
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b; }
virtual int area (void) =0;
};

class CRectangle: public


CPolygon {
public:
int area (void)
{ return (width *
height); }
};

class CTriangle: public CPolygon


{
public:
int area (void)
{ return (width * height /
2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = &rect;
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() <<
- 131 -

endl;
cout << ppoly2->area() <<
endl;
return 0;
}
20
10

I f you review t he program you will not ice t hat we refer


t o obj ect s of different but relat ed classes using a unique
t ype of point er ( CPolygon*) . This can be t rem endously
useful. For exam ple, now we can creat e a funct ion
m em ber of t he abst ract base class CPolygon t hat is able
t o print on screen t he result of t he area() funct ion even
t hough CPolygon it self has no im plem ent at ion for t his
funct ion:

// pure virtual members can be


called
// from the abstract base class
#include <iostream>
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() <<
endl; }
};

class CRectangle: public


CPolygon {
public:
int area (void)
{ return (width *
height); }
};

class CTriangle: public CPolygon


{
public:
int area (void)
{ return (width * height /
2); }
};

int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = &rect;
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
- 132 -

ppoly2->printarea();
return 0;
}
20
10

Virt ual m em bers and abst r act classes grant C+ + t he


polym orphic charact erist ics t hat m ake obj ect - orient ed
program m ing such a useful inst rum ent in big proj ect s.
Of course, we have seen very sim ple uses of t hese
feat ures, but t hese feat ures can be applied t o arrays of
obj ect s or dy nam ically allocat ed obj ect s.

Let 's end wit h t he sam e exam ple again, but t his t im e
wit h obj ect s t hat are dynam ically allocat ed:

// dynamic allocation and


polymorphism
#include <iostream>
using namespace std;

class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b; }
virtual int area (void) =0;
void printarea (void)
{ cout << this->area() <<
endl; }
};

class CRectangle: public


CPolygon {
public:
int area (void)
{ return (width *
height); }
};

class CTriangle: public CPolygon


{
public:
int area (void)
{ return (width * height /
2); }
};

int main () {
CPolygon * ppoly1 = new
CRectangle;
CPolygon * ppoly2 = new
CTriangle;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
delete ppoly1;
- 133 -

delete ppoly2;
return 0;
}
20
10

Not ice t hat t he ppoly point ers:

CPolygon * ppoly1 = new CRectangle;


CPolygon * ppoly2 = new CTriangle;

are declared being of t ype point er t o CPolygon but t he


obj ect s dynam ically allocat ed have been declared
having t he derived class t ype direct ly.
- 134 -

Obj ect Orient ed Program m ing:

1 9 . Te m pla t e s

Fu n ct ion t e m pla t e s
Funct ion t em plat es are special funct ions t hat can operat e
wit h generic t ypes. This allows us t o creat e a funct ion
t em plat e whose funct ionalit y can be adapt ed t o m or e
t han one t ype or class wit hout repeat ing t he ent ire code
for each t ype.

I n C+ + t his can be achieved using t em plat e par am et ers.


A t em plat e param et er is a special kind of param et er t hat
can be used t o pass a t ype as argum ent : j ust like regular
funct ion param et ers can be used t o pass values t o a
funct ion, t em plat e param et ers allow t o pass also t ypes
t o a funct ion. These funct ion t em plat es can use t hese
param et ers as if t hey were any ot her regular t ype.

The form at for declaring funct ion t em plat es wit h t ype


param et ers is:

template <class identifier> function_declaration;


template <typename identifier> function_declaration;

The only difference bet ween bot h prot ot ypes is t he use


of eit her t he keyword class or t he keyword typename.
I t s use is indist inct , since bot h expressions have exact ly
t he sam e m eaning and behave exact ly t he sam e way.

For exam ple, t o creat e a t em plat e funct ion t hat ret urns
t he great er one of t wo obj ect s we could use:

template <class myType>


myType GetMax (myType a, myType b) {
return (a>b?a:b);
}

Here we have creat ed a t em plat e funct ion wit h myType


as it s t em plat e param et er. This t em plat e param et er
represent s a t ype t hat has not yet been specified, but
t hat can be used in t he t em plat e funct ion as if it were a
regular t ype. As you can see, t he funct ion t em plat e
GetMax ret urns t he great er of t wo param et ers of t his
st ill- undefined t ype.
- 135 -

To use t his funct ion t em plat e we use t he following form at


for t he funct ion call:

function_name <type> (parameters);

For exam ple, t o call GetMax t o com pare t wo int eger


values of t ype int we can writ e:

int x,y;
GetMax <int> (x,y);

When t he com piler encount ers t his call t o a t em plat e


funct ion, it uses t he t em plat e t o aut om at ically generat e
a funct ion replacing each appear ance of myType by t he
t ype passed as t he act ual t em plat e par am et er ( int in
t his case) and t hen calls it . This process is aut om at ically
perform ed by t he com piler and is invisible t o t he
program m er.

Here is t he ent ire exam ple:

// function template
#include <iostream>
using namespace std;

template <class T>


T GetMax (T a, T b) {
T result;
result = (a>b)? a : b;
return (result);
}

int main () {
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax<int>(i,j);
n=GetMax<long>(l,m);
cout << k << endl;
cout << n << endl;
return 0;
}
6
10

I n t his case, we have used T as t he t em plat e param et er


nam e inst ead of myType because it is short er and in fact
is a very com m on t em plat e param et er nam e. But you
can use any ident ifier you like.

I n t he exam ple above we used t he funct ion t em plat e


GetMax() t wice. The first t im e wit h argum ent s of t ype
int and t he second one wit h argum ent s of t ype long.
The com piler has inst ant iat ed and t hen called each t im e
t he appropriat e version of t he funct ion.

As you can see, t he t ype T is used wit hin t he GetMax()


t em plat e funct ion even t o declare new obj ect s of t hat
t ype:
- 136 -

T result;

Therefore, result will be an obj ect of t he sam e t ype as


t he param et ers a and b when t he funct ion t em plat e is
inst ant iat ed wit h a specific t ype.

I n t his specific case where t he generic t ype T is used as


a param et er for GetMax t he com piler can find out
aut om at ically which dat a t ype has t o inst ant iat e wit hout
having t o explicit ly specify it wit hin angle bracket s ( like
we have done before specifying <int> and <long>) .
So we could have writ t en inst ead:

int i,j;
GetMax (i,j);

Since bot h i and j are of t ype int, and t he com piler can
aut om at ically find out t hat t he t em plat e param et er can
only be int. This im plicit m et hod produces exact ly t he
sam e result :

// function template II
#include <iostream>
using namespace std;

template <class T>


T GetMax (T a, T b) {
return (a>b?a:b);
}

int main () {
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax(i,j);
n=GetMax(l,m);
cout << k << endl;
cout << n << endl;
return 0;
}
6
10

Not ice how in t his case, we called our funct ion t em plat e
GetMax() wit hout explicit ly specifying t he t ype bet ween
angle- bracket s <>. The com piler aut om at ically det er m ines
what t ype is needed on each call.

Because our t em plat e funct ion includes only one t em plat e


param et er ( class T) and t he funct ion t em plat e it self
accept s t wo param et ers, bot h of t his T t ype, we cannot
call our funct ion t em plat e wit h t wo obj ect s of different
t ypes as argum ent s:

int i;
long l;
k = GetMax (i,l);
- 137 -

This would not be correct , since our GetMax funct ion


t em plat e expect s t wo argum ent s of t he sam e t ype, and
in t his call t o it we use obj ect s of t wo different t ypes.

We can also define funct ion t em plat es t hat accept m ore


t han one t ype param et er, sim ply by specifying m ore
t em plat e par am et ers bet ween t he angle bracket s.
For exam ple:

template <class T, class U>


T GetMin (T a, U b) {
return (a<b?a:b);
}

I n t his case, our funct ion t em plat e GetMin() accept s


t wo param et ers of different t ypes and ret urns an obj ect
of t he sam e t ype as t he first param et er ( T) t hat is
passed. For exam ple, aft er t hat declarat ion we could
call GetMin() wit h:

int i,j;
long l;
i = GetMin<int,long> (j,l);

or sim ply:

i = GetMin (j,l);

even t hough j and l have different t ypes, since t he


com piler can det erm ine t he apropriat e inst ant iat ion
anyway.

Cla ss t e m pla t e s
We also have t he possibilit y t o writ e class t em plat es, so
t hat a class can have m em bers t hat use t em plat e
param et ers as t ypes. For exam ple:

template <class T>


class mypair {
T values [2];
public:
mypair (T first, T second)
{
values[0]=first; values[1]=second;
}
};

The class t hat we have j ust defined serves t o st ore t wo


elem ent s of any valid t ype. For exam ple, if we want ed t o
declare an obj ect of t his class t o st ore t wo int eger values
of t ype int wit h t he values 115 and 36 we would writ e:

mypair<int> myobject (115, 36);


- 138 -

t his sam e class would also be used t o creat e an obj ect


t o st ore any ot her t ype:

mypair<double> myfloats (3.0, 2.18);

The only m em ber funct ion in t he previous class t em plat e


has been defined inline wit hin t he class declarat ion it self.
I n case t hat we define a funct ion m em ber out side t he
declarat ion of t he class t em plat e, we m ust always
precede t hat definit ion wit h t he template <...> prefix:

// class templates
#include <iostream>
using namespace std;

template <class T>


class mypair {
T a, b;
public:
mypair (T first, T second)
{a=first; b=second;}
T getmax ();
};

template <class T>


T mypair<T>::getmax ()
{
T retval;
retval = a>b? a : b;
return retval;
}

int main () {
mypair <int> myobject (100,
75);
cout << myobject.getmax();
return 0;
}
100

Not ice t he synt ax of t he definit ion of m em ber funct ion


get m ax:

template <class T>


T mypair<T>::getmax ()

Confused by so m any T's? There are t hree T's in t his


declarat ion: The first one is t he t em plat e param et er . The
second T refers t o t he t ype ret urned by t he funct ion. And
t he t hird T ( t he one bet ween angle bracket s) is also a
requirem ent : I t specifies t hat t his funct ion's t em plat e
param et er is also t he class t em plat e par am et er.

Te m pla t e spe cia liza t ion


I f we want t o define a different im plem ent at ion for a
- 139 -

t em plat e when a specific t ype is passed as t em plat e


param et er, we can declare a specializat ion of t hat
t em plat e.

For exam ple, let 's suppose t hat we have a very sim ple
class called mycontainer t hat can st ore one elem ent of
any t ype and t hat it has j ust one m em ber funct ion called
increase, which increases it s value. But we find t hat
when it st ores an elem ent of t ype char it would be m ore
convenient t o have a com plet ely different im plem ent at ion
wit h a funct ion m em ber uppercase, so we decide t o
declare a class t em plat e specializat ion for t hat t ype:

// template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
T element;
public:
mycontainer (T arg)
{element=arg;}
T increase () {return
++element;}
};

// class template
specialization:
template <>
class mycontainer <char> {
char element;
public:
mycontainer (char arg)
{element=arg;}
char uppercase ()
{
if
((element>='a')&&(element<='z'))
element+='A'-'a';
return element;
}
};

int main () {
mycontainer<int> myint (7);
mycontainer<char> mychar
('j');
cout << myint.increase() <<
endl;
cout << mychar.uppercase() <<
endl;
return 0;
}
8
J

This is t he synt ax used in t he class t em plat e


specializat ion:
- 140 -

template <> class mycontainer <char> { ... };

First of all, not ice t hat we precede t he class t em plat e


nam e wit h an em pt y template<> param et er list . This is
t o explicit ly declare it as a t em plat e specializat ion.

But m ore im port ant t han t his prefix, is t he <char>


specializat ion param et er aft er t he class t em plat e nam e.
This specializat ion param et er it self ident ifies t he t ype for
which we are going t o declare a t em plat e class
specializat ion ( char) . Not ice t he differences bet ween t he
generic class t em plat e and t he specializat ion:

template <class T> class mycontainer { ... };


template <> class mycontainer <char> { ... };

The first line is t he generic t em plat e, and t he second one


is t he specializat ion.

When we declare specializat ions for a t em plat e class, we


m ust also define all it s m em bers, even t hose exact ly
equal t o t he generic t em plat e class, because t here is no
" inherit ance" of m em bers from t he generic t em plat e t o
t he specializat ion.

N on - t ype pa r a m e t e r s for t e m pla t e s


Besides t he t em plat e argum ent s t hat are preceded by
t he class or typename keywords , which represent
t ypes, t em plat es can also have regular t yped param et ers,
sim ilar t o t hose found in funct ions. As an exam ple, have
a look at t his class t em plat e t hat is used t o cont ain
sequences of elem ent s:

// sequence template
#include <iostream>
using namespace std;

template <class T, int N>


class mysequence {
T memblock [N];
public:
void setmember (int x, T
value);
T getmember (int x);
};

template <class T, int N>


void mysequence<T,N>::setmember
(int x, T value) {
memblock[x]=value;
}

template <class T, int N>


T mysequence<T,N>::getmember
(int x) {
return memblock[x];
}
- 141 -

int main () {
mysequence <int,5> myints;
mysequence <double,5>
myfloats;
myints.setmember (0,100);
myfloats.setmember (3,3.1416);
cout << myints.getmember(0) <<
'\n';
cout << myfloats.getmember(3)
<< '\n';
return 0;
}
100
3.1416

I t is also possible t o set default values or t ypes for class


t em plat e par am et ers. For exam ple, if t he previous class
t em plat e definit ion had been:

template <class T=char, int N=10> class mysequence {..};

We could creat e obj ect s using t he default t em plat e


param et ers by declaring:

mysequence<> myseq;

Which would be equivalent t o:

mysequence<char,10> myseq;

Te m pla t e s a n d
m u lt iple - file pr oj e ct s
From t he point of view of t he com piler, t em plat es are
not norm al funct ions or classes. They are com piled on
dem and, m eaning t hat t he code of a t em plat e funct ion
is not com piled unt il an inst ant iat ion wit h specific
t em plat e argum ent s is required. At t hat m om ent , when
an inst ant iat ion is required, t he com piler generat es a
funct ion specifically for t hose argum ent s from
t he t em plat e.

When proj ect s grow it is usual t o split t he code of a


program in different source code files. I n t hese cases,
t he int erface and im plem ent at ion are generally
separat ed. Taking a library of funct ions as exam ple, t he
int erface generally consist s of declarat ions of t he
prot ot ypes of all t he funct ions t hat can be called. These
are generally declared in a " header file" wit h a .h
ext ension, and t he im plem ent at ion ( t he definit ion of
t hese funct ions) is in an independent file wit h c+ + code.

Because t em plat es are com piled when required, t his


forces a rest r ict ion for m ult i- file proj ect s: t he
im plem ent at ion ( definit ion) of a t em plat e class or
funct ion m ust be in t he sam e file as it s declarat ion.
- 142 -

That m eans t hat we cannot separat e t he int erface


in a separat e header file, and t hat we m ust include
bot h int erface and im plem ent at ion in any file t hat
uses t he t em plat es.

Since no code is generat ed unt il a t em plat e is


inst ant iat ed when required, com pilers are prepared t o
allow t he inclusion m ore t han once of t he sam e
t em plat e file wit h bot h declarat ions and definit ions in
a proj ect wit hout generat ing linkage errors.
- 143 -

Advanced Concept s:

2 0 . N a m e spa ce s

Nam espaces allow t o group ent it ies like classes, obj ect s
and funct ions under a nam e. This way t he global scope
can be divided in " sub- scopes" , each one wit h it s own
nam e.

The form at of nam espaces is:

namespace identifier
{
entities
}

Where identifier is any valid ident ifier and entities


is t he set of classes, obj ect s and funct ions t hat are
included wit hin t he nam espace. For exam ple:

namespace myNamespace
{
int a, b;
}

I n t his case, t he variables a and b are norm al variables


declared wit hin a nam espace called myNamespace. I n
order t o access t hese variables from out side t he
myNamespace nam espace we have t o use t he scope
operat or ::. For exam ple, t o access t he previous
variables from out side myNamespace we can writ e:

myNamespace::a
myNamespace::b

The funct ionalit y of nam espaces is especially useful in


t he case t hat t here is a possibilit y t hat a global obj ect
or funct ion uses t he sam e ident ifier as anot her one,
causing redefinit ion errors. For exam ple:

// namespaces
#include <iostream>
using namespace std;

namespace first
{
int var = 5;
}
- 144 -

namespace second
{
double var = 3.1416;
}

int main () {
cout << first::var << endl;
cout << second::var << endl;
return 0;
}
5
3.1416

I n t his case, t here are t wo global variables wit h t he sam e


nam e: var. One is defined wit hin t he nam espace first
and t he ot her one in second. No redefinit ion errors
happen t hanks t o nam espaces.

using
The keyword using is used t o int roduce a nam e from a
nam espace int o t he current declarat ive region.
For exam ple:

// using
#include <iostream>
using namespace std;

namespace first
{
int x = 5;
int y = 10;
}

namespace second
{
double x = 3.1416;
double y = 2.7183;
}

int main () {
using first::x;
using second::y;
cout << x << endl;
cout << y << endl;
cout << first::y << endl;
cout << second::x << endl;
return 0;
}
5
2.7183
10
3.1416

Not ice how in t his code, x ( wit hout any nam e qualifier)
refers t o first::x whereas y refers t o second::y,
exact ly as our using declarat ions have specified. We
- 145 -

st ill have access t o first::y and second::x using


t heir fully qualified nam es.

The keyword using can also be used as a direct ive t o


int roduce an ent ire nam espace:

// using
#include <iostream>
using namespace std;

namespace first
{
int x = 5;
int y = 10;
}

namespace second
{
double x = 3.1416;
double y = 2.7183;
}

int main () {
using namespace first;
cout << x << endl;
cout << y << endl;
cout << second::x << endl;
cout << second::y << endl;
return 0;
}
5
10
3.1416
2.7183

I n t his case, since we have declared t hat we were


using namespace first, all direct uses of x and y
wit hout nam e qualifiers were referring t o t heir
declarat ions in namespace first.

using and using namespace have validit y only in t he


sam e block in which t hey are st at ed or in t he ent ire code
if t hey are used direct ly in t he global scope. For exam ple,
if we had t he int ent ion t o first use t he obj ect s of one
nam espace and t hen t hose of anot her one, we could do
som et hing like:

// using namespace example


#include <iostream>
using namespace std;

namespace first
{
int x = 5;
}

namespace second
{
double x = 3.1416;
- 146 -

int main () {
{
using namespace first;
cout << x << endl;
}
{
using namespace second;
cout << x << endl;
}
return 0;
}
5
3.1416

N a m e spa ce a lia s
We can declare alt ernat e nam es for exist ing nam espaces
according t o t he following form at :

namespace new_name = current_name;

N a m e spa ce st d
All t he files in t he C+ + st andard library declare all of it s
ent it ies wit hin t he std nam espace. That is why we have
generally included t he using namespace std;
st at em ent in all program s t hat used any ent it y defined
in iostream.
- 147 -

Advanced Concept s:

2 1 . Ex ce pt ion s

Except ions provide a way t o react t o except ional


circum st ances ( like runt im e errors) in our program by
t ransferring cont rol t o special funct ions called handlers.

To cat ch except ions we m ust place a port ion of code


under except ion inspect ion. This is done by enclosing
t hat port ion of code in a t ry block. When an except ional
circum st ance arises wit hin t hat block, an except ion is
t hrown t hat t ransfers t he cont rol t o t he except ion
handler. I f no except ion is t hrown, t he code cont inues
norm ally and all handlers are ignored.

A except ion is t hrown by using t he t hrow keyword from


inside t he t ry block. Except ion handlers are declared
wit h t he keyword catch, which m ust be placed
im m ediat ely aft er t he t ry block:

// exceptions
#include <iostream>
using namespace std;

int main () {
try
{
throw 20;
}
catch (int e)
{
cout << "An exception
occurred. Exception Nr. " << e <<
endl;
}
return 0;
}
An exception occurred. Exception
Nr. 20

The code under except ion handling is enclosed in a try


block. I n t his exam ple t his code sim ply t hrows an
except ion:

throw 20;

A t hrow expression accept s one param et er ( in t his case


t he int eger value 20) , which is passed as an argum ent
- 148 -

t o t he except ion handler.

The except ion handler is declared wit h t he catch


keyword. As you can see, it follows im m ediat ely t he
closing brace of t he try block. The cat ch form at is sim ilar
t o a regular funct ion t hat always has at least one
param et er. The t ype of t his param et er is very im port ant ,
since t he t ype of t he argum ent passed by t he t hrow
expression is checked against it , and only in t he case
t hey m at ch, t he except ion is caught .

We can chain m ult iple handlers ( cat ch expressions) , each


one wit h a different param et er t ype. Only t he handler
t hat m at ches it s t ype wit h t he argum ent specified in t he
t hrow st at em ent is execut ed.

I f we use an ellipsis ( ...) as t he param et er of catch,


t hat handler will cat ch any except ion no m at t er what t he
t ype of t he throw except ion is. This can be used as a
default handler t hat cat ches all except ions not caught by
ot her handlers if it is specified at last :

try {
// code here
}
catch (int param) { cout << "int exception"; }
catch (char param) { cout << "char exception"; }
catch (...) { cout << "default exception"; }

I n t his case t he last handler would cat ch any except ion


t hrown wit h any param et er t hat is neit her an int
nor a char.

Aft er an except ion has been handled t he program


execut ion resum es aft er t he try-catch block, not aft er
t he throw st at em ent ! .

I t is also possible t o nest try-catch blocks wit hin m ore


ext ernal try blocks. I n t hese cases, w e have t he
possibilit y t hat an int ernal catch block forwards t he
except ion t o it s ext ernal level. This is done wit h t he
expression throw; wit h no argum ent s. For exam ple:

try {
try {
// code here
}
catch (int n) {
throw;
}
}
catch (...) {
cout << "Exception occurred";
}

Ex ce pt ion spe cifica t ion s


- 149 -

When declaring a funct ion we can lim it t he except ion


t ype it m ight direct ly or indirect ly t hrow by appending a
throw suffix t o t he funct ion declarat ion:

float myfunction (char param) throw (int);

This declares a funct ion called myfunction which t akes


one agum ent of t ype char and ret urns an elem ent of
t ype float. The only except ion t hat t his funct ion m ight
t hrow is an except ion of t ype int. I f it t hrows an
except ion wit h a different t ype, eit her direct ly or indirect ly,
it cannot be caught by a regular int- t ype handler.

I f t his throw specifier is left em pt y wit h no t ype, t his


m eans t he funct ion is not allowed t o t hrow except ions.
Funct ions wit h no throw specifier ( regular funct ions) are
allowed t o t hrow except ions wit h any t ype:

int myfunction (int param) throw();

// no exceptions allowed
int myfunction (int param);

// all exceptions allowed

St a n da r d e x ce pt ion s
The C+ + St andard library provides a base class
specifically designed t o declare obj ect s t o be t hrown as
except ions. I t is called exception and is defined in t he
<exception> header file under t he namespace std.
This class has t he usual default and copy const ruct ors,
operat ors and dest ruct or s, plus an addit ional virt ual
m em ber funct ion called what t hat ret urns a
null- t erm inat ed charact er sequence ( char *) and t hat
can be overwrit t en in derived classes t o cont ain som e
sort of descript ion of t he except ion.

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public


exception
{
virtual const char* what() const
throw()
{
return "My exception
happened";
}
} myex;

int main () {
try
{
throw myex;
- 150 -

}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
My exception happened.

We have placed a handler t hat cat ches except ion obj ect s
by reference ( not ice t he am persand & aft er t he t ype) ,
t herefore t his cat ches also classes derived from
exception, like our myex obj ect of class myexception.

All except ions t hrown by com ponent s of t he C+ +


St andard library t hrow except ions derived from t his
std::exception class. These are:

e x ce pt ion de scr ipt ion


bad_alloc t hrown by new on allocat ion failure
bad_cast t hrown by dynam ic_cast when fails wit h a referenced t ype
bad_except ion t hrown when an except ion t ype doesn't m at ch any cat ch
bad_t y peid t hrown by t ypeid
ios_base: : failure t hrown by funct ions in t he iost ream library

For exam ple, if we use t he operat or new wit hout


(nothrow) and t he m em ory cannot be allocat ed, an
except ion of t ype bad_alloc is t hrown:

try
{
int * myarray= new int[1000];
}
catch (bad_alloc&)
{
cout << "Error allocating memory." << endl;
}

I t is recom m ended t o include all dynam ic m em ory


allocat ions wit hin a t ry block t hat cat ches t his t ype of
except ion t o perform a clean act ion inst ead of an
abnorm al program t erm inat ion, which is what happens
when t his t ype of except ion is t hrown and not caught .
I f you want t o force a bad_alloc except ion t o see it in
act ion, you can t ry t o allocat e a huge array; On m y
syst em , t rying t o allocat e 1 billion ints t hrew
a bad_alloc except ion.

Because bad_alloc is derived from t he st andard base


class exception, we can handle t hat sam e except ion
by cat ching references t o t he exception class:

// bad_alloc standard exception


#include <iostream>
#include <exception>
using namespace std;
- 151 -

int main () {
try
{
int* myarray= new int[1000];
}
catch (exception& e)
{
cout << "Standard exception: "
<< e.what() << endl;
}
return 0;
}
- 152 -

Advanced Concept s:

2 2 . Type Ca st in g

Convert ing an expression of a given t ype int o anot her


t ype is known as t ype- cast ing. We have already seen
som e ways t o t ype cast :

I m plicit con ve r sion


I m plicit conversions do not require any operat or. They
are aut om at ically perform ed when a value is copied t o
a com pat ible t ype. For exam ple:

short a=2000;
int b;
b=a;

Here, t he value of a has been prom ot ed from short t o


int and we have not had t o specify any t ype- cast ing
operat or. This is known as a st andard conversion.
St andard conversions affect fundam ent al dat a t ypes,
and allow conversions such as t he conversions bet ween
num erical t ypes ( short t o int, int t o float, double
t o int...) , t o or from bool, and som e point er conversions.
Som e of t hese conversions m ay im ply a loss of precision,
which t he com piler can signal wit h a warning. This can be
avoided wit h an explicit conversion.

I m plicit conversions also include const ruct or or oper at or


conversions, which affect classes t hat include specific
const ruct ors or operat or funct ions t o perform conversions.
For exam ple:

class A {};
class B { public: B (A a) {} };

A a;
B b=a;

Here, a im plicit conversion happened bet ween obj ect s


of class A and class B, because B has a const ruct or
t hat t akes an obj ect of class A as param et er. Therefore
im plicit conversions from A t o B are allowed.

Ex plicit con ve r sion


- 153 -

C+ + is a st rong- t yped language. Many conversions,


specially t hose t hat im ply a different int erpret at ion of t he
value, require an explicit conversion. We have already
seen t wo not at ions for explicit t ype conversion:
funct ional and c- like cast ing:

short a=2000;
int b;
b = (int) a; // c-like cast notation
b = int (a); // functional notation

The funct ionalit y of t hese explicit conversion operat ors


is enough for m ost needs wit h fundam ent al dat a t ypes.
However, t hese operat ors can be applied indiscrim inat ely
on classes and point ers t o classes, which can lead t o
code t hat while being synt act ically correct can cause
runt im e errors. For exam ple, t he following code is
synt act ically correct :

// class type-casting
#include <iostream>
using namespace std;

class CDummy {
float i,j;
};

class CAddition {
int x,y;
public:
CAddition (int a, int b)
{ x=a; y=b; }
int result() { return
x+y;}
};

int main () {
CDummy d;
CAddition * padd;
padd = (CAddition*) &d;
cout << padd->result();
return 0;
}

The program declares a point er t o CAddition, but t hen


it assigns t o it a reference t o an obj ect of anot her
incom pat ible t ype using explicit t ype- cast ing:

padd = (CAddition*) &d;

Tradit ional explicit t ype- cast ing allows t o convert any


point er int o any ot her point er t ype, independent ly of t he
t ypes t hey point t o. The subsequent call t o m em ber
result will produce eit her a run- t im e error or an
unexpect ed r esult .

I n order t o cont rol t hese t ypes of conversions bet ween


classes, we have four specific cast ing operat ors:
dynamic_cast, reinterpret_cast, static_cast and
- 154 -

const_cast. Their form at is t o follow t he new t ype


enclosed bet ween angle- bracket s ( <>) and im m ediat ely
aft er, t he expression t o be convert ed bet ween
parent heses.

dynamic_cast <new_type> (expression)


reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

The t radit ional t ype- cast ing equivalent s t o t hese


expressions would be:

(new_type) expression
new_type (expression)

but each one wit h it s own special charact erist ics:

dyn a m ic_ ca st
dynamic_cast can be used only wit h point ers and
references t o obj ect s. I t s purpose is t o ensure t hat t he
result of t he t ype conversion is a valid com plet e obj ect
of t he request ed class.

Therefore, dynamic_cast is always successful when we


cast a class t o one of it s base classes:

class CBase { };
class CDerived: public CBase { };

CBase b; CBase* pb;


CDerived d; CDerived* pd;

pb = dynamic_cast<CBase*>(&d);
// ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);
// wrong: base-to-derived

The second conversion in t his piece of code would


produce a com pilat ion error since base- t o- derived
conversions are not allowed wit h dynamic_cast unless
t he base class is polym orphic.

When a class is polym orphic, dynamic_cast perform s a


special checking during runt im e t o ensure t hat t he
expression yields a valid com plet e obj ect of t he
request ed class:

// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;

class CBase { virtual void dummy()


{} };
class CDerived: public CBase { int
a; };
- 155 -

int main () {
try {
CBase * pba = new CDerived;
CBase * pbb = new CBase;
CDerived * pd;

pd =
dynamic_cast<CDerived*>(pba);
if (pd==0) cout << "Null
pointer on first type-cast" <<
endl;

pd =
dynamic_cast<CDerived*>(pbb);
if (pd==0) cout << "Null
pointer on second type-cast" <<
endl;

} catch (exception& e) {cout <<


"Exception: " << e.what();}
return 0;
}
Null pointer on second type-cast
Com pa t ibilit y n ot e : dynamic_cast requires t he Run- Tim e
Type I nform at ion ( RTTI ) t o keep t rack of dynam ic t ypes.
Som e com pilers support t his feat ure as an opt ion which
is disabled by default . This m ust be enabled for runt im e
t ype checking using dynamic_cast t o work properly.

The code t ries t o perform t wo dynam ic cast s from point er


obj ect s of t ype CBase* ( pba and pbb) t o a point er obj ect
of t ype CDerived*, but only t he first one is successful.
Not ice t heir respect ive init ializat ions:

CBase * pba = new CDerived;


CBase * pbb = new CBase;

Even t hough bot h are point ers of t ype CBase*, pba


point s t o an obj ect of t ype CDerived, while pbb point s
t o an obj ect of t ype CBase. Thus, when t heir respect ive
t ype- cast ings are perform ed using dynamic_cast, pba
is point ing t o a full obj ect of class CDerived, whereas
pbb is point ing t o an obj ect of class CBase, which is an
incom plet e obj ect of class CDerived.

When dynamic_cast cannot cast a point er because it


is not a com plet e obj ect of t he required class - as in t he
second conversion in t he previous exam ple- it ret urns a
null point er t o indicat e t he failure. I f dynamic_cast is
used t o convert t o a reference t ype and t he conver sion
is not possible, an except ion of t ype bad_alloc is
t hrown inst ead.

dynamic_cast can also cast null point ers even


bet ween point ers t o unrelat ed classes, and can also
cast point ers of any t ype t o void point ers ( void*) .
- 156 -

st a t ic_ ca st
static_cast can perform conversions bet ween point ers
t o relat ed classes, not only from t he derived class t o it s
base, but also from a base class t o it s derived. This
ensures t hat at least t he classes are com pat ible if t he
proper obj ect is convert ed, but no safet y check is
perform ed during runt im e t o check if t he obj ect being
convert ed is in fact a full obj ect of t he dest inat ion t ype.
Therefore, it is up t o t he program m er t o ensure t hat t he
conversion is safe. On t he ot her side, t he overhead of
t he t ype- safet y checks of dynamic_cast is avoided.

class CBase {};


class CDerived: public CBase {};
CBase * a = new CBase;
CDerived * b = static_cast<CDerived*>(a);

This would be valid, alt hough b would point t o an


incom plet e obj ect of t he class and could lead t o runt im e
errors if dereferenced.

static_cast can also be used t o perform any ot her


non- point er conversion t hat could also be perform ed
im plicit ly, like for exam ple st andard conversion bet ween
fundam ent al t ypes:

double d=3.14159265;
int i = static_cast<int>(d);

Or any conversion bet ween classes wit h explicit


const ruct ors or operat or funct ions as described in
" im plicit conversions" above.

r e in t e r pr e t _ ca st
reinterpret_cast convert s any point er t ype t o any
ot her point er t ype, even of unrelat ed classes. The
operat ion result is a sim ple binary copy of t he value
from one point er t o t he ot her. All point er conversions
are allowed: neit her t he cont ent point ed nor t he
point er t ype it self is checked.

I t can also cast point ers t o or from int eger t ypes. The
form at in which t his int eger value represent s a point er
is plat form - specific. The only guarant ee is t hat a point er
cast t o an int eger t ype large enough t o fully cont ain it ,
is grant ed t o be able t o be cast back t o a valid point er.

The conversions t hat can be perform ed by


reinterpret_cast but not by static_cast have no
specific uses in C+ + are low- level operat ions, whose
int erpret at ion result s in code w hich is generally
syst em - specific, and t hus non- port able. For exam ple:

class A {};
class B {};
- 157 -

A * a = new A;
B * b = reinterpret_cast<B*>(a);

This is valid C+ + code, alt hough it does not m ake m uch


sense, since now we have a point er t hat point s t o an
obj ect of an incom pat ible class, and t hus dereferencing
it is unsafe.

con st _ ca st
This t ype of cast ing m anipulat es t he const ness of an
obj ect , eit her t o be set or t o be rem oved. For exam ple,
in order t o pass a const argum ent t o a funct ion t hat
expect s a non- const ant param et er:

// const_cast
#include <iostream>
using namespace std;

void print (char * str)


{
cout << str << endl;
}

int main () {
const char * c = "sample text";
print ( const_cast<char *>
(c) );
return 0;
}
sample text

t ype id
typeid allows t o check t he t ype of an expression:

typeid (expression)

This operat or ret urns a reference t o a const ant obj ect


of t ype type_info t hat is defined in t he st andard
header file <typeinfo>. This ret urned value can be
com pared wit h anot her one using operat ors ==
and != or can serve t o obt ain a null- t erm inat ed charact er
sequence represent ing t he dat a t ype or class nam e by
using it s name() m em ber .

// typeid
#include <iostream>
#include <typeinfo>
using namespace std;

int main () {
int * a,b;
a=0; b=0;
if (typeid(a) != typeid(b))
{
cout << "a and b are of
- 158 -

different types:\n";
cout << "a is: " <<
typeid(a).name() << '\n';
cout << "b is: " <<
typeid(b).name() << '\n';
}
return 0;
}
a and b are of different types:
a is: int *
b is: int

When typeid is applied t o classes typeid uses t he


RTTI t o keep t rack of t he t ype of dynam ic obj ect s. When
t ypeid is applied t o an expression whose t ype is a
polym orphic class, t he result is t he t ype of t he m ost
derived com plet e obj ect :

// typeid, polymorphic class


#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;

class CBase { virtual void


f(){} };
class CDerived : public CBase {};

int main () {
try {
CBase* a = new CBase;
CBase* b = new CDerived;
cout << "a is: " <<
typeid(a).name() << '\n';
cout << "b is: " <<
typeid(b).name() << '\n';
cout << "*a is: " <<
typeid(*a).name() << '\n';
cout << "*b is: " <<
typeid(*b).name() << '\n';
} catch (exception& e) { cout <<
"Exception: " << e.what() <<
endl; }
return 0;
}
a is: class CBase *
b is: class CBase *
*a is: class CBase
*b is: class CDerived

Not ice how t he t ype t hat typeid considers for point ers
is t he point er t ype it self ( bot h a and b are of t ype class
CBase *) . However, when typeid is applied t o obj ect s
( like *a and *b) typeid yields t heir dynam ic t ype ( i.e.
t he t ype of t heir m ost derived com plet e obj ect ) .

I f t he t ype typeid evaluat es is a point er preceded by


t he derefer ence operat or ( *) , and t his point er has a null
value, typeid t hrows a bad_typeid except ion.
- 159 -

Advanced Concept s:

2 3 . Pr e pr oce ssor D ir e ct ive s


Preprocessor direct ives are lines included in t he code of
our program s t hat are not program st at em ent s but
direct ives for t he preprocessor. These lines are always
preceded by a pound sign ( #) . The preprocessor is
execut ed before t he act ual com pilat ion of code begins,
t herefore t he preprocessor digest s all t hese direct ives
before any code is generat ed by t he st at em ent s.

These pr eprocessor direct ives ext end only across a


single line of code. As soon as a newline charact er is
found, t he preprocessor direct ive is considered t o end.
No sem icolon ( ; ) is expect ed at t he end of a preprocessor
direct ive. The only way a preprocessor direct ive can
ext end t hrough m ore t han one line is by preceding t he
newline charact er at t he end of t he line by a backslash ( \) .

m a cr o de fin it ion s ( # de fin e , # u n de f)


To define preprocessor m acros we can use #define.
I t s form at is:

#define identifier replacement

When t he preprocessor encount ers t his direct ive, it


replaces any occurrence of identifier in t he rest of
t he code by replacement. This replacement can be
an expression, a st at em ent , a block or sim ply anyt hing.
The preprocessor does not underst and C+ + , it sim ply
replaces any occurrence of identifier by
replacement.

#define TABLE_SIZE 100


int table1[TABLE_SIZE];
int table2[TABLE_SIZE];

Aft er t he preprocessor has replaced TABLE_SIZE, t he


code becom es equivalent t o:

int table1[100];
int table2[100];

This use of # define as const ant definer is already known


by us from previuos t ut orials, but #define can work also
wit h param et ers t o define funct ion m acros:
- 160 -

#define getmax(a,b) a>b?a:b

This would replace any occurrence of getmax followed


by t wo argum ent s by t he replacem ent expression, but
also replacing each argum ent by it s ident ifier, exact ly as
you would expect if it was a funct ion:

// function macro
#include <iostream>
using namespace std;

#define getmax(a,b)
((a)>(b)?(a):(b))

int main()
{
int x=5, y;
y= getmax(x,2);
cout << y << endl;
cout << getmax(7,x) << endl;
return 0;
}
5
7

Defined m acros are not affect ed by block st ruct ure. A


m acro last s unt il it is undefined wit h t he # undef
preprocessor direct ive:

#define TABLE_SIZE 100


int table1[TABLE_SIZE];
#undef TABLE_SIZE
#define TABLE_SIZE 200
int table2[TABLE_SIZE];

This would generat e t he sam e code as:

int table1[100];
int table2[200];

Funct ion m acro definit ions accept t wo special operat ors


( # and ##) in t he replacem ent sequence: I f t he operat or
# is used before a param et er is used in t he replacem ent
sequence, t hat param et er is replaced by a st ring lit eral
( as if it were enclosed bet ween double quot es)

#define str(x) #x
cout << str(test);

This would be t ranslat ed int o:

cout << "test";

The operat or ## concat enat es t wo argum ent s leaving


no blank spaces bet ween t hem :
- 161 -

#define glue(a,b) a ## b
glue(c,out) << "test";

This would also be t ranslat ed int o:

cout << "test";

Because preprocessor replacem ent s happen before any


C+ + synt ax check, m acro definit ions can be a t ricky
feat ure, but be careful: code t hat relies heavily on
com plicat ed m acros m ay result obscure t o ot her
program m ers, since t he synt ax t hey expect is on m any
occasions different from t he regular expressions
program m ers expect in C+ + .

Con dit ion a l in clu sion s ( # ifde f,


# ifn de f, # if, # e n dif, # e lse a n d # e lif)
These direct ives allow t o include or discard part of t he
code of a program if a cert ain condit ion is m et .

#ifdef allows a sect ion of a program t o be com piled


only if t he m acro t hat is specified as t he param et er has
been defined, no m at t er which it s value is. For exam ple:

#ifdef TABLE_SIZE
int table[TABLE_SIZE];
#endif

I n t his case, t he line of code int table[TABLE_SIZE];


is only com piled if TABLE_SIZE was previously defined
wit h #define, independent ly of it s value. I f it was not
defined, t hat line will not be included in t he program
com pilat ion.

#ifndef serves for t he exact opposit e: t he code bet ween


#ifndef and #endif direct ives is only com piled if t he
specified ident ifier has not been previously defined.
For exam ple:

#ifndef TABLE_SIZE
#define TABLE_SIZE 100
#endif
int table[TABLE_SIZE];

I n t his case, if when arriving at t his piece of code, t he


TABLE_SIZE m acro has not been defined yet , it would
be defined t o a value of 100. I f it already exist ed it would
keep it s previous value since t he #define direct ive
would not be execut ed.

The #if, #else and #elif ( i.e., " else if" ) direct ives
serve t o specify som e condit ion t o be m et in order for t he
- 162 -

port ion of code t hey surround t o be com piled. The


condit ion t hat follows #if or #elif can only evaluat e
const ant expressions, including m acro expressions.
For exam ple:

#if TABLE_SIZE>200
#undef TABLE_SIZE
#define TABLE_SIZE 200

#elif TABLE_SIZE<50
#undef TABLE_SIZE
#define TABLE_SIZE 50

#else
#undef TABLE_SIZE
#define TABLE_SIZE 100
#endif

int table[TABLE_SIZE];

Not ice how t he whole st ruct ure of #if, #elif and #else
chained direct ives ends wit h #endif.

The behavior of #ifdef and #ifndef can also be


achieved by using t he special operat ors defined and
!defined respect ively in any #if or #elif direct ive:

#if !defined TABLE_SIZE


#define TABLE_SIZE 100
#elif defined ARRAY_SIZE
#define TABLE_SIZE ARRAY_SIZE
int table[TABLE_SIZE];

Lin e con t r ol ( # lin e )


When we com pile a program and som e error happen
during t he com piling process, t he com piler shows an
error m essage wit h references t o t he nam e of t he file
where t he er ror happened and a line num ber, so it is
easier t o find t he code generat ing t he error.

The #line direct ive allows us t o cont rol bot h t hings,


t he line num bers wit hin t he code files as well as t he file
nam e t hat we want t hat appear s when an error t akes
place. I t s form at is:

#line number "filename"


- 163 -

Where number is t he new line num ber t hat will be


assigned t o t he next code line. The line num bers of
successive lines will be increased one by one from t his
point on.

"filename" is an opt ional param et er t hat allows t o


redefine t he file nam e t hat will be shown. For exam ple:

#line 20 "assigning variable"


int a?;

This code will generat e an error t hat will be shown as


error in file "assigning variable", line 20.

Er r or dir e ct ive ( # e r r or )
This direct ive abort s t he com pilat ion process when it is
found, generat ing a com pilat ion t he error t hat can be
specified as it s param et er:

#ifndef __cplusplus
#error A C++ compiler is required!
#endif

This exam ple abort s t he com pilat ion process if t he m acro


nam e __cplusplus is not defined ( t his m acro nam e is
defined by default in all C+ + com pilers) .

Sou r ce file in clu sion ( # in clu de )


This direct ive has also been used assiduously in ot her
sect ions of t his t ut orial. When t he preprocessor finds an
#include direct ive it replaces it by t he ent ire cont ent of
t he specified file. There are t wo ways t o specify a file t o
be included:

#include "file"
#include <file>

The only difference bet ween bot h expr essions is t he


places ( direct ories) where t he com piler is going t o look
for t he file. I n t he first case where t he file nam e is
specified bet w een double- quot es, t he file is searched
first in t he sam e direct ory t hat includes t he file cont aining
t he direct ive. I n case t hat it is not t here, t he com piler
searches t he file in t he default direct ories where it is
configured t o look for t he st andard header files.
I f t he file nam e is enclosed bet ween angle- bracket s <>
t he file is searched direct ly where t he com piler is
configured t o look for t he st andard header files. Therefore,
st andard header files are usually included in angle- bracket s,
while ot her specific header files are included using quot es.

Pr a gm a dir e ct ive ( # pr a gm a )
This direct ive is used t o specify diverse opt ions t o t he
- 164 -

com piler. These opt ions are specific for t he plat form and
t he com piler you use. Consult t he m anual or t he reference
of your com piler for m ore inform at ion on t he possible
param et ers t hat you can define wit h #pragma.

I f t he com piler does not support a specific argum ent for


#pragma, it is ignored - no error is generat ed.

Pr e de fine d m a cr o n a m e s
The following m acro nam es are defined at any t im e:
m a cr o va lue
I nt eger value represent ing t he current line in
__LI NE__
t he source code file being com piled.
A st ring lit eral cont aining t he presum ed nam e
__FI LE__
of t he source file being com piled.
A st ring lit eral in t he form " Mm m dd yyyy"
__DATE__ cont aining t he dat e in which t he com pilat ion
process began.
A st ring lit eral in t he form " hh: m m : ss"
__TI ME__ cont aining t he t im e at which t he com pilat ion
process began.
An int eger value. All C+ + com pilers have t his
const ant defined t o som e value. I f t he com piler
__cplusplus is fully com pliant wit h t he C+ + st andard it s
value is equal or great er t han 199711L
depending on t he version of t he st andard t hey com ply.

For exam ple:

// standard macro names


#include <iostream>
using namespace std;

int main()
{
cout << "This is the line number
" << __LINE__;
cout << " of file " << __FILE__
<< ".\n";
cout << "Its compilation began "
<< __DATE__;
cout << " at " << __TIME__ <<
".\n";
cout << "The compiler gives a
__cplusplus value of " <<
__cplusplus;
return 0;
}
This is the line number 7 of file
/home/jay/stdmacronames.cpp.
Its compilation began Nov 1 2005
at 10:12:29.
The compiler gives a __cplusplus
value of 1
- 165 -

C+ + St andard Library:

2 4 . I n pu t / Ou t pu t
w it h File s
C+ + provides t he following classes t o perform out put and
input of charact ers t o/ from files:

• ofst r e a m : St ream class t o writ e on files


• ifst r e a m : St ream class t o read from files
• fst r e a m : St ream class t o bot h read and writ e
from / t o files.

These classes are derived direct ly or indirect ly from t he


classes istream, and ostream. We have already used
obj ect s whose t ypes were t hese classes: cin is an obj ect
of class istream and cout is an obj ect of class ostream.
Therfore, we have already been using classes t hat are
relat ed t o our file st ream s. And in fact , we can use our
file st ream s t he sam e way we are already used t o use
cin and cout, wit h t he only difference t hat we have t o
associat e t hese st ream s wit h physical files.
Let 's see an exam ple:

// basic file operations


#include <iostream>
#include <fstream>
using namespace std;

int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a
file.\n";
myfile.close();
return 0;
}
[file example.txt]
Writing this to a file

This code creat es a file called example.txt and insert s a


sent ence int o it in t he sam e way we are used t o do wit h
cout, but using t he file st ream myfile inst ead.

But let 's go st ep by st ep:

Ope n a file
The first operat ion generally perform ed on an obj ect of
- 166 -

one of t hese classes is t o associat e it t o a real file. This


procedur e is known as t o open a file. An open file is
represent ed wit hin a program by a st ream obj ect ( an
inst ant iat ion of one of t hese classes, in t he previous
exam ple t his was myfile) and any input or out put
operat ion per form ed on t his st ream obj ect will be
applied t o t he physical file associat ed t o it .

I n order t o open a file wit h a st ream obj ect we use it s


m em ber funct ion open():

open (filename, mode);

Where filename is a null- t erm inat ed charact er sequence


of t ype const char * ( t he sam e t ype t hat st ring lit erals
have) represent ing t he nam e of t he file t o be opened, and
mode is an opt ional param et er wit h a com binat ion of t he
following flags:

ios: : in Open for input operat ions.


ios: : out Open for out put operat ions.
ios: : binary Open in binary m ode.
Set t he init ial posit ion at t he end of t he file.
ios: : at e I f t his flag is not set t o any value, t he init ial
posit ion is t he beginning of t he file.
All out put operat ions are perform ed at t he end
of t he file, appending t he cont ent t o t he current
ios: : app
cont ent of t he file. This flag can only be used in
st ream s open for out put - only operat ions.
I f t he file opened for out put operat ions already
ios: : t runc exist ed before, it s previous cont ent is delet ed
and replaced by t he new one.

All t hese flags can be com bined using t he bit wise operat or
OR(|). For exam ple, if we want t o open t he file
example.bin in binary m ode t o add dat a we could do it
by t he following call t o m em ber funct ion open():

ofstream myfile;
myfile.open ("example.bin",

ios::out | ios::app | ios::binary);

Each one of t he open() m em ber funct ions of t he classes


ofstream, ifstream and fstream has a default m ode
t hat is used if t he file is opened wit hout a second
argum ent :

cla ss de fa u lt m ode pa r a m e t e r
ofst ream ios: : out
ifst ream ios: : in
fst ream ios: : in | ios: : out
- 167 -

For ifstream and ofstream classes, ios::in and


ios::out are aut om at ically and respect ivelly assum ed,
even if a m ode t hat does not include t hem is passed as
second argum ent t o t he open() m em ber funct ion.

The default value is only applied if t he funct ion is called


wit hout specifying any value for t he m ode param et er. I f
t he funct ion is called wit h any value in t hat param et er
t he default m ode is overridden, not com bined.

File st ream s opened in binary m ode per form input and


out put operat ions independent ly of any form at
considerat ions. Non- binary files are known as t ext files,
and som e t ranslat ions m ay occur due t o form at t ing of
som e special charact ers ( like newline and carriage
ret urn charact ers) .

Since t he first t ask t hat is perform ed on a file st ream


obj ect is generally t o open a file, t hese t hree classes
include a const ruct or t hat aut om at ically calls t he
open() m em ber funct ion and has t he exact sam e
param et ers as t his m em ber. Therefor, we could also have
declared t he previous myfile obj ect and conduct ed t he
sam e opening operat ion in our previous exam ple by
writ ing:

ofstream myfile ("example.bin",

ios::out | ios::app | ios::binary);

Com bining obj ect const ruct ion and st ream opening in a
single st at em ent . Bot h form s t o open a file are valid and
equivalent .

To check if a file st ream was successful opening a file,


you can do it by calling t o m em ber is_open() wit h no
argum ent s. This m em ber funct ion ret urns a bool value of
t rue in t he case t hat indeed t he st ream obj ect is associat ed
wit h an open file, or false ot herwise:

if (myfile.is_open())

{ /* ok, proceed with output */ }

Closin g a file
When we are finished wit h our input and out put
operat ions on a file we shall close it so t hat it s resources
becom e available again. I n order t o do t hat we have t o
- 168 -

call t he st ream 's m em ber funct ion close(). This


m em ber funct ion t akes no param et ers, and what it does
is t o flush t he associat ed buffers and close t he file:

myfile.close();

Once t his m em ber funct ion is called, t he st ream obj ect


can be used t o open anot her file, and t he file is available
again t o be opened by ot her processes.

I n case t hat an obj ect is dest ruct ed while st ill associat ed


wit h an open file, t he dest ruct or aut om at ically calls t he
m em ber funct ion close().

Te x t file s
Text file st ream s are t hose where we do not include t he
ios::binary flag in t heir opening m ode. These files are
designed t o st ore t ext and t hus all values t hat we input
or out put from / t o t hem can suffer som e form at t ing
t ransform at ions, which do not necessarily correspond t o
t heir lit eral binary value.

Dat a out put operat ions on t ext files are perform ed in t he


sam e way we operat ed wit h cout:

// writing on a text file


#include <iostream>
#include <fstream>
using namespace std;

int main () {
ofstream myfile
("example.txt");
if (myfile.is_open())
{
myfile << "This is a
line.\n";
myfile << "This is another
line.\n";
myfile.close();
}
else cout << "Unable to open
file";
return 0;
}
[file example.txt]
This is a line.
This is another line.
- 169 -

Dat a input from a file can also be perform ed in t he sam e


way t hat we did wit h cin:

// reading a text file


#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main () {
string line;
ifstream myfile
("example.txt");
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}

else cout << "Unable to open


file";

return 0;
}
This is a line.
This is another line.

This last exam ple reads a t ext file and print s out it s
cont ent on t he screen. Not ice how we have used a new
m em ber funct ion, called eof() t hat ret urns t rue in t he
case t hat t he end of t he file has been reached. We have
creat ed a while loop t hat finishes when indeed
myfile.eof() becom es t rue ( i.e., t he end of t he file
has been reached) .

Ch e ck in g st a t e fla gs
I n addit ion t o eof(), which checks if t he end of file has
been reached, ot her m em ber funct ions exist t o check t he
st at e of a st ream ( all of t hem ret urn a bool value) :

ba d( )
Ret urns t rue if a reading or w rit ing operat ion fails.
For exam ple in t he case t hat we t ry t o writ e t o a
file t hat is not open for writ ing or if t he device
where we t ry t o writ e has no space left .
fa il( )
Ret urns t rue in t he sam e cases as bad( ) , but also
- 170 -

in t he case t hat a form at error happens, like when


an alphabet ical charact er is ext ract ed w hen we are
t rying t o read an int eger num ber.
e of( )
Ret urns t rue if a file open for reading has reached
t he end.
good( )
I t is t he m ost generic st at e flag: it ret urns false
in t he sam e cases in which calling any of t he
previous funct ions would ret urn t rue.

I n order t o reset t he st at e flags checked by any of t hese


m em ber funct ions we have j ust seen we can use t he
m em ber funct ion clear(), which t akes no param et ers.

ge t a n d pu t st r e a m point e r s
All i/ o st ream s obj ect s have, at least , one int ernal st ream
point er:

ifstream, like istream, has a point er known as t he


get point er t hat point s t o t he elem ent t o be read in t he
next input operat ion.

ofstream, like ostream, has a point er known as t he


put point er t hat point s t o t he locat ion where t he next
elem ent has t o be writ t en.

Finally, fstream, inherit s bot h, t he get and t he put


point ers, from iostream ( which is it self derived from
bot h istream and ostream) .

These int ernal st ream point ers t hat point t o t he reading


or writ ing locat ions wit hin a st ream can be m anipulat ed
using t he following m em ber funct ions:

t e llg( ) a n d t e llp( )

These t wo m em ber funct ions have no param et ers and


ret urn a value of t he m em ber t ype pos_type, which is
an int eger dat a t ype repr esent ing t he current posit ion of
t he get st ream point er ( in t he case of tellg) or t he put
st ream point er ( in t he case of tellp) .

se e k g( ) a n d se e k p( )

These funct ions allow us t o change t he posit ion of t he get


and put st ream point ers. Bot h funct ions are overloaded
wit h t wo different prot ot y pes. The first prot ot ype is:

seekg ( position );
seekp ( position );

Using t his prot ot ype t he st ream point er is changed t o t he


absolut e posit ion position ( count ing from t he beginning
of t he file) . The t ype for t his param et er is t he sam e as t he
- 171 -

one ret urned by funct ions tellg and tellp: t he m em ber


t ype pos_type, which is an int eger value.

The ot her pr ot ot ype for t hese funct ions is:

seekg ( offset, direction );


seekp ( offset, direction );

Using t his prot ot ype, t he posit ion of t he get or put point er


is set t o an offset value relat ive t o som e specific point
det erm ined by t he param et er direction. offset is of
t he m em ber t ype off_type, which is also an int eger t ype.
And direction is of t ype seekdir, which is an
enum erat ed t ype ( enum) t hat det erm ines t he point from
where offset is count ed from , and t hat can t ake any of t he
following values:

ios: : beg offset count ed from t he beginning of t he st ream


offset count ed from t he current posit ion of t he
ios: : cur
st ream point er
ios: : end offset count ed from t he end of t he st ream

The following exam ple uses t he m em ber funct ions we


have j ust seen t o obt ain t he size of a file:

// obtaining file size


#include <iostream>
#include <fstream>
using namespace std;

int main () {
long begin,end;
ifstream myfile
("example.txt");
begin = myfile.tellg();
myfile.seekg (0, ios::end);
end = myfile.tellg();
myfile.close();
cout << "size is: " << (end-
begin) << " bytes.\n";
return 0;
}
size is: 40 bytes.

Bina r y file s
I n binary files, t o input and out put dat a wit h t he
ext ract ion and insert ion operat ors ( << and >>) and
funct ions like getline is not efficient , since we do not
need t o form at any dat a, and dat a m ay not use t he
separat ion codes used by t ext files t o separat e elem ent s
( like space, newline, et c...) .

File st ream s include t wo m em ber funct ions specifically


designed t o input and out put binary dat a sequent ially:
write and read. The first one ( write) is a m em ber
funct ion of ostream inherit ed by ofstream. And read
- 172 -

is a m em ber funct ion of istream t hat is inherit ed by


ifstream. Obj ect s of class fstream have bot h m em bers.
Their prot ot ypes are:

write ( memory_block, size );


read ( memory_block, size );

Where memory_block is of t ype " point er t o char"


( char*) , and represent s t he address of an array of
byt es where t he read dat a elem ent s are st ored or from
where t he dat a elem ent s t o be writ t en are t aken. The
size param et er is an int eger value t hat specifies t he
num ber of charact ers t o be read or writ t en from / t o t he
m em ory block.

// reading a complete binary file


#include <iostream>
#include <fstream>
using namespace std;

ifstream::pos_type size;
char * memblock;

int main () {
ifstream file ("example.txt",
ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();

cout << "the complete file


content is in memory";

delete[] memblock;
}
else cout << "Unable to open
file";
return 0;
}
the complete file content is in
memory

I n t his exam ple t he ent ire file is read and st ored in a


m em ory block. Let 's exam ine how t his is done:

First , t he file is open wit h t he ios::ate flag, which


m eans t hat t he get point er will be posit ioned at t he end
of t he file. This way, when we call t o m em ber tellg(),
we will direct ly obt ain t he size of t he file. Not ice t he t ype
we have used t o declare variable size:

ifstream::pos_type size;

ifstream::pos type is a specific t ype used for buffer


- 173 -

and file posit ioning and is t he t ype ret urned by


file.tellg(). This t ype is defined as an int eger t ype,
t herefore we can conduct on it t he sam e operat ions we
conduct on any ot her int eger value, and can safely be
convert ed t o anot her int eger t ype large enough t o cont ain
t he size of t he file. For a file wit h a size under 2GB we
could use int:

int size;
size = (int) file.tellg();

Once we have obt ained t he size of t he file, we request


t he allocat ion of a m em ory block large enough t o hold
t he ent ire file:

memblock = new char[size];

Right aft er t hat , we proceed t o set t he get point er at t he


beginning of t he file ( rem em ber t hat we opened t he file
wit h t his point er at t he end) , t hen read t he ent ire file,
and finally close it :

file.seekg (0, ios::beg);


file.read (memblock, size);
file.close();

At t his point we could operat e wit h t he dat a obt ained


from t he file. Our program sim ply announces t hat t he
cont ent of t he file is in m em ory and t hen t erm inat es.

Bu ffe r s a n d Syn ch r on iza t ion


When we operat e wit h file st ream s, t hese are associat ed
t o an int ernal buffer of t ype streambuf. This buffer is a
m em ory block t hat act s as an int erm ediary bet ween t he
st ream and t he physical file. For exam ple, wit h an
ofstream, each t im e t he m em ber funct ion put ( which
writ es a single charact er) is called, t he charact er is not
writ t en direct ly t o t he physical file wit h which t he st ream
is associat ed. I nst ead of t hat , t he charact er is insert ed in
t hat st ream 's int erm ediat e buffer.

When t he buffer is flushed, all t he dat a cont ained in it is


writ t en t o t he physical m edium ( if it is an out put st ream )
or sim ply freed ( if it is an input st ream ) . This process is
called synchronizat ion and t akes place under any of t he
following circum st ances:

• W h e n t h e file is close d: before closing a file all


buffers t hat have not yet been flushed are
synchronized and all pending dat a is writ t en or
read t o t he physical m edium .
• W h e n t h e bu ffe r is fu ll: Buffers have a cert ain
- 174 -

size. When t he buffer is full it is aut om at ically


synchronized.
• Ex plicit ly, w it h m a n ipu la t or s: When cert ain
m anipulat ors are used on st ream s, an explicit
synchronizat ion t akes place. These m anipulat ors
are: flush and endl.
• Ex plicit ly, w it h m e m be r fu n ct ion sy n c( ) :
Calling st ream 's m em ber funct ion sync(), which
t akes no param et ers, causes an im m ediat e
synchronizat ion. This funct ion ret urns an int value
equal t o -1 if t he st ream has no associat ed buffer
or in case of failure. Ot herwise ( if t he st ream buffer
was successfully synchronized) it ret urns 0.
- 175 -

Appendixes:

2 5 . Ascii Code s

I t is a very well- known fact t hat com put ers can m anage int ernally only 0s
( zeros) and 1s ( ones) . This is t rue, and by m eans of sequences of 0s and 1s
t he com put er can express any num erical value as it s binary t ranslat ion,
which is a very sim ple m at hem at ical operat ion ( as explained in t he paper
num erical bases) .

Nevert heless, t here is no such evident way t o represent let t ers and ot her
non- num eric charact ers wit h 0s and 1s. Therefore, in order t o do t hat ,
com put ers use ASCI I t ables, which are t ables or list s t hat cont ain all t he
let t ers in t he rom an alphabet plus som e addit ional charact ers. I n t hese
t ables each charact er is always represent ed by t he sam e order num ber. For
exam ple, t he ASCI I code for t he capit al let t er " A" is always represent ed by
t he order num ber 65, which is easily represent able using 0s and 1s in binary:
65 expressed as a binary num ber is 1000001.

The st andar d ASCI I t able defines 128 charact er codes ( from 0 t o 127) , of
which, t he first 32 are cont rol codes ( non- print able) , and t he rem aining 96
charact er codes are repr esent able charact ers:

* 0 1 2 3 4 5 6 7 8 9 A B C D E F
0 NUL SOH STX ETX EOT ENQ ACK BEL BS TAB LF VT FF CR SO SI
1 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
2 ! " # $ % & ' ( ) * + , - . /
3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4 @ A B C D E F G H I J K L M N O
5 P Q R S T U V W X Y Z [ \ ] ^ _
6 ` a b c d e f g h i j k l m n o
7 p q r s t u v w x y z { | } ~

* This panel is organized t o be easily read in hexadecim al: row num bers
represent t he first digit and t he colum n num bers represent t he second one.
For exam ple, t he " A" charact er is locat ed at t he 4t h row and t he 1st colum n,
for t hat it would be represent ed in hexadecim al as 0x41 ( 65) .

Because m ost syst em s nowadays work wit h 8bit byt es, which can represent
256 different values, in addit ion t o t he 128 st andard ASCI I codes t here are
ot her 128 t hat are known as ext ended ASCI I , which are plat form - and locale-
dependent . So t here is m ore t han one ext ended ASCI I charact er set .

The t wo m ost used ext ended ASCI I charact er set s are t he one known as
OEM, t hat com es from t he default charact er set incorporat ed by default in
t he I BM- PC and t he ot her is t he ANSI ext end ASCI I which is used by m ost
recent oper at ing syst em s.

The first of t hem , t he OEM charact er set , is t he one used by t he hardware of


- 176 -

t he im m ense m aj orit y of PC com pat ible m achines, and was also used under
t he old DOS syst em . I t includes som e foreign signs, som e m arked charact ers
and pieces t o represent panels.

The ANSI charact er set is a st andard t hat m any syst em s incorporat e, like
Windows, som e UNI X plat form s and m any st andalone applicat ions. I t
includes m any m ore local sym bols and m arked let t ers so t hat it can be used
wit h no need of being redefined in m any m ore languages:
- 177 -

Appendixes:

2 6 . Boole a n Ope r a t ion s


A bit is t he m inim um am ount of inform at ion t hat we can im agine, since it only st ores eit her
value 1 or 0, which represent s eit her YES or NO, act ivat ed or deact ivat ed, t rue or false, et c...
t hat is: t wo possible st at es each one opposit e t o t he ot her, wit hout possibilit y of any shades.
We are going t o consider t hat t he t wo possible values of a bit are 0 and 1.

Several operat ions can be perform ed w it h bit s, eit her in conj unct ion wit h ot her bit s or t hem selves
alone. These operat ions receive t he nam e of boolean operations, a word t hat com es from t he
nam e of one of t he m at hem at icians who cont ribut ed t he m ore t o t his field: George Boole ( 1815- 1864) .

All t hese operat ions have an est ablished behavior and all of t hem can be applied t o any bit no m at t er
which value t hey cont ain ( eit her 0 or 1) . Next you have a list of t he basic boolean operat ions and a
t able wit h t he behavior of t hat operat ion wit h every possible com binat ion of bit s.

AN D
This operat ion is perform ed bet ween t wo bit s, which we will call a and b. The
result of applying t his AND operat ion is 1 if bot h a and b are equal t o 1, and 0 in
all ot her cases ( i.e., if one or bot h of t he variables is 0) .

AN D ( & )

a b a&b
000
0
01
0
10
111

OR
This operat ion is perform ed bet ween t wo bit s ( a and b) . The result is 1 if eit her
one of t he t wo bit s is 1, or if bot h are 1. I f none is equal t o 1 t he result is 0.

OR ( | )

a b a| b
000
011
101
111

XOR ( Ex clu sive Or )


- 178 -

This operat ion is perform ed bet ween t wo bit s ( a and b) . The result is 1 if eit her
one of t he t wo bit s is 1, but not in t he case t hat bot h are. There for, if neit her or
bot h of t hem are equal t o 1 t he result is 0.

XOR ( ^ )

a b a^ b
000
011
101
110

N OT
This operat ion is perform ed on a single bit . I t s result is t he inversion of t he act ual
value of t he bit : if it was set t o 1 it becom es 0, and if it was 0 it becom es 1:

N OT ( ~ )

a~a
01
10

These are t he 4 basic boolean operat ions ( AND, OR, XOR and NOT) . Com bining
t hese oper at ions we can obt ain any possible result from t wo bit s.

I n C+ + , t hese operat ors can be used w it h variables of any int eger dat a t ype; t he
boolean oper at ion is perform ed t o all of t he bit s of each variable involved. For
exam ple, supposing t wo variables: a and b, bot h of t ype unsigned char, where
a cont ains 195 ( 11000011 in binary) and b cont ains 87 ( or 01010111 in binary) .
I f we writ e t he following code:

unsigned char a=195;


unsigned char b=87;
unsigned char c;
c=a&b;

That m eans, t hat we conduct ed a bit wise AND operat ion bet ween a and b. The
operat ion is perform ed bet ween t he bit s of t he t wo variables t hat are locat ed at
t he sam e posit ion: The right m ost bit of c will cont ain t he result of conduct ing t he
AND operat ion bet ween t he right m ost bit s of a and b:

The sam e operat ion is also perform ed bet ween t he second bit s of bot h variables,
and t he t hird, and so on, unt il t he operat ion is perform ed bet ween all bit s of bot h
variables ( each one only wit h t he sam e bit of t he ot her variable) .

The final binary value of c is 01000011, that is 67 in decimal numbers. So 195&87


is equal to 67.
- 179 -

Appendixes:

2 7 . N u m e r ica l Ba se s

We are all used since we were kids t o use decim al num bers t o express quant it ies.
This nom enclat ure t hat seem s so logical t o us m ay not seem so t o an inhabit ant of
Classical Rom e. For t hem , each sym bol t hat t hey wrot e t o express a num ber
always represent ed t he sam e value:

I 1
II 2
III 3
IV 4
V 5

All t he I signs always represent t he value 1 ( one) wherever t hey are placed, and
t he V sign always represent s a value of 5 ( five) . Nevert heless t hat does not t ake
place in our decim al syst em . When we writ e t he decim al sym bol 1 we are not
always t alking about a value of one ( I in Rom an num bers) . For exam ple:

1 I
10 X
100 C

In t hese cases, our sym bol 1 does not have always a value of one ( or I in Rom an
num bers) . For exam ple, in t he second case, t he sym bol 1 represent s a value of
t en ( or X in Rom an) and in t he t hird one, 1 represent s a value of one hundred ( or
C) .

For exam ple:

275 is not equivalent t o 2+ 7+ 5, it could rat her be decom posed as 200+ 70+ 5:

200
+ 70
5
---
275

t herefore, t he first " 2" sign is equivalent t o 200 ( 2 x 100) , t he second " 7" sign is
equivalent t o 70 ( 7 x 10) whereas t he last sign corresponds t o t he value 5 ( 5 x 1) .

This is because our syst em is a posit ional num eral syst em . Therefor t he value of a
given digit depends on it s posit ion wit hin t he ent ire num ber being represent ed. All
t he above can be m at hem at ically represent ed in a very sim ple way. For exam ple,
t o represent t he value 182736 we can assum e t hat each digit is t he product of
it self m ult iplied by 10 pow ered t o it s place as exponent , beginning from t he right
wit h 10 0 , following wit h 10 1 , 10 2 , and so on:
- 180 -

Oct a l n u m be r s ( ba se 8 )
Like our " norm al" num bers are ba se 1 0 ( or radix 10) because we have 10
different digit s ( from t he 0 t o t he 9) :

0123456789

t he oct als num bers include only t he represent at ions for t he values from 0 t o 7:

01234567

and, t herefore, it s m at hem at ical base is 8. I n C+ + oct al num bers are denot ed by
beginning always wit h a 0 digit . Let 's see how we would writ e t he first num bers in
oct al:

octal decimal
----- -------
0 0 (zero)
01 1 (one)
02 2 (two)
03 3 (three)
04 4 (four)
05 5 (five)
06 6 (six)
07 7 (seven)
010 8 (eight)
011 9 (nine)
012 10 (ten)
013 11 (eleven)
014 12 (twelve)
015 13 (thirteen)
016 14 (fourteen)
017 15 (fifteen)
020 16 (sixteen)
021 17 (seventeen)

Thus, for exam ple, t he num ber 17 ( sevent een, or XVI I in Rom an) it is expressed
021 as an oct al num ber in C+ + . We can apply t he sam e m echanism t hat we saw
previously for decim al num bers t o t he oct al num bers sim ply by considering t hat it s
base is 8. For exam ple, t aking t he oct al num ber 071263:
- 181 -

t herefore t he oct al num ber 071263 is expressed as 29363 in decim al num bers.

H e x a de cim a l n u m be r s ( ba se 1 6 )
Like decim al num bers have 10 different digit s t o be represent ed ( 0123456789)
and oct al num bers have 8 ( 01234567) , hexadecim al num bers have 16 different
digit s, t hat are represent ed by t he num bers from 0 t o 9 and t he let t ers A, B, C, D,
E and F, which t oget her serve us t o represent t he 16 different sym bols t hat we
need t o expr ess base 16 num bers:

hexadecimal decimal
----------- -------
0 0 (zero)
0x1 1 (one)
0x2 2 (two)
0x3 3 (three)
0x4 4 (four)
0x5 5 (five)
0x6 6 (six)
0x7 7 (seven)
0x8 8 (eight)
0x9 9 (nine)
0xA 10 (ten)
0xB 11 (eleven)
0xC 12 (twelve)
0xD 13 (thirteen)
0xE 14 (fourteen)
0xF 15 (fifteen)
0x10 16 (sixteen)
0x11 17 (seventeen)

I n C+ + , hexadecim al num bers are pr eceded by 0x ( zero, x) .

Once again we can use t he sam e m et hod t o t ranslat e a num ber from a base t o
anot her one:
- 182 -

Bin a r y r e pr e se n t a t ion s
Oct al and hexadecim al num bers have a considerable advant age over our decim al
num bers in t he world of bit s, and is t hat t heir bases ( 8 and 16) are perfect
m ult iples of 2 ( 2 3 and 2 4 , respect ivelly) , which allows us t o m ake easier
conversions from t hese bases t o binary t han from decim al num bers ( whose base
is 2x5) . For exam ple, suppose t hat we want t o t ranslat e t he following binary
sequence t o num bers of ot her bases:

110011111010010100

I n order t o t ranslat e it t o decim al we would need t o conduct a m at hem at ical


operat ion sim ilar t o t he one we have used previously t o convert from hexadecim al
or oct al, which would give us t he decim al num ber 212628.

Nevert heless t o pass t his sequence t o oct al it will only t ake us som e seconds and
even t he less skilled in m at hem at ics can do it j ust by seeing it : Since 8 is 2 3 , we
will separat e t he binary value in groups of 3 num bers:

110 011 111 010 010 100

and now we j ust have t o t ranslat e t o oct al num beral radix each group separat ely:

110 011 111 010 010 100


6 3 7 2 2 4

giving t he num ber 637224 as result . This sam e process can be inversely
perform ed t o pass from oct al t o binary.
I n order t o conduct t he operat ion wit h hexadecim al num bers we only have t o
perform t he sam e process but separat ing t he binary value in groups of 4 num bers,
because 16 = 2 4 :

11 0011 1110 1001 0100


3 3 E 9 4

Therefore, t he binary expression 110011111010010100 can be r epresent ed in


C+ + eit her as 212628 ( decim al) , as 0637224 ( oct al) or as 0x33e94
( hexadecim al) .

The hexadecim al code is specially int erest ing in com put er science since nowadays,
com put ers ar e based on byt es com posed of 8 binary bit s and t herefore each byt e
m at ches wit h t he range t hat 2 hexadecim al num bers can represent . For t hat
reason it is so frequent ly used t o represent values t ranslat ed t o or from binary
base.

You might also like