C Language Tutorial
C Language Tutorial
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
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
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
#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 .
#include <iostream>
Lines beginning wit h a pound sign ( #) are direct ives
for t he prepr ocessor. They are not regular code
-2-
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.
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.
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.
Let us add an addit ional inst ruct ion t o our first program :
#include <iostream>
int main ()
{
cout << "Hello World! ";
cout << "I'm a C++ program";
return 0;
}
Hello World! I'm a C++ program
int main ()
{
cout <<
"Hello World!";
cout
<< "I'm a C++ program";
return 0;
}
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-
// line comment
/* block comment */
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World! ";
Basics of C+ + :
2 . Va r ia ble s. D a t a Type s.
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;
I de n t ifie r s
-7-
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:
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-
int a;
float mynumber;
int a, b, c;
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:
int MyAccountBalance;
short Year;
short int Year;
- 10 -
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:
#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;
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.
int a = 0;
int a (0);
// 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.
// 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
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;
}
Basics of C+ + :
3 . Con st a n t s
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;
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.
75 // decimal
0113 // octal
0x4b // hexadecimal
- 15 -
75 // int
75u // unsigned int
75l // long
75ul // unsigned long
Floa t in g Poin t N u m be r s
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:
Ch a r a ct e r a n d st r in g lit e r a ls
"Hello world"
"How do you do?"
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'
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 ( \)
'\n'
'\t'
"Left \t Right"
"one\ntwo\nthree"
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"
Boole a n lit e r a ls
#define PI 3.14159265
#define NEWLINE '\n'
#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
Basics of C+ + :
4 . Ope r a t or s
Assign m e n t ( = )
The assignm ent operat or assigns a value t o a variable.
a = 5;
a = b;
// 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
return 0;
}
a:4 b:7
a = 2 + (b = 5);
is equivalent t o:
b = 5;
a = 2 + b;
a = b = c = 5;
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 -
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;
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:
#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;
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
= = Equal t o
! = Not equal t o
> Great er t han
- 23 -
(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.
a b a && b
t rue t rue t rue
t rue false false
false t rue false
false false false
| | OPERATOR
a b a || b
t rue t rue t rue
t rue false t rue
false t rue t rue
false false false
#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
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.
a = (b=3, b+2);
int i;
float f = 3.14;
i = (int) f;
i = int ( f );
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);
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
a = 5 + (7 % 2) // with a result of 6, or
a = (5 + 7) % 2 // with a result of 0
a = 5 + 7 % 2;
a = 5 + (7 % 2);
- 28 -
or
a = (5 + 7) % 2;
Basics of C+ + :
5 . Ba sic I n pu t / Ou t pu t
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 << "Hello, " << "I am " << "a C++ statement";
cout << "Hello, I am " << age << " years old and my zipcode is "
<< zipcode;
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:
First sentence.
Second sentence.
Third sentence.
First sentence.
Second sentence.
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;
// i/o example
#include <iostream>
using namespace std;
int main ()
{
int i;
cout << "Please enter an integer
value: ";
cin >> i;
- 32 -
You can also use cin t o request m ore t han one dat um
input from t he user:
is equivalent t o:
cin >> a;
cin >> b;
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:
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!
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:
// stringstreams
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string mystr;
float price=0;
int quantity=0;
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 -
6 . Con t r ol St r u ct u r e s
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: { }:
if (condition) statement
if (x == 100)
cout << "x is 100";
- 36 -
if (x == 100)
{
cout << "x is ";
cout << x;
}
if (x == 100)
cout << "x is 100";
else
cout << "x is not 100";
if (x > 0)
cout << "x is positive";
else if (x < 0)
cout << "x is negative";
else
cout << "x is 0";
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:
#include <iostream>
using namespace std;
int main ()
{
int n;
cout << "Enter the starting
number > ";
cin >> n;
while (n>0) {
cout << n << ", ";
--n;
}
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.
I t s form at is:
// 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
Th e for loop
I t s form at is:
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
#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
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
#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
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
}
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";
}
7 . Fu n ct ion s ( I )
where:
// function example
#include <iostream>
using namespace std;
int main ()
{
int z;
z = addition (5,3);
- 45 -
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 -
Scope of va r ia ble s
of t he program .
// function example
#include <iostream>
using namespace std;
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
z = subtraction (7,2);
cout << "The first result is " << z;
z = 5;
cout << "The first result is " << z;
As well as
I n t he case of:
z = 4 + subtraction (x,y);
z = subtraction (x,y) + 4;
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:
void printmessage ()
{
cout << "I'm a function!";
}
int main ()
{
printmessage ();
return 0;
}
I'm a function!
printmessage ();
printmessage;
- 50 -
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:
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.
// passing parameters by
reference
#include <iostream>
using namespace std;
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.
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.
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:
int main ()
{
cout << divide (12);
cout << endl;
cout << divide (20,4);
return 0;
}
6
5
- 53 -
divide (12)
I n t he second call:
divide (20,4)
// overloaded function
#include <iostream>
using namespace std;
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
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.
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 -
5! = 5 * 4 * 3 * 2 * 1 = 120
// factorial calculator
#include <iostream>
using namespace std;
int main ()
{
long number;
cout << "Please type a number:
";
cin >> number;
cout << number << "! = " <<
factorial (number);
return 0;
}
Please type a number: 9
9! = 362880
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 -
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:
// declaring functions
prototypes
#include <iostream>
using namespace std;
int main ()
{
int i;
do {
cout << "Type a number (0 to
exit): ";
cin >> i;
odd (i);
} while (i!=0);
return 0;
}
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.
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:
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.
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]
t he following:
billy[2] = 75;
a = billy[2];
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 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[1][3]
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:
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 -
#define HEIGHT 3
t o:
#define HEIGHT 4
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.
procedure (myarray);
// arrays as parameters
#include <iostream>
using namespace std;
int main ()
{
int firstarray[] = {5, 10,
15};
- 64 -
base_type[][depth][depth]
for exam ple, a funct ion wit h a m ult idim ensional array as
argum ent could be:
1 0 . Ch a r a ct e r Se qu e n ce s
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 -
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.
mystext = "Hello";
mystext[] = "Hello";
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 -
string mystring;
char myntcs[]="some text";
mystring = myntcs;
- 69 -
1 1 . Poin t e r s
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 .
ted = &andy;
andy = 25;
fred = andy;
ted = &andy;
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 -
beth = *ted;
andy = 25;
ted = &andy;
andy == 25
&andy == 1776
ted == 1776
*ted == 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
type * name;
int * number;
char * character;
float * greatnumber;
// 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
// 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
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) .
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:
p = numbers;
numbers = p;
// 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,
a[5] = 0; // a [offset of 5] = 0
*(a+5) = 0; // pointed by (a+5) = 0
int number;
int *tommy = &number;
int number;
int *tommy;
tommy = &number;
int number;
int *tommy;
*tommy = &number;
*(terry+4)
terry[4]
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 .
char *mychar;
short *myshort;
long *mylong;
So if we writ e:
mychar++;
myshort++;
mylong++;
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;
*p++
(*p)++
I f we writ e:
*p++ = *q++;
*p = *q;
++p;
++q;
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;
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.
// increaser
#include <iostream>
using namespace std;
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
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;
(*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
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.
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:
int * bobby;
bobby = new int [5];
int * bobby;
bobby = new (nothrow) int [5];
if (bobby == 0) {
// error assigning memory. Take measures.
};
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;
// 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 -
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 .
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) .
1 3 . D a t a St r u ct u r e s
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:
struct product {
int weight;
float price;
} ;
product apple;
product banana, melon;
struct product {
int weight;
float price;
} apple, banana, melon;
apple.weight
apple.price
banana.weight
banana.price
melon.weight
melon.price
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:
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
} mine, yours;
int main ()
{
string mystr;
// 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];
int main ()
{
string mystr;
int n;
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;
pmovie = &amovie;
// 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;
return 0;
}
Enter title: Invasion of the
body snatchers
Enter year: 1978
pmovie->title
(*pmovie).title
*pmovie.title
which is equivalent t o:
*(pmovie.title)
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;
charlie.name
maria.favorite_movie.title
charlie.favorite_movie.year
pfriends->favorite_movie.year
1 4 . Ot h e r D a t a Type s
typedef char C;
typedef unsigned int WORD;
typedef char * pChar;
typedef char field [50];
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 -
union union_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
union mytypes_t {
char c;
int i;
float f;
} mytypes;
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.
union mix_t {
long l;
struct {
short hi;
short lo;
} s;
char c[4];
} mix;
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;
book.price.dollars
book.price.yens
book.dollars
book.yens
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 -
enum enumeration_name {
value1,
value2,
value3,
.
.
} object_names;
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.
1 5 . Cla sse s ( I )
class class_name {
access_specifier_1:
member1;
access_specifier_2:
member2;
...
} object_names;
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area (void);
} rect;
int a;
rect.set_values (3,4);
myarea = rect.area();
// classes example
#include <iostream>
using namespace std;
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area () {return (x*y);}
};
- 102 -
int main () {
CRectangle rect;
rect.set_values (3,4);
cout << "area: " <<
rect.area();
return 0;
}
area: 12
class CRectangle {
int x, y;
public:
void set_values (int,int);
int area () {return (x*y);}
};
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
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.
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
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.
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
// 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 -
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.
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; };
};
CExample ex;
class CExample {
public:
int a,b,c;
CExample (int n, int m) { a=n; b=m; };
void multiply () { c=a*b; };
};
CExample ex (2,3);
- 108 -
But ,
CExample ex;
CExample ex (2,3);
CExample ex2 (ex); // copy constructor (data copied from ex)
CRectangle * prect;
class CRectangle {
int width, height;
public:
void set_values (int, int);
- 109 -
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
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;
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:
// vectors: overloading
operators example
#include <iostream>
using namespace std;
class CVector {
public:
int x,y;
CVector () {};
CVector (int,int);
CVector operator +
(CVector);
};
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
c = a + b;
c = a.operator+ (b);
CVector () { };
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;
CVector d (2,3);
CVector e;
e = d; // copy assignment operator
- 114 -
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.
// this
#include <iostream>
using namespace std;
class CDummy {
public:
int isitme (CDummy& param);
- 115 -
};
int main () {
CDummy a;
CDummy* b = &a;
if ( b->isitme(a) )
cout << "yes, &a is b";
return 0;
}
yes, &a is b
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.
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
int CDummy::n=0;
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.
// 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);
};
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 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 -
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 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 -
// 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;}
};
int area ()
{ return (width *
height); }
};
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
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 :
derived_constructor_name (parameters)
: base_constructor_name (parameters) {...}
class mother {
public:
mother ()
{ cout << "mother: no
parameters\n"; }
mother (int a)
{ cout << "mother: int
parameter\n"; }
};
int main () {
daughter cynthia (0);
son daniel(0);
return 0;
}
mother: no parameters
daughter: int parameter
daughter (int a)
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:
// 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);
};
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 -
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.
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b; }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
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
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.
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 main () {
CRectangle rect;
CTriangle trgl;
CPolygon poly;
CPolygon * ppoly1 = ▭
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
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 -
CPolygon poly;
CPolygon * ppoly1;
CPolygon * ppoly2;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int
b)
{ width=a; height=b; }
virtual int area (void) =0;
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
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
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; }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
- 132 -
ppoly2->printarea();
return 0;
}
20
10
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:
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; }
};
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
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.
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:
int x,y;
GetMax <int> (x,y);
// function template
#include <iostream>
using namespace std;
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
T result;
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;
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.
int i;
long l;
k = GetMax (i,l);
- 137 -
int i,j;
long l;
i = GetMin<int,long> (j,l);
or sim ply:
i = GetMin (j,l);
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:
// class templates
#include <iostream>
using namespace std;
int main () {
mypair <int> myobject (100,
75);
cout << myobject.getmax();
return 0;
}
100
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
// sequence template
#include <iostream>
using namespace std;
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
mysequence<> myseq;
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.
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.
namespace identifier
{
entities
}
namespace myNamespace
{
int a, b;
}
myNamespace::a
myNamespace::b
// 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
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 -
// 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
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 :
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
// 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
throw 20;
try {
// code here
}
catch (int param) { cout << "int exception"; }
catch (char param) { cout << "char exception"; }
catch (...) { cout << "default exception"; }
try {
try {
// code here
}
catch (int n) {
throw;
}
}
catch (...) {
cout << "Exception occurred";
}
// no exceptions allowed
int myfunction (int param);
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;
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.
try
{
int * myarray= new int[1000];
}
catch (bad_alloc&)
{
cout << "Error allocating memory." << endl;
}
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
short a=2000;
int b;
b=a;
class A {};
class B { public: B (A a) {} };
A a;
B b=a;
short a=2000;
int b;
b = (int) a; // c-like cast notation
b = int (a); // functional notation
// 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;
}
(new_type) expression
new_type (expression)
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.
class CBase { };
class CDerived: public CBase { };
pb = dynamic_cast<CBase*>(&d);
// ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);
// wrong: base-to-derived
// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;
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;
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.
double d=3.14159265;
int i = static_cast<int>(d);
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.
class A {};
class B {};
- 157 -
A * a = new A;
B * b = reinterpret_cast<B*>(a);
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;
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)
// 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
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 ) .
Advanced Concept s:
int table1[100];
int table2[100];
// 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
int table1[100];
int table2[200];
#define str(x) #x
cout << str(test);
#define glue(a,b) a ## b
glue(c,out) << "test";
#ifdef TABLE_SIZE
int table[TABLE_SIZE];
#endif
#ifndef TABLE_SIZE
#define TABLE_SIZE 100
#endif
int table[TABLE_SIZE];
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 -
#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.
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
#include "file"
#include <file>
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.
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.
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:
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
Ope n a file
The first operat ion generally perform ed on an obj ect of
- 166 -
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",
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 -
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 .
if (myfile.is_open())
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 -
myfile.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.
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 -
int main () {
string line;
ifstream myfile
("example.txt");
if (myfile.is_open())
{
while (! myfile.eof() )
{
getline (myfile,line);
cout << line << endl;
}
myfile.close();
}
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 -
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:
t e llg( ) a n d t e llp( )
se e k g( ) a n d se e k p( )
seekg ( position );
seekp ( position );
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...) .
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();
delete[] memblock;
}
else cout << "Unable to open
file";
return 0;
}
the complete file content is in
memory
ifstream::pos_type size;
int size;
size = (int) file.tellg();
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.
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:
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
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:
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) .
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) .
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)
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
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:
and now we j ust have t o t ranslat e t o oct al num beral radix each group separat ely:
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 :
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.