Vous êtes sur la page 1sur 140

Programming C/C++

Delia Ungureanu - UNITBV

Contents

Introduction ....................................................................................................................................6
Preliminaries ...................................................................................................................................7
Programs ..............................................................................................................................7
The Development Environment .........................................................................................8
Compiling the Source Code ................................................................................................8
A Simple C++ Program ......................................................................................................9
Compile Errors ..................................................................................................................11
Using Comments................................................................................................................12
The ANSI Standard...........................................................................................................13
Identifiers ...........................................................................................................................13
Memory ..............................................................................................................................14
Simple Input/Output ....................................................................................................................16
Printing output ..................................................................................................................16
Reading input.....................................................................................................................19
Variables........................................................................................................................................21
Variable Names .................................................................................................................21
Data types and sizes...........................................................................................................21
Numeric Variable Types ..........................................................................................21
Integer Numbers.......................................................................................................24
Real Numbers...........................................................................................................25
Characters ................................................................................................................25
Strings ......................................................................................................................26
Symbolic Constants ...........................................................................................................28
Using #define directive ............................................................................................28
Defining Constants with the const Keyword ...........................................................29
Operators and expressions...........................................................................................................32
The Assignment Operator ................................................................................................32
Arithmetic Operators........................................................................................................33
Delia Ungureanu - UNITBV

Contents
Bitwise Operators..............................................................................................................36
Relational Operators.........................................................................................................37
Logical Operators..............................................................................................................39
Conditional Operator........................................................................................................39
Compound Assignment Operator....................................................................................40
Comma Operator ..............................................................................................................41
Parentheses Operator .......................................................................................................42
Operator Precedence.........................................................................................................42
Type Conversion................................................................................................................43
Statements .....................................................................................................................................45
Statements and White Space ............................................................................................46
Null Statements..................................................................................................................46
Compound Statements ......................................................................................................46
The if Statement ................................................................................................................48
The else Clause ........................................................................................................49
The switch Statement ........................................................................................................51
Controlling Program Execution.......................................................................................53
The for Statement.....................................................................................................54
Nesting for Statements.............................................................................................56
The while Statement ................................................................................................57
The do...while Loop .................................................................................................58
The continue Statement............................................................................................60
The break Statement ................................................................................................60
The return Statement................................................................................................61
Pointers ..........................................................................................................................................62
Pointers and Symbolic Constants ....................................................................................65
Pointer Arithmetic.............................................................................................................65
Consequences of use of uninitialized pointers ................................................................67
Arrays ............................................................................................................................................68
Single-Dimensional Arrays...............................................................................................68
Multi-Dimensional Arrays................................................................................................70
Dynamic Memory .........................................................................................................................73
Delia Ungureanu - UNITBV

Contents
References......................................................................................................................................75
Functions .......................................................................................................................................76
Parameters and Arguments..............................................................................................79
Symbolic Constants ...........................................................................................................83
Global and Local Scope ....................................................................................................84
Scope Operator ..................................................................................................................85
Auto Variables ...................................................................................................................86
Register Variables .............................................................................................................86
Static Variables and Functions ........................................................................................87
Extern Variables and Functions ......................................................................................88
Runtime Stack ...................................................................................................................89
Inline Functions .................................................................................................................90
Recursion............................................................................................................................91
Default Arguments ............................................................................................................92
Overloading Functions......................................................................................................94
Creating New Types .....................................................................................................................97
Typedef ...............................................................................................................................97
Enumerations.....................................................................................................................98
Structures.........................................................................................................................100
Defining and Declaring Structures.........................................................................100
Accessing Structure Members ...............................................................................101
Initializing Structures.............................................................................................102
Pointers to Structures .............................................................................................102
Structures That Contain Structures ........................................................................103
Structures That Contain Arrays .............................................................................106
Pointers as Structure Members ..............................................................................107
Pointers and Arrays of Structures ..........................................................................108
Passing Structures as Arguments to Functions ......................................................110
Unions...............................................................................................................................111
Bit Fields...........................................................................................................................113
Object-Oriented Programming .................................................................................................115
Encapsulation .........................................................................................................115
Delia Ungureanu - UNITBV

Contents
Inheritance..............................................................................................................115
Polymorphism ........................................................................................................116
Classes ..............................................................................................................................116
Declaring a Class ...................................................................................................117
Implementing Class Methods ................................................................................118
Inline Implementation ............................................................................................119
Defining an Object.................................................................................................120
Accessing Class Members .....................................................................................120
Pointers to Classes .................................................................................................120
this Pointer .............................................................................................................122
Constructors ...........................................................................................................123
Destructors .............................................................................................................126
Static Members ......................................................................................................127
Friends....................................................................................................................128
Overloading......................................................................................................................129
Operator Overloading ............................................................................................130
Type Conversion..............................................................................................................133
Constructor conversion ..........................................................................................134
Operator conversion ...............................................................................................134
Inheritance ..................................................................................................................................136
Type Conversion..............................................................................................................140

Delia Ungureanu - UNITBV

Intro ductio n
The only way to learn a new programming
language is by writing programs in it.
- Brian Kernighan

This book is designed to help you teach how to program with C++.
You don't need any previous experience in programming to learn C++ with this presentation.
This book starts you from the beginning and teaches you both the language and the concepts
involved with programming C++. You'll find the numerous examples of syntax and detailed
analysis of code.
You'll learn about such fundamentals as managing I/O, loops and arrays, object-oriented
programming, templates, and creating C++ applications.
This book does not attempt to cover the difficult topic of Windows programming because we
believe you need to know the basics of programming first.
Lessons provide sample listings and complete with sample output and an analysis of the code.
To help you, each lesson ends with a set of common questions and answers, exercises, and a quiz.
You can check your progress by examining the quiz and exercise answers provided in the
course's appendix.
This course offers notions about computer programming using structural languages, procedural
languages, with examples in C++ programming language. It strive, also, that students obtain
abilities for programming through knowledge of data structures and programming techniques
concomitant with development of an application. It offers too basic notions about object oriented
programming.

Delia Ungureanu - UNITBV

Prelimina ries

Programs
The word program is used in two ways: to describe individual instructions, or source code,
created by the programmer, and to describe an entire piece of executable software. This
distinction can cause enormous confusion, so we will try to distinguish between the source code
on one hand, and the executable on the other.
A program can be defined as either a set of written instructions created by a
programmer or an executable piece of software.
Source code can be turned into an executable program in two ways: Interpreters translate the
source code into computer instructions, and the computer acts on those instructions immediately.
Alternatively, compilers translate source code into a program, which you can run at a later time.
While interpreters are easier to work with, most serious programming is done with compilers
because compiled code runs much faster. C++ is a compiled language.
Computer programs are composed of instructions and data. Instructions tell the computer to do
things, such as to add and subtract. Data is what the computer operates on, such as the numbers
that are added and subtracted. In mature programs, the instructions don't change as the program
executes (at least they're not supposed to). Data, on the other hand, can and usually does change
or vary as the program executes. A variable is nothing more than the name used to point to a
piece of this data.
C++, perhaps more than other languages, demands that the programmer design the program
before writing it. Trivial problems, such as the ones discussed in the first few chapters of this
book, don't require much design. Complex problems require design. A good design also makes
for a program that is relatively bug-free and easy to maintain.
The first question you need to ask when preparing to design any program is, "What is the
problem I'm trying to solve?" Every program should have a clear, well-articulated goal.
A solution to a problem is called an algorithm. It describes the sequence of steps to be performed
for the problem to be solved.
To be intelligible to a computer, an algorithm needs to be expressed in machine language, a
language understood by it. Programs expressed in the machine language are said to be
executable. A program written in any other language needs to be first translated to the machine
language before it can be executed.
A machine language is too cryptic to be used directly by the programmers. A further abstraction
of this language is the assembly language which provides mnemonic names for the instructions
and a more intelligible notation for the data. An assembly language program is translated to
machine language by a translator called an assembler.
Delia Ungureanu - UNITBV

Preliminaries
The assembly languages are difficult to work with, too. High-level languages such as C++
provide a much more convenient notation for implementing algorithms. A program written in a
high-level language is translated to assembly language by a translator called a compiler. The
assembly code produced by the compiler is then assembled to produce an executable program.

The Development Environment


The compiler may have its own built-in text editor, or you may be using a commercial text editor
or word processor that can produce text files. The important thing is that whatever you write your
program in, it must save simple, plain-text files, with no word processing commands embedded
in the text. Examples of safe editors include Windows Notepad, the DOS Edit command, etc.
Many commercial word processors, such as WordPerfect, Word, and dozens of others, also offer
a method for saving simple text files.
The files you create with your editor are called source files, and for C++ they typically are
named with the extension .CPP, .CP, or .C. In this book, we'll name all the source code files with
the .CPP extension.

Compiling the Source Code


To turn your source code into a program, you use a compiler. How you invoke your compiler,
and how you tell it where to find your source code, will vary from compiler to compiler; check
your documentation. In Borland's Turbo C++ you pick the RUN menu command. Other
compilers may do things slightly differently.
After your source code is compiled, an object file is produced. This file is often named with the
extension .OBJ. This is still not an executable program, however. To turn this into an executable
program, you must run your linker.
C++ programs are typically created by linking together one or more OBJ files with one or more
libraries. A library is a collection of linkable files that were supplied with your compiler, that
you purchased separately, or that you created and compiled. All C++ compilers come with a
library of useful functions (or procedures) and classes that you can include in your program. (A
function is a block of code that performs a service and a class is a collection of data and related
functions; we'll be talking about later in this book).
The steps to create an executable file are:
1. Create a source code file, with a .CPP extension.
2. Compile the source code into a file with the .OBJ extension.
3. Link your OBJ file with any needed libraries to produce a file with the .EXE extension that is
an executable program.

Delia Ungureanu - UNITBV

Preliminaries
Figure 1. C++ Compilation

A Simple C++ Program


Traditional programming books begin by writing the words Hello World to the screen, or a
variation on that statement.
The listing of this program, named FIRST.CPP, is Listing 1.
Listing 1
1
2
3
4
5
6

#include <stdio.h>
int main (void)
{
cout << "Hello World !\n";
return 0;
}

Comments:
1 This line uses the preprocessor directive #include to include the contents of the
header file iostream.h in the program. Iostream.h is a standard C++ header file
and contains definitions for input and output.
2

This line defines a function called main.() .


- A function may have zero or more parameters; these always appear after the
function name, between a pair of brackets
- All C++ programs must have exactly one main function. When your program
starts, main() is called automatically.
-The word void appearing between the brackets indicates that main has no
parameters.
- A function may also have a return type; this always appears before the function
name. The return type for main is int (i.e., an integer number).

This brace marks the beginning of the body of main.

This line is a statement. A statement is a computation step which may produce a


value.
- The end of a statement is always marked with a semicolon ( ;).
- This statement causes the string "Hello World\n" to be sent to the cout output
stream.

Delia Ungureanu - UNITBV

Preliminaries
- The last character in this string (\n) is a newline character which is similar to a
carriage return on a type writer. A stream is an object which performs input or
output. Cout is the standard output stream in C++ (standard output usually means
your computer monitor screen).
- The symbol << is an output operator which takes an output stream as its left
operand and an expression as its right operand, and causes the value of the latter
to be sent to the former. In this case, the effect is that the string "Hello World\n"
is sent to cout, causing it to be printed on the computer monitor screen.
This brace marks the end of the body of main.

The preprocessor runs before your compiler each time the compiler is invoked. The
preprocessor translates any line that begins with a pound symbol (#) into a special
command, getting your code file ready for the compiler.
A string is any sequence of characters enclosed in double-quotes, like Hello world.
A stream is an object which performs input or output. Cout is the standard output
stream in C++ (standard output usually means your computer monitor screen).
Compilation of source file FIRST.CPP produces a number of steps (most of which are transparent
to the user):
First, the C++ preprocessor goes over the program text and carries out the
instructions specified by the preprocessor directives (e.g., #include). The result
is a modified program text which no longer contains any directives.
 Then, the C++ compiler translates the program code and provides the
FIRST.OBJ file. The outcome may be incomplete due to the program referring to
library routines which are not defined as a part of the program. For example,
Listing 1 refers to the << operator which is actually defined in a separate IO
library.
 Finally, the linker completes the object code by linking it with the object code of
any library modules that the program may have referred to. The final result is an
executable file FIRST.EXE.


Try running FIRST.EXE; it should produce the Dialog 1.


Dialog 1
1

Hello World !

Delia Ungureanu - UNITBV

10

Preliminaries

Compile Errors
Unfortunately, almost every program, no matter how trivial, can and will have errors, or bugs, in
the program. Some bugs will cause the compile to fail, some will cause the link to fail, and some
will only show up when you run the program.
Whatever type of bug you find, you must fix it, and that involves editing your source code,
recompiling and relinking, and then rerunning the program.
Good compilers will not only tell you what you did wrong, they'll point you to the exact place in
your code where you made the mistake. The great ones will even suggest a remedy!
The Listing 2 is a demonstration of compiler error:
Listing 2
1
2
3
4
5

#include <iostream.h>
int main (void)
{
cout << "Hello World\n";
return 0;

Recompile your program and you should see an error that looks similar to the following dialog in
Message window:
Dialog 2
Compiling FIRST.CPP:
Err First.cpp 5: Compound statement missing terminating } in function
main().

Messages are written with the message class first, followed by the source file name and line
number where the error was detected, and finally with the text of the message itself.
Compiler Errors and Warnings
Compile-time error messages indicate errors in program syntax, command-line errors, or errors
in accessing a disk or memory.
When most compile-time errors occur, the compiler completes the current phase (preprocessing,
parsing, optimizing and code-generating) of the compilation and stops. But when fatal compiletime errors happen, compilation stops completely. If a fatal error occurs, you must fix the error
and restart compilation.
Run-time errors occur after the program has successfully compiled and is running. Run-time
errors are usually caused by logic errors in your program code. If you receive a run-time error,
you must fix the error in your source code and recompile the program for the fix to take effect.
Delia Ungureanu - UNITBV

11

Preliminaries
Warnings indicate that conditions which are suspicious but legitimate exist or that machinedependent constructs exist in your source files. Warnings do not stop compilation.
Linker Errors and Warnings do not make the linker stop or cause .EXE or .MAP files to be
deleted. When such errors happen, don't try to execute the .EXE file. Fix the error and re-link. A
fatal link error, however, stops the linker immediately. In such a case, the .EXE file is deleted.
Librarian errors and warnings occur when there is a problem with files or extended
dictionaries, when memory runs low, or when there are problems as libraries are accessed.

Using Comments
C++ comments come in two ways: the double-slash (//) comment and the slash-star (/*)
comment. The double-slash comment, which will be referred to as a C++-style comment, tells the
compiler to ignore everything that follows this comment, until the end of the line.
The slash-star comment mark tells the compiler to ignore everything that follows until it finds a
star-slash (*/) comment mark. These marks will be referred to as C-style comments. Every /*
must be matched with a closing */.
Many C++ programmers use the C++-style comment most of the time, and reserve C-style
comments for blocking out large blocks of a program.
As a general rule, the overall program should have comments at the beginning, telling you what
the program does. Each function should also have comments explaining what the function does
and what values it returns. Finally, any statement in your program that is obscure or less than
obvious should be commented as well.
Listing 3 demonstrates the use of comments, showing that they do not affect the processing of the
program or its output.
Listing 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14

/*
This is my first C++ program
*/
#include <iostream.h>
int main (void)
{
/* this is a comment
and it extends until the closing
star-slash comment mark */
cout << "Hello World\n";
// this comment ends at the end of the line
cout << "Hello World, again\n";
return 0; // this comment ends at the end of the line
}

Delia Ungureanu - UNITBV

12

Preliminaries
The comments on lines 1 through 3, 7 through 9 are completely ignored by the compiler, as
are the comments on lines 11, and 13. So, execution of this program produces Dialog 3.
Dialog 3
1
2

Hello World
Hello World, again

The ANSI Standard


The Accredited Standards Committee, operating under the procedures of the American National
Standards Institute (ANSI), is working to create an international standard for C++.
The draft of this standard
www.libertyassociates.com.

has

been

published,

and

link

is

available

at

The ANSI standard is an attempt to ensure that C++ is portable, that code you write for
Microsoft's compiler will compile without errors, using a compiler from any other vendor.
For most students of C++, the ANSI standard will be invisible. The standard has been stable for a
while, and all the major manufacturers support the ANSI standard.

Identifiers
Programming languages use names to refer to the various entities that make up a program. (i.e.,
variable names, function names, type names, and macro names, which will be described later in
this book).
Names are a programming convenience, which allow the programmer to organize what would
otherwise be quantities of plain data into a meaningful and human-readable collection. As a
result, no trace of a name is left in the final executable code generated by a compiler. For
example, a temperature variable eventually becomes a few bytes of memory which is referred to
by the executable code by its address, not its name.
C++ imposes the following rules for creating valid names (also called identifiers). A name
should consist of one or more characters, each of which may be a letter (i.e., 'A'-'Z' and 'a'-'z'), a
digit (i.e., '0'-'9'), or an underscore character ('_'), except that the first character may not be a
digit. Upper and lower case letters are distinct. For example:
distance

// valid identifier

dist1

// valid identifier

dist_1

// valid identifier

1_dist

// invalid identifier (begins with a digit)

distance

// valid identifier

Distance

// valid but distinct from distance

123

// invalid identifier (begins with a digit it is a


literal integer)

Delia Ungureanu - UNITBV

13

Preliminaries
C++ imposes no limit on the number of characters in an identifier, but, to make the program
legible, it must be short and suggestive.
Certain words are reserved by C++ for specific purposes and may not be used as identifiers.
These are called reserved words or keywords and are summarized in Table 1:
Table 1 C++ keywords.
asm
auto

continue
default

float
for

new
operator

signed
sizeof

try
typedef

break
case
catch
char
class
const

delete
do
double
else
enum
extern

friend
goto
if
inline
int
long

private
protected
public
register
return
short

static
struct
switch
template
this
throw

union
unsigned
virtual
void
volatile
while

Note: It isnt enabled to use keywords in other purpose.

Memory
A computer uses random-access memory (RAM) to store information while it's operating. RAM
is located in integrated circuits, or chips, inside your computer. RAM is volatile, which means
that it is erased and replaced with new information as often as needed. Being volatile also means
that RAM "remembers" only while the computer is turned on and loses its information when you
turn the computer off.
This memory can be thought of as a contiguous sequence of bits, each of which is capable of
storing a binary digit (0 or 1). Typically, the memory is also divided into groups of 8
consecutive bits (called bytes). The bytes are sequentially addressed. Therefore each byte can be
uniquely identified by its address (see Figure 2). Addresses are assigned to memory locations in
order, starting at zero and increasing to the system limit.
Note: You don't need to worry about addresses; it's all handled automatically by the
C/C++ compiler.
Each computer has a certain amount of RAM installed. The amount of RAM in a system is
usually specified in kilobytes (KB) or megabytes (MB), such as 512KB, 640KB, 2MB, 4MB, or
8MB. One kilobyte of memory consists of 1,024 bytes (210 bytes). Thus, a system with 640KB of
memory actually has 640 * 1,024, or 65,536, bytes of RAM. One megabyte is 1,024 kilobytes. A
machine with 4MB of RAM would have 4,096KB or 4,194,304 bytes of RAM.

Delia Ungureanu - UNITBV

14

Preliminaries
Figure 2 Organization of memory

While the exact binary representation of a data item is rarely of interest to a programmer, the
general organization of memory and use of addresses for referring to data items (as we will see
later) is very important.

Delia Ungureanu - UNITBV

15

Simp le Input/Output

The most common way in which a program communicates with the outside world is through
simple, character-oriented Input/Output (IO) operations.
C++ does not, as part of the language, define how data is written to the screen or to a file, nor
how data is read into a program. These are clearly essential parts of working with C++, however,
and the standard C++ library now includes the iostream library, which facilitates input and
output (I/O).
When a C++ program that includes the iostream classes starts, four objects are created and
initialized:
 cin handles

input from the standard input, the keyboard.

cout handles output to the standard output, the screen.


cerr handles unbuffered output to the standard error device, the screen. Because this is
unbuffered, everything sent to cerr is written to the standard error device immediately,
without waiting for the buffer to fill or for a flush command to be received.
 clog handles buffered error messages that are output to the standard error device, the
screen. It is common for this to be "redirected" to a log file



Note: Speaking about Input/Output we will use notions like variables, constants, data
types that are discussed later in this chapter.

Printing output
To send data to standard output, use the operator <<.
Note: C programmers know this operator as the bitwise left shift. C++ allows
operators to be overloaded. When you overload an operator, you give it a new
meaning when that operator is used with an object of a particular type. With iostream
objects, the operator << means send to.
For example:
cout << "cout example !";
sends the string cout example to the object called cout.
The special iostream function endl outputs the line and a newline. So Listing 3 and Listing 4 will
produce some result (Dialog 3)

Delia Ungureanu - UNITBV

16

Simple Input/Output
Listing 4
1
2
3
4
5
6
7
8
9
10

#include <iostream.h>
int main (void)
{
cout << "Hello World";
cout << endl;
cout << "Hello World, again";
cout << endl;
return 0;
}

Comments:
1 On this line the statement #include <iostream.h> causes the iostream.h file to be
added to your source code. This is required if you use cout and its related functions.
5

On line 5 is the simplest use of cout, printing a string or series of characters.

6
7

endl tells cout to print a newline character to the screen.


This line 5 prints another string to the screen

It prints a newline character to the screen.

Inside a character string, you can insert special characters that do not print using escape
sequences. These consist of a backslash (\) followed by a special code. For example \n means
new line. Your compiler manual or local Standard C guide gives a complete set of escape
sequences; others include \t (tab), \\ (backslash) and \b (backspace).
An important feature is string concatenation. If two quoted strings are adjacent, and no
punctuation is between them, the compiler will paste the strings together as a single string. This is
particularly useful when printing code listings in books and magazines that have width
restrictions:
Listing 5
1
2
3
4
5
6
7
8
9
10

#include <iostream.h>
int main (void)
{
// Example of string concatenation
cout << "This string is far too long to put on a single "
"line but it can be broken up with no ill effects\n"
"as long as there is no punctuation separating "
"adjacent strings.\n";
}

Delia Ungureanu - UNITBV

17

Simple Input/Output
Comments:
On lines 6..9 an informative message is printed. It is create by string concatenation.
The effect of running of Listing 5 is Dialog 4
Dialog 4
1
2
3

This string is far too long to put on a single line but it can be
broken up with no ill effects
as long as there is no punctuation separating adjacent strings

String arguments and constant numbers are mixed in the cout statement. Because the operator <<
is overloaded with a variety of meanings when used with cout, you can send cout a variety of
different arguments. Floating-point numbers are determined automatically, by the compiler. In
addition, any character can be sent to a stream object using a cast to a character (a char is a data
type designed to hold characters), which looks like a function call: char( ), along with the
character's ASCII value. In the above program, an escape is sent to cout.
Listing 6
1
2
3
4
5
6
7
8
9
10
11
12
13

#include <iostream.h>
int main (void)
{
cout << "It will be printed different type of data:\n";
cout << "string: " << "abcd" <<endl;
cout << "char: " << 'a' << endl;
cout << "char: " << char(97) <<endl;
cout << "non-printing char (escape): "<< char(27) << endl;
cout << "integer: " << 123 <<endl;
cout << "long: " << -1234567 <<endl;
cout << "double: " << 123.456 << endl;
}

Comments:
6 Three values are passed to cout on line 6, and each value is separated by the
insertion operator. The first value is the string "string: ". Note the space after the
colon. The space is part of the string. Next value is a string too; it is passed to the
insertion operator and then newline follows. This causes the line
string: abcd

to be printed to the screen. Because there is no newline character after the first
string, the next value is printed immediately afterwards. This is called concatenating
the two values.
7

On this line, are printed the string char: , the character a and a newline.

Delia Ungureanu - UNITBV

18

Simple Input/Output
8

To print a character is used the function char() and the ASCII cod character.

9 The value 27 is the cod for a non-printing character, the character escape.
10..12 On this lines are included different type numbers determined automatically by the
compiler
The effect of Listing 6 is Dialog 5.
Dialog 5
It will be printed different type of data:
string : abcd"
char : a
char : a
non-printing char (escape):
integer : 123
long : -1234567
double : 123.456

Reading input
The iostreams class provides the ability to read input. The object used for standard input is cin.
cin normally expects input from the console, but input can be redirected from other sources. (The
redirection isnt object of this chapter).
The iostreams operator used with cin is >>. This operator waits for the same kind of input as its
argument. For example, if you give it an integer argument, it waits for an integer from the
console. Here's an example program that reads an integer and a real and it prints it.
Listing 7
1
2
3
4
5
6
7
8
9
10
11
12
13

#include <iostream.h>
int main (void)
{
int integer;
float real ;
cout << "Enter a decimal number: ";
cin >> integer;
cout << "Enter a real number: ";
cin >> real;
cout << "value of integer is: " << integer << endl;
cout << "value of real is: " << real << endl;
}

Notice the declaration of the integer number at the beginning of main( ). Since the extern
keyword isn't used, the compiler creates space for number at that point.
Delia Ungureanu - UNITBV

19

Simple Input/Output
Note: Both << and >> return their left operand as their result, enabling multiple input
or multiple output operations to be combined into one statement. This is illustrated by
Listing 6, Listing 7
The output formatting available with iostreams includes number formatting in decimal, octal and
hex. Here's another example of the use of iostreams:
Listing 8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#include <iostream.h>
int main (void)
{
// Specifying formats with manipulators:
int integer;
cout << "input a number in decimal: " ;
cin >> integer;
cout << "in octal is: " << oct << integer << endl;
cout << "in hex is: " << hex << integer << endl;
cout << "input a number in octal: " ;
cin >> oct >> integer;
cout << "in decimal is: " << dec << integer << endl;
cout << "in hex is: " << hex << integer << endl;
}

This example shows the iostreams class printing numbers in decimal, octal and hexadecimal
using iostream manipulators (which don't print anything, but change the state of the output
stream).
Dialog Error! No text of specified style in document.6
1
2
3
4
5
6

input a number in decimal: 123


in octal is: 173
in hex is: 7b
input a number in octal: 123
in decimal is: 83
in hex is: 53

Comments:

If at Listing 8 execution on first line you introduce decimal value 123, on next lines it
will be printed as octal value (173) and hexadecimal value (7b).
On the line number 4 you must introduce an octal value, so all digits must be among 0 ..
7. On line 5 the value will be printed as decimal value, 83 and on line 6 as hexadecimal
value, 53.

Delia Ungureanu - UNITBV

20

Variables
A variable is a named data storage location in your computer's memory. By using a variable's
name in your program, you are, in effect, referring to the data stored there.
All variables have two important attributes (we will discuss about later in this chapter):
 A type which is established when the variable is defined (e.g., integer, real,
character). Once defined, the type of a C++ variable cannot be changed.
 A value which can be changed by assigning a new value to the variable. The kind
of values a variable can assume depends on its type. For example, an integer
variable can only take integer values (e.g., 1, 99, -555).

Variable Names
Your variable's name (for example, myVariable) is an identifier. Keywords can't be used as
variable names.
The following list contains some examples of legal and illegal C variable names:
number

// legal

Percent

// legal

annual_profit

// legal

_1111_2222

// legal but not advised

circle*radius

// illegal contains illegal character *

float

// illegal is a C++ keyword

Note: C/C++ programmers commonly use only lowercase letters in variable names,
although this isn't required. Using all-uppercase letters is usually reserved for the
names of constants (which are covered later in this chapter).
DO use variable names that are descriptive.
DO adopt and stick with a style for naming your variables.
DON'T start your variable names with an underscore unnecessarily.
DON'T name your variables with all capital letters unnecessarily.

Data types and sizes


Numeric Variable Types
C++ provides several different types of numeric variables. You need different types of variables
because different numeric values have varying memory storage requirements and differ in the
Delia Ungureanu - UNITBV

21

Variables
ease with which certain mathematical operations can be performed on them. Small integers (for
example, 1, -5, and 125) require less memory to store, and your computer can perform
mathematical operations (addition, multiplication, and so on) with such numbers very quickly. In
contrast, large integers and floating-point values (123456789 or 0.123456789, for example)
require more storage space and more time for mathematical operations. By using the appropriate
variable types, you ensure that your program runs as efficiently as possible.
There are two numerical categories:
Integer variables that have no fractional part. Integer variables come in two flavors:
signed integer variables can hold positive or negative values, whereas unsigned integer
variables can hold only positive values (and 0).
 Floating-point variables hold values that have a fractional part (that is, real numbers).


Within each of these categories are more specific variable types. These are summarized in Table
2, which also shows the amount of memory, in bytes, required to hold a single variable of each
type.
Table 2 Numeric data types.
Variable Type

Keyword

Character
char
Integer
int
Short integer
short
Long integer
long
Unsigned character
unsigned char
Unsigned integer
unsigned int
Unsigned short integer
unsigned short
Unsigned long integer
unsigned long
Single-precision floating-point
float
Double-precision floating-point
double
Long double-precision floatinglong double
point
1
Approximate range; precision = 7 digits.
2
Approximate range; precision = 15 digits.
3
Approximate range; precision = 19 digits.

Bytes
Required
1
2
2
4
1
2
2
4
4
8
10

Range
-128 to 127
-32768 to 32767
-32768 to 32767
-2,147,483,648 to 2,147,438,647
0 to 255
0 to 65535
0 to 65535
0 to 4,294,967,295
+/-(3.4E-383.4E+38)1
+/-(1.7E-3081.7E+308)2
+/-(3.4E-49321.1E4932)3

Note: The sizes of variables might be different from those shown in Error!
Reference source not found., depending on the compiler and the computer you are
using. You should consult your compiler's manual for the values that your variable
types can hold.
The C++ compiler generates executable code which maps data entities to memory locations. For
example, the variable definition:
Delia Ungureanu - UNITBV

22

Variables
int myVariable = 12000;

causes the compiler to allocate two bytes to represent myVariable. The exact number of bytes
allocated and the method used for the binary representation of the integer depends on the specific
C++ implementation. The compiler uses the address of the first byte at which myVariable is
allocated to refer to it. The above assignment causes the value 12000 to be stored as a 2s
complement integer in the two bytes allocated (see Figure 3).
Figure 3 Representation of an integer in memory.

Listing 9 will help you determine the size of variables on your particular computer.
Listing 9 A program that displays the size of variable types.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include <iostream.h>
int main (void)
{
cout << "\nA char
cout << "\nAn int
cout << "\nA short
cout << "\nA long
cout << "\nAn unsigned
cout << "\nAn unsigned
cout << "\nAn unsigned
cout << "\nAn unsigned
cout << "\nA float
cout << "\nA double
return 0;
}

is " << sizeof( char ) << " bytes";


is " << sizeof( int ) << " bytes";
is " << sizeof( short ) << " bytes";
is " << sizeof( long ) << " bytes";
char is " << sizeof( unsigned char ) << " bytes";
int
is " << sizeof( unsigned int ) << " bytes";
short is " << sizeof( unsigned short ) << " bytes";
long is " << sizeof( unsigned long ) << " bytes";
is " << sizeof( float ) << " bytes";
is " << sizeof( double ) << " bytes";

The result of running this program is Dialog 7.


Delia Ungureanu - UNITBV

23

Variables
Dialog 7
A char

is 1 bytes

An int

is 2 bytes

A short

is 2 bytes

A long

is 4 bytes

An unsigned char

is 1 bytes

An unsigned int

is 2 bytes

An unsigned short is 2 bytes


An unsigned long

is 4 bytes

A float

is 4 bytes

A double

is 8 bytes

Note: Use the sizeof operator to return the size, in bytes, of the given expression or
type. On your computer, the number of bytes presented might be different.

Integer Numbers
An integer variable may be defined to be of type short, int, or long.
short

age = 20;

int

max_no = 32000;

long

distance = 500000;

By default, an integer variable is assumed to be signed (i.e., have a signed representation so that it
can assume positive as well as negative values). However, an integer can be defined to be
unsigned by using the keyword unsigned in its definition. The keyword signed is also allowed but
is redundant.
unsigned short

age = 20;

unsigned int

max_no = 32000;

unsigned long

distance = 500000;

A literal integer (e.g., 2004) is always assumed to be of type int. If it has an L or l suffix it is
treated as a long. Also, a literal integer can be specified to be unsigned using the suffix U or u.
For example:
2004L

2004l

2004U

2004u

2004LU

2004ul

Literal integers can be expressed in decimal, octal, and hexadecimal notations. The decimal
notation is the one we have been using so far. An integer is taken to be octal if it is preceded by a
zero (0), and hexadecimal if it is preceded by a 0x or 0X. For example:
Delia Ungureanu - UNITBV

24

Variables
165

// decimal

0245

// octal equivalent of 165 decimal

0xA5

// hexadecimal equivalent of 165 decimal

Octal numbers use the base 8, and can therefore only use the digits 0-7.
Hexadecimal numbers use the base 16, and therefore use the letter A-F

Note:

(or a-f) to represent, respectively, 10-15.


Octal and hexadecimal numbers are calculated as follows:
0245 = 2 82 + 4 81 + 5 80 = 128 + 32 + 5 = 165
0xA5 = 10 161 + 5 160 = 160 + 5 = 165

Real Numbers
A real variable may be defined to be of type float, double or long double. On some PC, a float
uses 4, a double uses 8 bytes and a long double 10 bytes.
float

radius = 4.5;

double

pi = 3.141592654;

long double distance = 55.55 e-555

A literal real (e.g., 0.06) is always assumed to be of type double. If it has an F or f suffix it is
treated as a float, or an L or l suffix it is treated as a long double. For example:
0.01F

0.01f

3.1415L

3.1415l

Literal reals may also be expressed in scientific notation. For example, 0.001234 may be written
in the scientific notation as:
1.234E-3

or

1.234e-3

The letter E (or e) stands for exponent. The scientific notation is interpreted as follows:
1.234E-3 = 1.234 10-3

Characters
A character variable is defined to be of type char. A character variable occupies a single byte
which contains the code for the character. This code is a numeric value and depends on the
character coding system being used (i.e., is machine-dependent). The most common system is
ASCII (American Standard Code for Information Interchange). For example, the character A has
the ASCII code 65, and the character a has the ASCII code 97.
char ch = 'A';

Like integers, a character variable may be specified to be signed or unsigned. By the default (on
most systems) char means signed char. However, on some systems it may mean unsigned char. A
signed character variable can hold numeric values in the range -128 through 127. An unsigned
character variable can hold numeric values in the range 0 through 255. As a result, both are often
Delia Ungureanu - UNITBV

25

Variables
used to represent small integers in programs (and can be assigned numeric values like integers):
signed char

offset = -88;

unsigned char

row = 2, column = 26;

A literal character is written by enclosing the character between a pair of single quotes (e.g.,
A).
Nonprintable characters are represented using escape sequences (see Table 3 Table 3).
Table 3 Escape sequences
Sequence

Character

Meaning

\a

alarm (bell)

alarm

\b

BS

backspace

\f

FF

formfeed

\n

LF

linefeed (new line)

\r

CR

carrige return

\t

TAB

tab orizontal

\v

VT

tab vertical

\\

backslash (\)

single quote (')

double quote (")

\?

question mark

\o

any character

octal digits

\xH

any character

hexadecimal digits

Literal characters may also be specified using their numeric code value. The general escape
sequence \ooo (i.e., a backslash followed by up to three octal digits) is used for this purpose. For
example (assuming ASCII):
'\12'

// newline (decimal code = 10)

'\11'

// horizontal tab (decimal code = 9)

'\101'

// 'A' (decimal code = 65)

'\0'

// null (decimal code = 0)

Strings
Text inside double quotes is called a string. The compiler creates space for strings and stores the
ASCII equivalent for each character in this space. The string is terminated with a value of 0 to
indicate the end of the string. A string is a consecutive sequence (i.e., array) of characters which
Delia Ungureanu - UNITBV

26

Variables
are terminated by a null character.
A string variable is defined to be of type char* (i.e., a pointer to character). A pointer is simply
the address of a memory location. (Pointers will be discussed later). A string variable contains the
address of where the first character of a string appears. For example, consider the definition:
char*str = "STRING";

Figure 4 illustrates how the string variable str and the string "STRING" might appear in memory.
Figure 4 A string variable in memory.

A literal string is written by enclosing its characters between a pair of double quotes (e.g.,
"STRING). The compiler always appends a null character to a literal string to mark its end. The
characters of a string may be specified using any of the notations for specifying literal characters.
For example,
"Name\tAddress\tTelephone"

// tab-separated words

"ASCII character 65: \101"

// 'A' specified as '101'

A long string may extend beyond a single line, in which case each of the preceding lines should
be terminated by a backslash. For example:
"Example to show \
the use of backslash for \
writing a long string"

The backslash in this context means that the rest of the string is continued on the next line. The
above string is equivalent to the single line string:
"Example to show the use of backslash for writing a long string"

Note:
A common programming error results from confusing a single-character
string (e.g., "A") with a single character (e.g., A). These two are not equivalent. The
first consists of two bytes (the character A followed by the character \0), whereas
the latter consists of a single byte.
Note:
The shortest possible string is the null string ("") which simply consists of
the null character.

Delia Ungureanu - UNITBV

27

Variables

Symbolic Constants
A symbolic constant is a constant that is represented by a name (symbol) in your program. Like a
literal constant, a symbolic constant can't change. Whenever you need the constant's value in your
program, you use its name as you would use a variable name. The actual value of the symbolic
constant needs to be entered only once, when it is first defined.
Symbolic constants have two significant advantages over literal constants, as the following
example shows. Suppose that you're writing a program that performs a variety of geometrical
calculations. The program frequently needs the value 3.14159 for its calculations. (You might
recall from geometry class that, is the ratio of a circle's circumference to its diameter.) For
example, to calculate the circumference and area of a circle with a known radius, you could write
circumference = 3.14159 * (2 * radius);
area = 3.14159 * (radius)*(radius);

The asterisk (*) is the multiplication operator and is covered later in this chapter. Thus, the first
of these statements means "Multiply 2 times the value stored in the variable radius, and then
multiply the result by 3.14159. Finally, assign the result to the variable named circumference."
If, however, you define a symbolic constant with the name PI and the value 3.14, you could write
circumference = PI * (2 * radius);
area = PI * (radius)*(radius);

The resulting code is clearer. Rather than puzzling over what the value 3.14 is for, you can see
immediately that the constant PI is being used.
The second advantage of symbolic constants becomes apparent when you need to change a
constant. Continuing with the preceding example, you might decide that for greater accuracy your
program needs to use a value of PI with more decimal places: 3.14159 rather than 3.14. If you
had used literal constants for PI, you would have to go through your source code and change each
occurrence of the value from 3.14 to 3.14159. With a symbolic constant, you need to make a
change only in the place where the constant is defined.
C++ has two methods for defining a symbolic constant: the #define directive and the const
keyword.

Using #define directive


The #define directive is a preprocessor directives and it is used as follows:
#define CONSTNAME literal

This creates a constant named CONSTNAME with the value of literal. literal represents a literal
constant, as described earlier. CONSTNAME follows the same rules described earlier for
identifiers.
Note:
By convention, the names of symbolic constants are uppercase; this makes
them easy to distinguish from variable names, which by convention are lowercase.
For the previous example, the required #define directive would be
Delia Ungureanu - UNITBV

28

Variables
#define PI 3.14159

Note:

#define lines don't end with a semicolon (;).

Note:
#defines can be placed anywhere in your source code, but they are in effect
only for the portions of the source code that follow the #define directive. Most
commonly, programmers group all #defines together, near the beginning of the file
and before the start of main().

How a #define Works


The precise action of the #define directive is to instruct the compiler as follows: "In the source
code, replace CONSTNAME with literal." The effect is exactly the same as if you had used your
editor to go through the source code and make the changes manually. Note that #define doesn't
replace instances of its target that occur as parts of longer names, within double quotes, or as part
of a program comment. For example, in the following code, the instances of PI in the second and
third lines would not get changed:
#define PI 3.14159
/* You have defined a constant for PI. */
#define MIN 100
#define MAX 999999

Defining Constants with the const Keyword


The second way to define a symbolic constant is with the const keyword. const is a modifier that
can be applied to any variable declaration. A variable declared to be const can't be modified
during program execution, only initialized at the time of declaration. Here are some examples:
const int step = 100;
const float pi = 3.14159;
const int min = 100, long max = 999999;

const affects all variables on the declaration line. In the last line, min and max are symbolic
constants.
Note:
If your program tries to modify a const variable, the compiler generates an
error message, as shown here:
const int min = 100;
min = 1000;
/* Does not compile! Cannot reassign or alter
the value of a constant. */
Delia Ungureanu - UNITBV

29

Variables
Listing 10 A program that demonstrates the use of variables and constants.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

/* Demonstrates variables and constants */


#include <iostream.h>
/* Define a constant to convert from pounds to grams */
#define GRAMS_PER_POUND 454
/* Define a constant for the start of the next century */
const int grams_per_kilo = 1000;
int main (void)
{
/* Declare the needed variables */
long weight_in_grams, weight_in_pounds;
float weight_in_kilos;
/* Input data from user */
cout << "Enter your weight in pounds: ";
cin >> weight_in_pounds;
/* Perform conversions */
weight_in_grams = weight_in_pounds * GRAMS_PER_POUND;
weight_in_kilos = (float)weight_in_grams / grams_per_kilo;
/* Display results on the screen */
cout << "\nThe weight in grams = " << weight_in_grams;
cout << "\nThe weight in kilos = " << weight_in_kilos;
return 0;
}

Comments:
This program declares the two types of symbolic constants in lines 6 and 9. In line
6, a constant is used to make the value 454 more understandable. Because it uses
GRAMS_PER_POUND, line 22 is easy to understand. Lines 14 and 15 declare the
variables used in the program. Notice the use of descriptive names such as
weight_in_grams. You can tell what this variable is used for. Lines 22 and 23
calculate the weight in grams and in kilograms. These statements are covered
below in this chapter. To finish the program, lines 26 and 27 display the results.
If when you run Listing 10 you introduce 100 as value for weight_in_pound, on the screen will
display:

Delia Ungureanu - UNITBV

30

Variables
Dialog 8
Enter the weight in pounds: 100
The weight in grams = 45400
The weight in kilos = 45.4

DO use constants to make your programs easier to read.

Delia Ungureanu - UNITBV

31

Operators and ex pressions

An expression is any computation which yields a value. When discussing expressions, we often
use the term evaluation. For example, we say that an expression evaluates to a certain value. In
some cases, the expression may also produce side-effects. These are permanent changes in the
program state. In this sense, C++ expressions are different from mathematical expressions.
C++ provides operators for composing arithmetic, relational, logical, bitwise, and conditional
expressions. It also provides operators which produce useful side-effects, such as assignment,
increment, and decrement. We will also discuss the precedence rules which govern the order of
operator evaluation in a multi-operator expression.
An operator is a symbol that instructs C++ to perform some operation, or action, on one or more
operands. An operand is something that an operator acts on. In C++, all operands are
expressions. C++ operators fall into several categories according to number of operand (unary,
binary and ternary operators) or type of actions (arithmetic, relational, logical, bitwise, etc.).

The Assignment Operator


The assignment operator (=) causes the operand on the left side of the assignment operator to
have its value changed to the value on the right side of the assignment operator.
The form is as follows:
variable = expression;

When executed, expression is evaluated, and the resulting value is assigned to variable.
If you write:
x = y;

it means "assign the value of y to x."


Note:
In a C++ program, it doesn't mean "x is equal to y." Instead, it means
"assign the value of y to x."
The expression:
x = a + b;

assigns the value that is the result of adding a and b to the operand x.
An operand that legally can be on the left side of an assignment operator is called an lvalue. That
which can be on the right side is called an rvalue.
An lvalue (standing for left value) is anything that denotes a memory location in which a value
may be stored. The only kind of lvalue we have seen so far in this book is a variable. Other kinds
of lvalues (based on pointers and references) will be described later in this book.

Delia Ungureanu - UNITBV

32

Operators and expressions


Constants are r-values. They cannot be l-values. Thus, you can write
x = 35;

// ok

but you can't legally write


35 = x;

// error, not an lvalue!

Note:
An lvalue is an operand that can be on the left side of an expression. An
rvalue is an operand that can be on the right side of an expression. Note that all lvalues are r-values, but not all r-values are l-values. An example of an rvalue that is
not an lvalue is a literal. Thus, you can write x = 5;, but you cannot write 5 = x;.

Arithmetic Operators
C++'s arithmetic operators perform mathematical operations. C++ has four unary arithmetic
operators and five binary arithmetic operators.

Unary Arithmetic Operators


The unary arithmetic operators are so named because they take a single operand. They are listed
in Table 4 .
Table 4 Unary arithmetic operators
Operator

Symbol

Action

Examples

Plus

Keeps the sign

+x

Minus

Changes the sign

-x

Increment

++

Increments the operand by one

++x, x++

Decrement

--

Decrements the operand by one

--x, x--

The increment and decrement operators can be used only with variables, not with constants. The
operation performed is to add one to or subtract one from the operand. In other words, the
statements
++x;
--y;

are equivalent of these statements:


x = x + 1;
y = y - 1;

The increment and decrement operators can be placed before its operand (prefix mode) or after its
Delia Ungureanu - UNITBV

33

Operators and expressions


operand (postfix mode). These two modes are not equivalent. They differ in terms of when the
increment or decrement is performed:


when use in prefix mode, the increment and decrement operators modify their operand
before it's used.

when use in postfix mode, the increment and decrement operators modify their
operand after it's used.

An example should make this clearer. Look at these two statements:


x = 10;
y = x++;

After these statements are executed, x has the value 11, and y has the value 10. The value of x
was assigned to y, and then x was incremented. In contrast, the following statements result in
both y and x having the value 11. x is incremented, and then its value is assigned to y.
x = 10;
y = ++x;

Listing 11 illustrates the difference between prefix mode and postfix mode.
Listing 11 Demonstrates prefix and postfix modes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/* Demonstrates unary operator prefix and postfix modes */


#include <iostream.h>
int main(void)
{
int a, b;
/* Set a and b both equal to 5 */
a = b = 5;
/* Print them, decrementing each time. */
/* Use prefix mode for b, postfix mode for a */
cout << "\na
cout << "\na
cout << "\na
cout << "\na
cout << "\na
return 0;

=
=
=
=
=

"
"
"
"
"

<<
<<
<<
<<
<<

a-a-a-a-a--

<<
<<
<<
<<
<<

",
",
",
",
",

b
b
b
b
b

=
=
=
=
=

"
"
"
"
"

<<
<<
<<
<<
<<

--b;
--b;
--b;
--b;
--b;

Comments:
This program declares two variables, a and b, in line 6. In line 8, the variables are
set to the value of 5. With the execution of each output statement (lines 13 through
17), both a and b are decremented by 1. After a is printed, it is decremented,
whereas b is decremented before it is printed.
Delia Ungureanu - UNITBV

34

Operators and expressions


The result of Listing 11 execution is:
Dialog 9
a
a
a
a
a

=
=
=
=
=

5,
4,
3,
2,
1,

b
b
b
b
b

=
=
=
=
=

4
3
2
1
0

Note:
The increment and decrement operators can only be applied to variables;
an expressions like
x=(i+j)++;
5++;
are illegal.

Binary Arithmetic Operators


C++'s binary operators take two operands. C++ provides five basic arithmetic operators. These
are summarized in
Table 5.
Table 5 Binary mathematical operators.
Operator

Symbol

Action

Examples

Addition

Adds two operands

x+y

Subtraction

Subtracts the second operand from the first operand

x- y

Multiplication

Multiplies two operands

x* y

Division

Divides the first operand by the second operand

x/y

Modulus

Gives the remainder when the first operand is x % y


divided by the second operand

Except for remainder (%) all other arithmetic operators can accept a mix of integer and real
operands. Generally, if both operands are integers then the result will be an integer. However, if
one or both of the operands are reals then the result will be a real.
When both operands of the division operator (/) are integers then the division is performed as an
integer division and not the normal division we are used to. Integer division always results in an
integer outcome (i.e., the result is always rounded down). For example:
9 / 2

// gives 4, not 4.5!

-9 / 2

// gives -5, not -4!

Delia Ungureanu - UNITBV

35

Operators and expressions


Unintended integer divisions are a common source of programming errors. To obtain a real
division when both operands are integers, you should cast one of the operands to be real:
int

distance = 100;

int

time = 80;

float

speed = distance / (float) time;

// gives 1.25

The remainder operator (%) expects integers for both of its operands. It returns the remainder of
integer-dividing the operands. For example 22 *5 is calculated by integer dividing 22 by 5 to give
an outcome of 4 and a remainder of 2; the result is therefore 2.
Note:
It is possible for the outcome of an arithmetic operation to be too large for
storing in a designated variable. This situation is called an overflow. The outcome of
an overflow is machine-dependent and therefore undefined. For example:
char

a = 20 *15;

// overflow: 300 > 127

Note:
It is illegal to divide a number by zero. This results in a run-time divisionby-zero failure which typically causes typically causes the program to terminate.

Bitwise Operators
C++ provides six bitwise operators for manipulating the individual bits in an integer quantity.
These are summarized in Table 6.
Table 6 Bitwise operators.
Operator

Symbol

Action

Examples

Bitwise
Negation

Clears every bit in a number that is set and sets


every bit that is clear

Bitwise And

&

Execute operation and bit by bit

x&y

Bitwise Or

Execute operation or bit by bit

x| y

Bitwise
Exclusive Or

Execute operation exclusive or bit by bit

x^y

Bitwise
Shift

Left

<<

Produces a bit sequence equal to the left operand


but which has been shifted y bit positions to the left

x << y

Bitwise Right
Shift

>>

Produces a bit sequence equal to the left operand


but which has been shifted y bit positions to the
right

x >> y

~x

Bitwise operators expect their operands to be integer quantities and treat them as bit sequences.
Bitwise negation is a unary operator which reverses the bits in its operands. Bitwise and
Delia Ungureanu - UNITBV

36

Operators and expressions


compares the corresponding bits of its operands and produces a 1 when both bits are 1, and 0
otherwise. Bitwise or compares the corresponding bits of its operands and produces a 0 when
both bits are 0, and 1 otherwise. Bitwise exclusive or compares the corresponding bits of its
operands and produces a 0 when both bits are 1 or both bits are 0, and 1 otherwise.
Bitwise left shift operator and bitwise right shift operator both take a bit sequence as their left
operand and a positive integer quantity n as their right operand. The former produces a bit
sequence equal to the left operand but which has been shifted n bit positions to the left. The latter
produces a bit sequence equal to the left operand but which has been shifted n bit positions to the
right. Vacated bits at either end are set to 0.
Table 7 illustrates bit sequences for the sample operands and results. To avoid worrying about the
sign bit (which is machine dependent), it is common to declare a bit sequence as an unsigned
quantity:
Table 7 How the bits are calculated.
Expression

Value

Bit Sequence

23

~ x

232

23

45

x & y

23

45

x | y

63

23

45

x ^ y

58

23

x >> 2

23

x << 2

92

Relational Operators
C++ does not have a built-in boolean type. In C++, zero is considered false, and all other values
are considered true, although true is usually represented by 1. Thus, if an expression is false, it is
equal to zero, and if an expression is equal to zero, it is false. If a statement is true, all you know
Delia Ungureanu - UNITBV

37

Operators and expressions


is that it is nonzero, and any nonzero statement is true.


A value of zero represents false.

Any nonzero value represents true.

The relational operators are used to determine whether two numbers are equal, or if one is greater
or less than the other. Every relational statement evaluates to either 1 (TRUE) or 0 (FALSE).
C++ provides six relational operators for comparing numeric quantities. These are summarized in
Table 8.
Table 8 Relational Operators
Operator

Symbol

Action

Examples

Equal

==

Is operand 1 equal to operand 2?

5 == 5 //gives 1

Inequal

!=

Is operand 1 greater than operand 2?

5 != 5 //gives 0

Less Than

<

Is operand 1 less than operand 2?

5 < 5.5//gives 1

Less Than
Equal
Greater Than

or <=

Is operand 1 greater than or equal to operand 5 <= 5 //gives 1


2?

>

Greater Than or >=


Equal

Is operand 1 less than or equal to operand 2?

5 > 5.5//gives 0

Is operand 1 not equal to operand 2?

6.3>= 5//gives 1

The operands of a relational operator must evaluate to a number. Characters are valid operands
since they are represented by numeric values. For example (assuming ASCII coding):
'A' < 'F'

// gives 1 (is like 65 < 70)

Note:
The relational operators should not be used for comparing strings, because
this will result in the string addresses being compared, not the string contents. For
example, the expression
"STRING1" < "STRING2"
causes the address of "STRING1" to be compared to the address of "STRING2". As
these addresses are determined by the compiler (in a machine-dependent manner), the
outcome may be 0 or may be 1, and is therefore undefined.
C++ provides library functions (e.g., strcmp) for the lexicographic comparison of
strings.
Note:
The <= and >= operators are only supported in the form shown. In
particular, =< and => are both invalid and do not mean anything.
DON'T confuse ==, the relational operator, with =, the assignment operator. This is
Delia Ungureanu - UNITBV

38

Operators and expressions


one of the most common errors that C++ programmers make.

Logical Operators
C++ provides three logical operators for combining logical expression. These are summarized in
Table 9. Like the relational operators, logical operators evaluate to 1 or 0.
Table 9 Logical Operators
Operator

Symbol

Action

Examples

NOT

Return 1 if the operand is false, otherwise !(5==5)//gives 0


return 0

AND

&&

If both operands are true, the expression is


true, otherwise return 0

5 < 6 && 6 < 8


//gives 1

OR

||

If either one operand is true, the expression is


true, otherwise return 0

5 < 6 || 6 < 5
// gives 1

Logical negation is a unary operator, which negates the logical value of its single operand. If its
operand is nonzero it produces 0, and if it is 0 it produces 1.
Logical and produces 0 if one or both of its operands evaluate to 0. Otherwise, it produces 1.
Logical or produces 0 if both of its operands evaluate to 0. Otherwise, it produces 1.
!20

// gives 0

10 && 5

// gives 1

10 || 5.5

// gives 1

0 || 3

// gives 1

10 && 0

// gives 0

DO use (expression == 0) instead of (!expression). When compiled, these two


expressions evaluate the same; however, the first is more readable.
DO use the logical operators && and || instead of nesting if statements.

Conditional Operator
The conditional operator is C++'s only ternary operator, meaning that it takes three operands. Its
syntax is
exp1 ? exp2 : exp3;

Delia Ungureanu - UNITBV

39

Operators and expressions


If exp1 evaluates to true (that is, nonzero), the entire expression evaluates to the value of exp2. If
exp1 evaluates to false (that is, zero), the entire expression evaluates as the value of exp3. For
example to make max equal to the larger of x and y, you could write
max = (x > y) ? x : y;

Note:
The conditional operator functions somewhat like an if statement. The
preceding statement could also be written like this:
if (x > y)
max = x;
else
max = y;

Note:
Note that of the second and the third operands of the conditional operator
only one is evaluated. This may be significant when one or both contain side-effects
(i.e., their evaluation causes a change to the value of a variable). For example, in
int max = (x > y ? x++ : y++);
only one of x and y is incremented.
Note:
Because a conditional operation is itself an expression, it may be used as
an operand of another conditional operation, that is, conditional expressions may be
nested. For example:
int x = 1, y = 2, z =3;
int max = (x >y ? (x > z ? x : z) : (z > y ? z : y));

Compound Assignment Operator


The assignment operator is used for storing a value at some memory location (typically denoted
by a variable). Its left operand should be an lvalue, and its right operand may be an arbitrary
expression. The latter is evaluated and the outcome is stored in the location denoted by the lvalue.
The assignment operator has a number of variants, obtained by combining it with the arithmetic
and bitwise operators.
Compound assignment operators provide a shorthand method for combining a binary operation
with an assignment operation. For example, you could write
x = x + 5;

Using a compound assignment operator, which you can think of as a shorthand method of
assignment, you would write
x += 5;

In more general notation, the compound assignment operators have the following syntax (where
op represents a binary operator):
exp1 op= exp2

This is equivalent to writing


Delia Ungureanu - UNITBV

40

Operators and expressions


exp1 = exp1 op exp2;

These are summarized in Table 10. The examples assume that x and y are integer variables.
Table 10 Compound Assignment operators.
Operator

Example

Equivalent To

x = y

+=

x += y

x = x + y

-=

x -= y

x = x - y

*=

x *= y

x = x * y

/=

x /= y

x = x / y

%=

x %= y

x = x % y

&=

x &= y

x = x & y

|=

x |= y

x = x | y

^=

x ^= y

x = x ^ y

<<=

x <<= y

x = x << y

>>=

x >>= y

x = x >> y

Note:
An assignment operation is itself an expression whose value is the value
stored in its left operand. An assignment operation can therefore be used as the right
operand of another assignment operation. Any number of assignments can be
concatenated in this fashion to form one expression. For example:
int x, y, z;
x = y = z = 99;

// means: x = (y = (z = 99));

This is equally applicable to other forms of assignment. For example:


x += y = z = 99;

// means: x = x + (y = z = 99);

Comma Operator
The comma is frequently used in C++ as a simple punctuation mark, serving to separate variable
declarations, function arguments, and so on. In certain situations, the comma acts as an operator
rather than just as a separator. You can form an expression by separating two subexpressions with
a comma. The result is as follows:


Both expressions are evaluated, with the left expression being evaluated first.

The entire expression evaluates to the value of the right expression.

For example:
int x, y, z;
int min = 100, max = 1000;
Delia Ungureanu - UNITBV

41

Operators and expressions


//...
x = (y++ , z++);

For example, the above statement assigns the value of b to x, then increments a, and then
increments b.

Parentheses Operator
Parentheses () are used for:


group expressions

isolate conditional expressions

indicate function calls and function parameters

For example:
long hours, minutes, seconds;
seconds = ( hours *60 + minutes ) *60;

For complex expressions, you might need to nest parentheses one within another. For example:
int a, b, c, d, e;
e = ((a+b)*(a-c))+d;

This expression is read from the inside out.


You might want to use parentheses in some expressions for the sake of clarity, even when they
aren't needed for modifying operator precedence. Parentheses must always be in pairs, or the
compiler generates an error message.
DO use parentheses to change the order of precedence.
DON'T nest too deeply, because the expression becomes hard to understand and
maintain.

Operator Precedence
The order in which operators are evaluated in an expression is significant and is determined by
precedence rules. These rules divide the C++ operators into a number of precedence levels (see
Table 11). Operators in higher levels take precedence over operators in lower levels. When an
expression is evaluated, operators with higher precedence are performed first.
Table 11 Operator precedence levels and order
Priority
(highest)

Operator

Order

1 () [] - . ::
2 !

Delia Ungureanu - UNITBV

Left to Right
++

--

&

(typecast) Right to Left


42

Operators and expressions

Priority

Operator
sizeof new delete

Order

3 .*

->*

Left to Right

4 *

/ %

Left to Right

5 + 6 <<

Left to Right
>>

Left to Right

7 < <= >

>=

Left to Right

8 = = !=

Left to Right

9 &

Left to Right

10 ^

Left to Right

11 |

Left to Right

12 &&

Left to Right

13 ||

Left to Right

14 ?: (conditional operator)

Right to Left

15 = *= /= %=
<<= >>=
(lowerest) 16 , (comma)

+= -=

&=

^= |= Right to Left
Left to Right

For example, in
a == b + c * d

c * d is evaluated first because * has a higher precedence than + and ==. The result is then added
to b because + has a higher precedence than ==, and then == is evaluated. Precedence rules can
be overridden using brackets. For example, rewriting the above expression as
a == (b + c) * d

causes + to be evaluated before *.


Operators with the same precedence level are evaluated in the order specified by the last column
of Table 11. For example, in
a = b += c

the evaluation order is right to left, so first b += c is evaluated, followed by a = b.

Type Conversion
A value in any of the built-in types we have see so far can be converted (type-cast) to any of the
other types. For example:
(int) 3.14
Delia Ungureanu - UNITBV

// converts 3.14 to an int to give 3

43

Operators and expressions


(long) 3.14

// converts 3.14 to a long to give 3L

(double) 2

// converts 2 to a double to give 2.0

(char) 122

// converts 122 to a char whose code is 122

(unsigned short) 3.14

// gives 3 as an unsigned short

As shown by these examples, the built-in type identifiers can be used as type operators. Type
operators are unary (i.e., take one operand) and appear inside brackets to the left of their operand.
This is called explicit type conversion. When the type name is just one word, an alternate
notation may be used in which the brackets appear around the operand:
int(3.14)

// same as: (int) 3.14

In some cases, C++ also performs implicit type conversion. This happens when values of
different types are mixed in an expression. For example:
double

d = 1;

// d receives 1.0

int

i = 10.5;

// i receives 10

i = i + d;

// means: i = int(double(i) + d)

In the last example, i + d involves mismatching types, so i is first converted to double (promoted)
and then added to d. The result is a double which does not match the type of i on the left side of
the assignment, so it is converted to int (demoted) before being assigned to i.
The above rules represent some simple but common cases for type conversion. More complex
cases will be examined later in other chapters.

Delia Ungureanu - UNITBV

44

Sta tements

At its heart, a program is a set of commands executed in sequence. The power in a program
comes from its capability to execute one or another set of commands, based on whether a
particular condition is true or false. This chapter introduces the various forms of C++ statements
for composing programs, so you will learn about


Expressions

Composed instructions

Decision instructions

Loop instructions

A statement is a complete direction instructing the computer to carry out some task. Statements
represent the lowest-level building blocks of a program. Each statement represents a
computational step which has a certain side-effect. (A side-effect can be thought of as a change
in the program state, such as the value of a variable changing because of an assignment.)
Statements enable the program to serve a specific purpose (e.g., sort a list of names).
In C++, statements are usually written one per line, although some statements span multiple lines.
C++ statements always end with a semicolon (except for preprocessor directives such as #define
and #include).
Like many other procedural languages, C++ provides different forms of statements for different
purposes. Declaration statements are used for defining variables. Assignment-like statements are
used for simple, arithmetical computations. Branching statements are used for specifying
alternate paths of execution, depending on the outcome of a logical condition. Loop statements
are used for specifying computations which need to be repeated until a certain logical condition is
satisfied. Flow control statements are used to divert the execution path to another part of the
program. We will discuss these in turn.
For example,
int a, b=5;

// is a declaration statement witch defines variables


// a and b; b is initialized with 5

a=b+12 ;

// is an assignment statement; it instructs the


// computer to add value of variable b and 12 and to
// assign the result to the variable a

++a;

// this has a side-effect

a + 5;

// useless statement!

The last example represents a useless statement, because it has no side-effect (a is added to 5 and
the result is just discarded).

Delia Ungureanu - UNITBV

45

Statements

Statements and White Space


Whitespace (tabs, spaces, and newlines) is generally ignored in statements. The assignment
statement previously discussed could be written as
a=b+12 ;

or as
a = b + 12 ;

or as
a =
b +
12;

Although this last variation is perfectly legal but is not recommended. Whitespace can be used to
make your programs more readable and easier to maintain.
Whitespace characters (spaces, tabs, and newlines) cannot be seen. If these characters
are printed, you see only the white of the paper.
DO use whitespace judiciously to make your code clearer.

Null Statements
The simplest statement is the null statement which consists of just a semicolon:
;

// null statement

Although the null statement has no side-effect, we will see that it is necessary sometimes.

Compound Statements
A compound statement, also called a block, is a group of two or more C++ statements enclosed in
braces. Here's an example of a block:
{
cout << HELLO WORLD !;
cout << \n;
cout << HELLO WORLD, AGAIN !;
}

In C++, a block can be used anywhere a single statement can be used. The enclosing braces can
be positioned in different ways but it's a good idea to place braces on their own lines, making the
beginning and end of blocks clearly visible. Placing braces on their own lines also makes it easier
to see whether you've left one out.
Delia Ungureanu - UNITBV

46

Statements
DO put block braces on their own lines. This makes the code easier to read.
DO line up block braces so that it's easy to find the beginning and end of a block.
DON'T spread a single statement across multiple lines if there's no need to do so.
Limit statements to one line if possible.
Compound statements are useful in two ways:


they allow us to put multiple statements in places where otherwise only single statements
are allowed

they allow us to introduce a new scope in the program


A scope is a part of the program text within which a variable remains defined.

Listing 12 Using compound statements


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/* using compound statements */


#include <iostream.h>
int main(void)
{
int a, b;
a = 2;
b = 5;
cout << "a = " << a <<endl;
cout << "b = " << b <<endl;
{
int c ;
c = a * b;
cout << "c = " << c <<endl;
}
cout << "c = " << c <<endl;
return 0;
}

Comments:
For example, the scope of a and b is whole main() function. The scope of c is from
where they are defined till the closing brace of the compound statement. Outside the
compound statement, these variables are not defined, so the line 16 will produces an
error message like Undefined symbol 'c' in function main(). Blocks and scope rules
will be described in more detail when we discuss functions in the next chapter.

Delia Ungureanu - UNITBV

47

Statements

The if Statement
Relational operators are used mainly to construct the relational expressions used in if (conditional
statement) and repetitive statements (such while, do..while, for), covered in detail below in this
chapter.
You might be wondering what a program control statement is. Statements in a C program
normally execute from top to bottom, in the same order as they appear in your source code file. A
program control statement modifies the order of statement execution. Program control statements
can cause other program statements to execute multiple times or to not execute at all, depending
on the circumstances.
The if statement is one of C++'s program control statements.
The form of an if statement is as follows:
if (expression)
statement;

If expression evaluates to true, statement is executed. If expression evaluates to false, statement is


not executed. In either case, execution then passes to whatever code follows the if statement. You
could say that execution of statement depends on the result of expression. Note that both the line
if (expression) and the line statement; are considered to comprise the complete if statement; they
are not separate statements.
An if statement can control the execution of multiple statements through the use of a compound
statement, or block. Therefore, you could write an if statement as follows:
if (expression)
{
statement1;
statement2;
/* additional code goes here */
statementn;
}

DO indent statements within a block to make them easier to read. This includes the
statements within a block in an if statement.
DON'T make the mistake of putting a semicolon at the end of an if statement. An if
statement should end with the conditional statement that follows it.
In the following, statement1 executes whether or not x equals 2, because each line is evaluated as
a separate statement, not together as intended:
if( x == 2);

/* semicolon does not belong! */

statement1;

Delia Ungureanu - UNITBV

48

Statements
Listing 13 Using if statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/* Demonstrates the use of if statements */


#include <iostream.h>
int main(void)
{
int x, y;
/* Input the two values to be tested */
cout << "\nInput an integer value for x: ";
cin >> x;
cout << "\nInput an integer value for y: ";
cin >> y;
/* Test values and print result */
if (x == y)
cout << "x is equal to y\n";
if (x > y)
cout << "x is greater than y\n";
if (x < y)
cout << "x is smaller than y\n";
return 0;
}

Comments:
Listing 13 shows three if statements in action (lines 13 through 18).
Line 6 declares two variables, x and y, and lines 9 through 11 prompt the user for
values to be placed into these variables. Lines 13 through 18 use if statements to
determine whether x is greater than, less than, or equal to y.
Line 13 uses an if statement to see whether x is equal to y. Remember that ==, the
equal operator, means "is equal to" and should not be confused with =, the
assignment operator. After the program checks to see whether the variables are equal,
in line 15 it checks to see whether x is greater than y, followed by a check in line 17
to see whether x is less than y.
Note: You will notice that the statements within an if clause are indented. This is a
common practice to aid readability.

The else Clause


A variant form of the if statement allows us to specify two alternative statements: one which is
executed if a condition is satisfied and one which is executed if the condition is not satisfied. This
is called the if-else statement and has the general form:
if (expression)
Delia Ungureanu - UNITBV

49

Statements
statement1;
else

statement2;

If expression evaluates to true, statement1 is executed. If expression evaluates to false,


statement2 is executed. Both statement1 and statement2 can be compound statements or blocks.
Listing 14 Using if else statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/* Demonstrates the use of if else statements */


#include <iostream.h>
int main(void)
{
int x, y;
/* Input the two values to be tested */
cout << "\nInput an integer value for x: ";
cin >> x;
cout << "\nInput an integer value for y: ";
cin >> y;
/* Test values and print result */
if (x == y)
cout << "x is equal to y\n";
else
if (x > y)
cout << "x is greater than y\n";
else
cout << "x is smaller than y\n";
return 0;
}

Comments:
Lines 13 through 19 are slightly different from the previous listing (Listing 14). Line
13 still checks to see whether x equals y. If x does equal y, x is equal to y appears onscreen, just as in Listing 14. However, the program then ends, and lines 16 through 19
aren't executed. Line 16 is executed only if x is not equal to y , or, to be more
accurate, if the expression "x equals y" is false. If x does not equal y, line 16 checks
to see whether x is greater than y. If so, line 17 prints x is greater than y; otherwise
(else), line 19 is executed.
Listing 14 uses a nested if statement. Nesting means to place (nest) one or more C++ statements
inside another C++ statement. In the case of Listing 14, an if statement is part of the first if
statement's else clause.
A frequently-used form of nested if statements involves the else part consisting of another if-else
statement. For example:
Delia Ungureanu - UNITBV

50

Statements
Listing 15 Using nested if else statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

/* Demonstrates the use of nested if-else statements */


#include <iostream.h>
int main(void)
{
char ch;
cout << "Input a character: ";
cin >> ch;
if (ch >= '0' && ch <= '9')
cout << "The character is a digit";
else
if (ch >= 'A' && ch <= 'Z')
cout << "The character is an upper letter";
else
if (ch >= 'a' && ch <= 'z')
cout << "The character is a lower letter";
else
cout << "The character is a special character";
return 0;
}

Comments:
Listing 15 demonstrates the use of nested if else statements. Line 8 read a character
to be placed into ch variable. On lines 9 to 18 is checked if ch is a digit, an upper
letter, a lower letter or is a special character.
The conditionals expressions used are complexes; they include relational and logical
operators.

The switch Statement


The switch statement provides a way of choosing between a set of alternatives, based on the
value of an expression. The general form of the switch statement is:
switch (expression)
{

case constant1:

statements;
...
case constantn:

statements;
Delia Ungureanu - UNITBV

51

Statements
default:

statements;
}

First expression (called the switch tag) is evaluated, and the outcome is compared to each of the
numeric constants (called case labels), in the order they appear, until a match is found. The
statements following the matching case are then executed. Note the plural: each case may be
followed by zero or more statements (not just one statement). Execution continues until either a
break statement is encountered or all intervening statements until the end of the switch statement
are executed. The final default case is optional and is exercised if none of the earlier cases
provide a match.
For example, suppose we have parsed a binary arithmetic operation into its three components and
stored these in variables x, y, and op. The following switch statement performs the operation and
stored the result in result.
Listing 16 Using switch statments
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

/* Demonstrates the use switch statement */


#include <iostream.h>
int main(void)
{
float x, y, result;
char op;
cout << "Input two reals: ";
cin >> x >> y;
cout << "Specify the arithmetic operation (+, -, * or x, /):";
cin >> op;
switch (op) {
case '+': result = x + y;
break;
case '-': result = x - y;
break;
case 'x':
case '*': result = x * y;
break;
case '/': result = x / y;
break;
default: cout << "unknown operator: " << op << '\n';
}
cout << "The result of " << op << " operation is: " << result;
return 0;
}

Delia Ungureanu - UNITBV

52

Statements
Comments:
As illustrated by Listing 16, it is usually necessary to include a break statement at the
end of each case. The break terminates the switch statement by jumping to the very
end of it. There are, however, situations in which it makes sense to have a case
without a break. For example, we * or x to be used as a multiplication operator, so in
line 17 isnt necessary break. Because case 'x' has no break statement (in fact no
statement at all!), when this case is satisfied, execution proceeds to the statements of
the next case and the multiplication is performed.
It should be obvious that any switch statement can also be written as multiple if-else
statements.
The above statement, for example, may be written as:
if (op == '+')
result = x + y;
else if (op == '-')
result = x - y;
else if (op == 'x' || op == '*')
result = x * y;
else if (op == '/')
result = x / y;
else
cout << "unknown operator: " << op << '\n';

In general, preference should be given to the switch version when possible. The if-else approach
should be reserved for situation where a switch cannot do the job (e.g., when the conditions
involved are not simple equality expressions, or when the case labels are not numeric constants).
Unlike embedded if-else logic, the switch statement doesn't need a lot of fancy indentation that
causes code to move closer to the right margin as the statement gets longer.
DO use the switch statement to code multiple-choice logic. You will improve your
program's clarity and make future maintenance much easier.

Controlling Program Execution


The default order of execution in a C++ program is top-down. Execution starts at the beginning
of the main() function and progresses, statement by statement, until the end of main() is reached.
However, this order is rarely encountered in real C++ programs. The C++ language includes a
variety of program control statements that let you control the order of program execution.

Delia Ungureanu - UNITBV

53

Statements

The for Statement


The for statement is a C++ programming construct that executes a block of one or more
statements a certain number of times. It is sometimes called the for loop because program
execution typically loops through the statement more than once. A for statement has the
following structure:
for ( initial; condition; increment )
statement;

initial, condition, and increment are all C++ expressions, and statement is a single or compound
C++ statement. When a for statement is encountered during program execution, the following
events occur:
1. The expression initial is evaluated. initial is usually an assignment statement that sets a
variable to a particular value.
2. The expression condition is evaluated. condition is typically a relational expression.
3. If condition evaluates to false (that is, as zero), the for statement terminates, and
execution passes to the first statement following statement.
4. If condition evaluates to true (that is, as nonzero), the C statement(s) in statement are
executed.
5. The expression increment is evaluated, and execution returns to step 2.
Note:
Note that statement never executes if condition is false the first time it's
evaluated.
Listing 17 uses a for statement to print the numbers 1 through 20.
Listing 17 Using for loop statements
1
2
3
4
5
6
7
8
9
10
11
12

/* Demonstrates the use for loop statement */


#include <iostream.h>
int main(void)
{
int count;
/* Print the numbers 1 through 20 */
for (count = 1; count <= 20; count++)
cout << count << endl;
return 0;
}

Comments:
Line 5 declares a type int variable, named count, that will be used in the for loop.
Lines 9 and 10 are the for loop. When the for statement is reached, the initial
Delia Ungureanu - UNITBV

54

Statements
statement is executed first. In this listing, the initial statement is count = 1. This
initializes count so that it can be used by the rest of the loop. The second step in
executing this for statement is the evaluation of the condition count <= 20. Because
count was just initialized to 1, you know that it is less than 20, so the statement in the
for command, the cout<<, is executed. After executing the printing function, the
increment expression, count++, is evaluated. This adds 1 to count, making it 2. Now
the program loops back and checks the condition again. If it is true, the cout <<
reexecutes, the increment adds to count (making it 3), and the condition is checked.
This loop continues until the condition evaluates to false, at which point the program
exits the loop and continues to the next line (line 11), which returns 0 before ending
the program.
The for statement is frequently used, as in the previous example, to "count up," incrementing a
counter from one value to another. You also can use it to "count down," decrementing (rather
than incrementing) the counter variable.
for (count = 100; count > 0; count--)

You can also "count by" a value other than 1, as in this example:
for (count = 0; count < 1000; count += 5)

The for statement is quite flexible. For example, you can omit the initialization expression if the
test variable has been initialized previously in your program. (You still must use the semicolon
separator as shown, however.)
count = 1;
for ( ; count < 1000; count++)

The initialization expression doesn't need to be an actual initialization; it can be any valid C++
expression. Whatever it is, it is executed once when the for statement is first reached. For
example, the following prints the statement Now begin for...:
count = 1;
for (cout<<Now begin for ; count < 1000; count++)

You can also omit the increment expression, performing the updating in the body of the for
statement. Again, the semicolon must be included. To print the numbers from 0 to 99, for
example, you could write
for (count = 0; count < 100; )
cout << count++;

The test expression that terminates the loop can be any C++ expression. As long as it evaluates to
true (nonzero), the for statement continues to execute. You can use C++'s logical operators to
construct complex test expressions. For example, the following for statement prints only lower
letters:
char ch;
cin >> ch;
for (; ch >=a && ch <=z; ch++)
cout << ch << endl;
Delia Ungureanu - UNITBV

55

Statements
Comma operator is most often used in for statements. You can create an expression by separating
two subexpressions with the comma operator. The two subexpressions are evaluated (in left-toright order). By using the comma operator, you can make each part of a for statement perform
multiple duties.
for (i = 0, j = 100; i < j; i++, j--)
cout << i << \t << j << \n;

The comma operator is used to initialize two variables, i and j. It is also used to increment part of
these two variables with each loop.

Nesting for Statements


A for statement can be executed within another for statement. This is called nesting. Listing 18
illustrates the nesting of two for statements.
Listing 18 Nesting for statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/* Demonstrates nesting for statements */


#include <iostream.h>
int main(void)
{
int rows, cols, i, j;
cout << "Input number of rows:";
cin >> rows;
cout << "Input number of cols:";
cin >> cols;
for ( i = rows; i > 0 ; i--)
{
for( j = cols; j >0 ; j--)
cout <<"*";
cout << '\n';
}
return 0;
}

Comments:
When you run this program, if you read 5 for number of rows and 10 for number of
columns, * is printed on-screen by 50 times, forming a 5*10 rectangle. The program
has only one command to print an *, but it is nested in two loops.
Line 11 starts the first for loop. Looking at the condition, you see that this for loop is
executed until the i is 0. On first executing line 17, i is 5; therefore, the program
continues to line 13.
Line 13 contains the second for statement. The value of j is 10 initially (the value
Delia Ungureanu - UNITBV

56

Statements
passed via cols). Because j is greater than 0, line 14 is executed, printing an *. j is
then decremented, and the loop continues. When j is 0, the for loop ends, and control
goes to line 22. Line 15 causes the on-screen printing to start on a new line. After
moving to a new line on the screen, control reaches the end of the first for loop's
statements, thus executing the increment expression, which subtracts 1 from i,
making it 4. This puts control back at line 13 and actions are repeated until i become
0.

The while Statement


The while statement, also called the while loop, executes a block of statements as long as a
specified condition is true. The while statement has the following form:
while (condition)

statement;

condition is any C++ expression, and statement (called the loop body) is a single or compound
C++ statement. When program execution reaches a while statement, the following events occur:
1. The expression condition is evaluated.
2. If condition evaluates to false (that is, zero), the while statement terminates, and
execution passes to the first statement following statement.
3. If condition evaluates to true (that is, nonzero), the C statement(s) in statement are
executed.
4. Execution returns to step 1.
Listing 19 is a simple program that uses a while statement to print the numbers 1 through 20.
(This is the same task that is performed by a for statement in Listing 17)
Listing 19 A simple while statement.
1
2
3
4
5
6
7
8
9
10
11
12
13

int main(void)
{
int count;
/* Print the numbers 1 through 20 */
count = 1;
while(count <= 20)
{
cout << count << endl;
count++;
}
return 0;
}

Comments:
Examine Listing 19 and compare it with Listing 17, which uses a for statement to
Delia Ungureanu - UNITBV

57

Statements
perform the same task. In line 6, count is initialized to 1. Because the while statement
doesn't contain an initialization section, you must take care of initializing any
variables before starting the while. Line 7 is the actual while statement, and it
contains the same condition statement from Listing 17, count <= 20. In the while
loop, line 10 takes care of incrementing count. If you forgot to put line 10 in this
program, your program wouldn't know when to stop, because count would always be
1, which is always less than 20.
A while statement is essentially a for statement without the initialization and increment
components. Thus,
for ( ; condition ; )

is equivalent to
while (condition)

Note:
Anything that can be done with a for statement can also be done with a
while statement. When you use a while statement, any necessary initialization must
first be performed in a separate statement, and the updating must be performed by a
statement that is part of the while loop.

The do...while Loop


The do...while loop executes a block of statements as long as a specified condition is true. The
do...while loop tests the condition at the end of the loop rather than at the beginning, as is done by
the for loop and the while loop.
The structure of the do...while loop is as follows:
do

statement
while (condition);

condition is any C expression, and statement is a single or compound C statement. When program
execution reaches a do...while statement, the following events occur:
1. The statements in statement are executed.
2. condition is evaluated. If it's true, execution returns to step 1. If it's false, the loop
terminates.

Listing 20 is the same simple program that print the numbers 1 through 20, but it use do..while
statement instead while.
Delia Ungureanu - UNITBV

58

Statements

Listing 20 A simple dowhile statement.


1
2
3
4
5
6
7
8
9
10
11
12
13
14

int main(void)
{
int count;
/* Print the numbers 1 through 20 */
count = 1;
do
{
cout << count << endl;
count++;
}
while(count <= 20);
return 0;
}

Comments:
While statement was changed with do..while. The same condition is evaluated, but at
the end, on line 12.
The statements associated with a do...while loop are always executed at least once. This is
because the test condition is evaluated at the end, instead of the beginning, of the loop. In
contrast, for loops and while loops evaluate the test condition at the start of the loop, so the
associated statements are not executed at all if the test condition is initially false.
The do...while loop is used less frequently than while and for loops. It is most appropriate when
the statement(s) associated with the loop must be executed at least once. You could, of course,
accomplish the same thing with a while loop by making sure that the test condition is true when
execution first reaches the loop. A do...while loop probably would be more straightforward,
however.
The do loop is less frequently used than the while loop. It is useful for situations where we need
the loop body to be executed at least once, regardless of the loop condition. For example, suppose
we wish to read a value non zero to calculate a division. This can be expressed as the following
loop:
float a, b;
cin >> a;
do {
cin >> b;
} while (b == 0);
Delia Ungureanu - UNITBV

59

Statements
cout << a/b;

The continue Statement


The continue statement terminates the current iteration of a loop and instead jumps to the next
iteration. It applies to the loop immediately enclosing the continue statement. It is an error to use
the continue statement outside a loop.
In while and do loops, the next iteration commences from the loop condition. In a for loop, the
next iteration commences from the loops third expression. For example, a loop which repeatedly
reads in a number, processes it but ignores negative numbers, and terminates when the number is
zero, may be expressed as:
do {
cin >> num;
if (num < 0) continue;
// process num here...
} while (num != 0);

This is equivalent to:


do {
cin >> num;
if (num >= 0)

{
// process num here...
}

} while (num != 0);

When the continue statement appears inside nested loops, it applies to the loop immediately
enclosing it, and not to the outer loops. For example, in the following set of nested loops, the
continue applies to the for loop, and not the while loop:
while (more) {
for (i = 0; i < n; ++i) {
cin >> num;
if (num < 0) continue;

// causes a jump to: ++i

// process num here...


}
//etc...
}

The break Statement


A break statement may appear inside a loop (while, do, or for) or a switch statement. It causes a
jump out of these constructs, and hence terminates them. Like the continue statement, a break
statement only applies to the loop or switch immediately enclosing it. It is an error to use the
break statement outside a loop or a switch.
Delia Ungureanu - UNITBV

60

Statements
For example, suppose we wish to read in a user password, but would like to allow the user a
limited number of attempts:
for (i = 0; i < attempts; ++i) {
cout << "Please enter your password: ";
cin >> password;
if (Verify(password))
break;

// check password for correctness


// drop out of the loop

cout << "Incorrect!\n";


}

Here we have assumed that there is a function called Verify which checks a password and
returns true if it is correct and false otherwise.
Rewriting the loop without a break statement is always possible by using an additional logical
variable ( verified) and adding it to the loop condition:
verified = 0;
for (i = 0; i < attempts && !verified; ++i) {
cout << "Please enter your password: ";
cin >> password;
verified = Verify(password));
if (!verified)
cout << "Incorrect!\n";
}

The return Statement


The return statement enables a function to return a value to its caller. It has the general form:
return expression ;

where expression denotes the value returned by the function. The type of this value should match
the return type of the function. For a function whose return type is void, expression should be
empty:
return;

The only function we have discussed so far is main, whose return type is always int. The return
value of main is what the program returns to the operating system when it completes its
execution. Under UNIX, for example, it its conventional to return 0 from main when the program
executes without errors. Otherwise, a non-zero error code is returned.
When a function has a non-void return value (as in the above example), failing to return a value
will result in a compiler warning. The actual return value will be undefined in this case (i.e., it
will be whatever value which happens to be in its corresponding memory location at the time).
Delia Ungureanu - UNITBV

61

Po inters

One of the most powerful tools available to a C++ programmer is the ability to manipulate
computer memory directly by using pointers.
When you declare a variable in a C++ program, the compiler sets aside a memory location with a
unique address to store that variable (see Figure 3). The compiler associates that address with the
variable's name. When your program uses the variable name, it automatically accesses the proper
memory location. The location's address is used, but it is hidden from you, and you need not be
concerned with it. If you want this information, though, you can use the address of operator (&),
which is illustrated in Listing 21.
Listing 21 Using address operator.
1
2
3
4
5
6
7
8
9
10
11

/* Demonstrates the use of operator & (address) */


#include <iostream.h>
int main(void)
{
float var = 3.5;
cout <<"Value of variable var is: " << var <<endl;
cout <<"Variable var occupies " << sizeof(var)<<" bytes in memory"<< endl;
cout <<"Variable var is allocated in memory at "<< &var <<" address"<<endl;
return 0;
}

Comments:
This listing is an example to obtain information about a variable.
On line 6 variable var is declared with initialisation.
The type specified (i.e., float) determines the number of bytes allocated for var. It can
be obtained using sizeof operator (see line 8).
To determine the address where var is allocated in memory you can use & operator.
Line 9 will print memory address of var in hexadecimal format.
The type and the address of variable both cant be change during the program.
Output of Listing 21 is Dialog 10. The address reported for var might be another on your system.

Delia Ungureanu - UNITBV

62

Pointers
Dialog 10
Value of variable var is: 3.5
Variable var occupies 4 bytes in memory
Variable var is allocated in memory at 0x37e7245dc address

One of the most powerful tools available to a C++ programmer is the ability to manipulate
computer memory directly by using pointers.
A pointer is a variable that holds a memory address.
A pointer declaration takes the following form:
typename *ptrname;

typename is any of C++'s variable types.


The asterisk (*) is the indirection (or dereference) operator, and it indicates that ptrname is a
pointer.
The pointer ptrname to type typename and not a variable of type typename.
typename indicates the type of the variable that the pointer points to.
Values assigned to ptrname are address of variables of type typename.
You can declare variables pointer like:
int * ptr1;

// pointer to an int

char * ptr2;

// pointer to a char

float * ptr3

// pointer to a float

If given the definition


int var1= 7;

we can write:
ptr1 = &var1;

The expression
*ptr1

dereferences ptr1 to get to what it points to, and is equivalent to var1. The expression returns
the contents of the location to which ptr1 points (i.e., value 7, see
Figure 5).
Figure 5 Example for pointer variable.

Delia Ungureanu - UNITBV

63

Pointers

Listing 22 Using variable pointer.


1
2
3
4
5
6
7
8
9
10
11
12

/* using pointer */
#include <iostream.h>
int main(void)
{
int var1 = 7;
int * ptr1;
ptr1 = &var1;
cout << "Value of variable ptr1 is: " << ptr1 <<endl;
cout << "Variable ptr1 point to " << *ptr1 << " value"<< endl;
return 0;
}

Comments:
In this listing, two variables are declared. In line 6, var1 is declared as an int and
initialized to 7.
In line 7 is declared a pointer to a variable of type int. The name of pointer is ptr1.
In line 8, the pointer ptr1 is assigned the address of var1 using the address-of operator
(&).
Line 9 prints the value of ptr1.
Line 10 prints the value stored in the location pointed to by ptr1.
Dialog 11
Value of variable ptr1 is: 0x29072256
Variable ptr1 point to 7 value

Listing 22 prints on the screen Dialog 11 (it might be different on your system).
A pointer may be assigned the value 0 (called the NULL pointer). The null pointer doesnt point
to any address. The NULL pointer is used for initializing pointers.
DON'T use an uninitialized pointer. Results can be disastrous if you do.
In general, the type of a pointer must be matching the type of the data it is set to point to.
A pointer of type void*, however, will match any type. This is useful for defining pointers which
may point to data of different types, or whose type is originally unknown.
This example is legal:
Delia Ungureanu - UNITBV

64

Pointers
int var1;
float var2;
void * pvar;
pvar = &var1;
//...
pvar = &var2;

A pointer may be converted to another type using typecast operator. For example,
ptr2 = (char*) ptr1;

Pointers and Symbolic Constants


Using keyword const with pointers, two aspects need to be considered: the pointer itself, and the
object pointed to, either of which or both can be constant:
const char *str1 = "pointer to constant";
char *const str2 = "constant pointer";
const char *const str3 = "constant pointer to constant";
str1[0] = 'P';

// illegal!
illegal

str1 = "ptr to const";

// ok

str2 = "const ptr";

// illegal!
illegal

str2[0] = 'P';

// ok

str3 = "const to const ptr";

// illegal!
illegal

str3[0] = 'C';

// illegal!
illegal

Pointer Arithmetic
In C++ one can add an integer quantity to or subtract an integer quantity from a pointer. This is
frequently used by programmers and is called pointer arithmetic. Pointer arithmetic is not the
same as integer arithmetic, because the outcome depends on the size of the object pointed to. For
example, see Listing 23.
Listing 23 Example of pointer arithmetic.

Delia Ungureanu - UNITBV

65

Pointers
1
2
3
4
5
6
7
8
9
10
11
12

/* pointer arithmetic*/
#include <iostream.h>
int var1 = 7, var2=100;
int main(void)
{
int * ptr;
ptr = &var1;
cout << "ptr point to " << *ptr << endl;
cout << "ptr+1 point to " << *(ptr+1) << endl;
return 0;
}

Comments:
ptr points to var1, ptr+1 advances by one int (i.e., two bytes) so that it points to the
second variable, var2. This situation is illustrated in Figure 6.
Figure 6 Ilustration of pointer arithmetic.

Listing 24
ptr point to 7
ptr +1 point to 100

The expression
ptr + 4 ;

increase the value of ptr by 8, that is 4 * sizeof(int);


When you increment a pointer, you are increasing its value:
ptr++;

This increases the value of ptr with two.


Similar is :
ptr_to_int += 4;

that increases the value stored in ptr by 8.


The same concepts that apply to incrementing pointers hold true for decrementing pointers.
Decrementing a pointer is actually a special case of incrementing by adding a negative value. you
decrement a pointer with the -- or -= operators.
Delia Ungureanu - UNITBV

66

Pointers
For example,
ptr--;
ptr-=2;

Other pointer arithmetic operation is called differencing, which refers to subtracting two pointers.
If you have two pointers of the same type, you can subtract them and find out how far apart they
are.
ptr1 - ptr2;

Pointer comparisons are valid only between pointers that point to the same array. Under these
circumstances, the relational operators ==, !=, >, <, >=, and <= work properly. Thus, if ptr1 and
ptr2 point to elements of the same array, the comparison
ptr1 < ptr2

Many arithmetic operations that can be performed with regular variables, such as multiplication
and division, don't make sense with pointers. The C++ compiler doesn't allow them. For example,
if ptr is a pointer, the statement
ptr *= 2;

generates an error message.

Consequences of use of uninitialized pointers


We assume the declaration:
int * ptr;

This pointer isn't yet initialized, so it doesn't point to anything known. An uninitialized pointer
has some value; you just don't know what it is. In many cases, it is zero. If you use an
uninitialized pointer in an assignment statement, this is what happens:
*ptr = 100;

The value 100 is assigned to whatever address ptr points to. That address can be anywhere in
memory: where the operating system is stored, where is the program's code, etc. The 100 might
overwrite some important information, and the result can be disastrous, even it might produce the
system crash.

Delia Ungureanu - UNITBV

67

Arrays
An array consists of a set of objects (called its elements), all of which are of the same type and
are arranged contiguously in memory. In general, only the array itself has a symbolic name, not
its elements. Each element is identified by an index which denotes the position of the element in
the array. The number of elements in an array is called its dimension. The dimension of an array
is fixed and predetermined; it cannot be changed during program execution.
Arrays are suitable for representing composite data which consist of many similar, individual
items. Some examples: a list of names, a series of numbers, etc.
The name of an array is a pointer, it contain the address of memory where the array is allocated.
It cant be modified, is a constant pointer.

Single-Dimensional Arrays
A single-dimensional array has only a single subscript. A subscript is a number in brackets that
follows an array's name. This number can identify the number of individual elements in the array.
Declaration of a single-dimensional array is:
type_el array_name [dim];

where array_name is the name of array that contains dim elements, each element type is type_el.
For example,
float temperatures[24];

The array is named temperatures, and it contains 24 elements. Each of the 24 elements is the
equivalent of a single float variable.
Note:

All of C++'s data types can be used for arrays.

Note:

C++ array elements are always numbered starting at 0.

So the 24 elements of temperatures are numbered 0 through 23.


Note:

Array elements are stored in sequential memory locations.

Individual elements of the array are accessed by using the array name followed by the element
subscript enclosed in square brackets. For example, the following statements store the value 3.5
in the first array element, 5.7 in the second array element and in the third holds the average sum
of the first and the second elements of array.
temperatures[0]=3.5;
temperatures[1]=5.7;
temperatures[2]=(temperatures[0]+temperatures[1])/2;

Delia Ungureanu - UNITBV

68

Arrays
You also can initialize the array at the same time you define it:
int nums[6]={3, 5, -7, 15, 99, 43};

Figure 7 shows how the integer array looks in memory


Figure 7 Memory allocation for a single-dimensional array.

Listing 25
1
2
3
4
5
6
7
8
9
10
11
12
13

/* working with single-dimensional array*/


#include <iostream.h>
int main(void)
{
int nums[8]={5, 7, -27, 22, -14, 72, 65, 99};
float average=0;
for (int i=0; i<8; i++)
average += nums[i];
average /= 8;
cout << "Average sum of the 8 integers is: " << average << endl;
return 0;
}

Comments:
On 6 line array named nums is defined with initialisation.
On 7 line variable average is declared and it is initialised with 0. It is used to calculate
average sum of the 8 array elements.
To get every element of the array we use a for loop. Variable i is declared and is used
as array index.
In C++, characters array are used to create strings.
char name[] = Smith;

defines name to be an array of six characters: five letters and a null character. The terminating
Delia Ungureanu - UNITBV

69

Arrays
null character is inserted by the compiler.
Figure 8 Memory allocation for a string.

The elements of "SMITH" can be referred to as *name, *(name + 1), *(name + 2), etc.
Pointer arithmetic is very handy when processing the elements of an array. Listing 26 shows a
string copying function similar to strcpy.
Listing 26
1
2
3
4
5

void CopyString (char *dest, char *src)


{
while (*dest++ = *src++)
;
}

Comments:
The condition of this loop assigns the contents of src to the contents of dest and then
increments both pointers. This condition becomes 0 when the final null character of
src is copied to dest.

Multi-Dimensional Arrays
A multidimensional array has more than one subscript. A two-dimensional array has two
subscripts, a three-dimensional array has three subscripts, and so on. There is no limit to the
number of dimensions a C++ array can have.
For example,
int matrix[3][4] = { {

10, 20, 30, 40},

50, 60, 70, 80},

90, 100, 110, 120}};

matrix is a two-dimensional array. It has three rows and four columns.

Delia Ungureanu - UNITBV

70

Arrays
Figure 9 Organization of matrix in memory.

Multidimensional arrays are interpreted as arrays whose elements are of type array. matrix is an
array with 3 elements and every element is a four elements array.
matrix is the address of entire array, matrix[0] is the address of first row and matrix[0][0]
represents the value of first element on the first row.
Listing 27
1
2
3
4
5
6
7
8
9
10
11
12
13
14

/* working with multi-dimensional array*/


#include <iostream.h>
int main(void)
{
int matrix[3][4] = { {

10, 20, 30, 40},


{ 50, 60, 70, 80},
{ 90, 100, 110, 120}};

int row, col;


for (row =0; row < 3; row++)
for (col =0; col < 4; col++)
cout << "matrix["<<row<<"]["<<col<<"]="<<matrix[row][col]<<endl;
return 0;
}

Comments:
On line 6 is declared an tow-dimensional array with dimensions 3 x 4; its elements
are initialized.
To processing the array are used variables row and col and two nested for loops.
row gets successive values: 0, 1, 2 and col gets successive values: 0, 1, 2, 3.
Delia Ungureanu - UNITBV

71

Arrays
The result of running is the Dialog 12Dialog 12 printed on the screen.
Dialog 12
matrix[0][0]=10
matrix[0][1]=20
matrix[0][2]=30
matrix[0][3]=40
matrix[1][0]=50
matrix[1][1]=60
matrix[1][2]=70
matrix[1][3]=80
matrix[2][0]=90
matrix[2][1]=100
matrix[2][2]=110
matrix[2][3]=120

Delia Ungureanu - UNITBV

72

Dyna mic Memory


Each computer has a certain amount of memory (random access memory, or RAM) installed.
This amount varies from system to system. When you run a program, whether a word processor,
a graphics program, or a C++ program, the program is loaded from disk into the computer's
memory. The memory space the program occupies includes the program code as well as space for
all the program's static data, that is, data items that are declared in the source code. The memory
left over is called the heap. The heap is used for dynamically allocating memory blocks during
program execution. As a result, it is also called dynamic memory. Similarly, the program stack
is also called static memory.
Two operators are used for allocating and deallocating memory blocks on the heap.
You allocate memory on the free store in C++ by using the new operator. new is followed by the
type of the object that you want to allocate so that the compiler knows how much memory is
required. Therefore, new int allocates two bytes in the free store, and new long allocates four.
The return value from new is a memory address. It must be assigned to a pointer. To create a
double on the free store, you might write:
double * ptr;
ptr = new double;

You can use this like any other pointer to a variable and assign a value into that area of memory
by writing
*ptr = 12.345;

To allocate a block large enough for storing an array of 10 characters, you can write:
char *str = new char[10];

If new cannot create memory on the free store (memory is, after all, a limited resource) it returns
the null pointer. You must check your pointer for null each time you request new memory.
Note: Each time you allocate memory using the new keyword, you must check to
make sure the pointer is not null.
The delete operator is used for releasing memory blocks allocated by new. It takes a pointer as
argument and releases the memory block to which it points. For example:
delete ptr;

// delete an object

delete [] str;

// delete an array of objects

Note that when the block to be deleted is an array, an additional [] should be included to indicate
this.
Listing 28 Using dynamic memory.
1
2
3
4

/* using dynamic memory*/


#include <iostream.h>
#include <string.h>

Delia Ungureanu - UNITBV

73

Dynamic Memory
5
6
7
8
9
10
11
12
13
14

int main(void)
{
char *str1 = "learning about dynamic memory";
char *str2 = new char[strlen(str1) + 1];
strcpy(str2, str1);
cout << "contents of str2 is: " << str2;
delete []str2;
return 0;
}

Comments:

At line 3 is included the standard string header file which declares a variety of
functions for manipulating strings.
The strlen function (declared in string.h) counts the characters in its string
argument up to (but excluding) the final null character. Because the null character is
not included in the count, we add 1 to the total and allocate an array of characters of
that size.
The strcpy function (declared in string.h) copies its second argument to its first,
character by character, including the final null character.
str1 is a pointer that assigns address of constant string "learning about dynamic
memory".
str2 assigns the address of block allocated in heap using new operator. Dimension of
block depends on length of string allocated at str1 address, increased with one
because of string terminator (\0).
At line 12 is used delete operator to release the block allocated with new.
For every time in your program that you call new, there should be a call to delete. It
is important to keep track of which pointer owns an area of memory and to ensure that
the memory is returned to the free store when you are done with it.

Delia Ungureanu - UNITBV

74

References
A reference (&) is an alias for an object; when you create a reference, you initialize it with the
name of another object, the target. From that moment on, the reference acts as an alternative
name for the target, and anything you do to the reference is really done to the target.
A reference is like a constant pointer that is automatically dereferenced. It is usually used for
function argument lists and function return values. But you can also make a free-standing
reference. For example,
int x;
int& r = x;

defines r as a reference to x. After this definition x and r both refer to the same object, as if they
were the same variable. It should be emphasized that a reference does not create a copy of an
object, but merely a symbolic alias for it. Hence, after
x = 15;

both x and r will denote the value 15.


If you say
r++;

incrementing a is actually incrementing x.


A reference must always be initialized when it is defined: it should be an alias for something. It
would be illegal to define a reference and initialize it later.
double &num3;

// illegal: reference without initialization

num3 = num1;

You can also initialize a reference to a constant. In this case a copy of the constant is made (after
any necessary type conversion) and the reference is set to refer to the copy.
int &n = 1;

// n refers to a copy of 1

The reason that n becomes a reference to a copy of 1 rather than 1 itself is safety. Consider what
could happen if this were not the case.
int &x = 1;
++x;
int y = x + 1;

The most common use of references is for function parameters (we will be discussed in next
lecture).
Note: A reference must be initialized when it is created. (Pointers can be initialized at
any time.)
Note: Once a reference is initialized to an object, it cannot be changed to refer to
another object. (Pointers can be pointed to another object at any time.)
Note: You cannot have NULL references. You must always be able to assume that a
reference is connected to a legitimate piece of storage.
Delia Ungureanu - UNITBV

75

Functions

A function is, in effect, a subprogram that can act on data and return a value. Every C++ program
has at least one function, main(). When your program starts, main() is called automatically.
main() might call other functions, some of which might call still others.
A function is a named, independent section of C++ code that performs a specific task and
optionally returns a value to the calling program.
A function provides a convenient way of packaging a computational recipe, so that it can be used
as often as required.
A function definition consists of two aspects: prototype and proper definition.
The prototype specifies how it may be used. The function prototype is a statement, which means
it ends with a semicolon. It consists of the function's return type, name, and parameter list.
Entities of prototype:
The function name. This is simply a unique identifier.
 The function parameters. This is a set of zero or more typed identifiers used for
passing values to and from the function. The parameter list is a list of all the
parameters and their types, separated by commas.
 The function return type. This specifies the type of value the function returns. A
function which returns nothing should have the return type void.


Function prototype syntax is:


return_type function_name ( [type [parameterName]]...);

For example, Figure 10 illustrates the parts of the function prototype. This prototype declares a
function named area() that returns a long and that has two parameters, both integers.
Figure 10 Function prototype.

The prototype
long area(int, int);

is perfectly legal, but adding parameter names makes your prototype clearer. The same function
with named parameters might be
long area(int length, int width);

The proper definition of a function consists of the function header and its body.
Delia Ungureanu - UNITBV

76

Functions
The header is exactly like the function prototype, except that the parameters must be named, and
there is no terminating semicolon.
The body of the function contains the computational steps (statements) that comprise the
function. The statements are enclosed in braces.
Function definition syntax is:
return_type function_name ( [type parameterName]...)
{
statements;
}

All statements within the body of the function must be terminated with semicolons, but the
function itself is not ended with a semicolon; it ends with a closing brace.
If the function returns a value, it should end with a return statement, although return
statements can legally appear anywhere in the body of the function.
Every function has a return type. If one is not explicitly designated, the return type will be int.
Be sure to give every function an explicit return type.
If a function does not return a value, its return type will be void.
Function definition is illustrated in Figure 11.
Figure 11 Function definition.

Using a function involves calling it. A function call consists of the function name followed by
the call operator parentheses (), inside which zero or more comma-separated arguments appear.
The number of arguments should match the number of function parameters. Each argument is an
expression whose type should match the type of the corresponding parameter in the function
prototype.
An example for the function area call is:
area ( 10, 20);
Delia Ungureanu - UNITBV

77

Functions
When a function call is executed, the arguments are first evaluated and their resulting values are
assigned to the corresponding parameters. The function body is then executed. Execution begins
with the first statement after the opening brace ({). Finally, the function return value (if any) is
passed to the caller.
Functions can also call other functions and can even call themselves (see the section "Recursion"
later in this chapter).
Since a call to a function whose return type is non-void yields a return value, the call is an
expression and may be used in other expressions. By contrast, a call to a function whose return
type is void is a statement.
Listing 29 shows the definition of a simple function which calculates the area of a rectangle.
Listing 29 A simple function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

/* A simple function definition*/


#include <iostream.h>
long area( int length, int width);

// function area prototype

int main(void)
{
int len, wid;
long Area;
cout << "Input the rectangle length: ";
cin >> len;
cout << "Input the rectangle width: ";
cin >> wid;
Area = area(len, wid);
// function area call
cout <<"Area = " << Area;
return 0;
}
// function area definition
long area( int length, int width)
{
long Area;
Area = length * width;
return (Area);
}

// function area header

Comments:
The 4 line defines the function prototype. It consists in return type of the function
(long in this case), the function name area and the parameter list. Area has two
parameters which are both of type int.
Line 14 calls the function area and passes the variables input to it as the function's
arguments (the value of len is assigned to length and the value of wid is assigned to
Delia Ungureanu - UNITBV

78

Functions
width). The function's return value is assigned to the variable Area (area and Area
are two different identifiers).
Lines 19-24 define area function.
Line 19 is the header function (is similar to the function prototype).
On line 20 the brace marks the beginning of the function body.
Line 21 is a local variable definition.
Line 23 returns Area as the return value of the function.
The brace on line 24 marks the end of the function body.
Note that the syntax for parameters is similar to the syntax for defining variables: type identifier
followed by the parameter name. However, it is not possible to follow a type identifier with
multiple comma-separated parameters:
long area (int length, width)

// Wrong!

Parameters and Arguments


There are three ways to pass data from one function to another:


By value

By address

By reference

Passing by value is sometimes called passing by copy. When you pass an argument from one
function to another, the argument's value is passed to the receiving function, but the variable
itself isn't passed. The value parameter receives a copy of the value of the argument passed to it.
As a result, if the function makes any changes to the parameter, this will not affect the argument.
For example, in Listing 29 the two parameters are value parameters. When the function is called
and len passed to length, length receives a copy of the value of len. In some way, width receives a
copy of the value of wid.
The second way of passing data to a function is passing by address. Parameters used in this case
are pointers that hold addresses of arguments. When Visual C++ passes a variable by address, in
effect it passes the variable itself, which means that the receiving function can change the calling
function's variable. When the calling function regains control, any variable just passed by address
might be changed if the called function changed the argument.
The third way to pass data to a function is passing by reference. When you pass data by
reference, if the called function changes the data, C++ applies those same changes to the calling
function's data. The end result of passing by reference is identical to that of passing by address.
There is one exception, the syntax when you passing variables (nonarrays) by reference: if you
pass nonarrays by address you must precede the passed arguments with ampersands and also
precede all parameters in the called function with asterisks. When passing variables by reference,
you only have to precede the receiving parameters with ampersands.
For example,
Delia Ungureanu - UNITBV

79

Functions
void func1( int * x )

// function passing by address

{ cout << *x; }

// parameter value is obtained by indirection

The call of function func1 is like:


//
int a=10;
func1( &a);

// you pass the address of variable a

//

Compare the above example with the one below:


void func2( int &x )

// function passing by reference

{ cout << x; }

// the value of parameter is obtained directly,


// without indirection

The call of function func2 is like:


//
int a=10;
func2( a);

// you pass the variable a

//

Note: Be careful when passing by reference! Remember that any changes applied to
the receiving parameters will also apply to the sending function's arguments.
Within the context of function calls, the three styles of passing arguments are, respectively, called
pass-by-value, pass-by-address and pass-by-reference. It is perfectly valid for a function to use
pass-by-value for some of its parameters, pass-by-address for others and pass-by-reference for
others.
To observe the differences, consider the three swap functions in Listing 30.
Listing 30 Pass-by-Value, Pass-by-Address and Pass-by-Reference.
1
2
3
4
5
6
7
8
9
10
11
12

/* Parameters passing by value & passing by reference*/


#include <iostream.h>
void swap1 (int x, int y)
// pass-by-value (objects)
{
cout << Function swap1 << endl ;
cout << Initial values : x= << x << , y= << y << endl ;
int temp = x ;
x = y ;
y = temp ;
cout << Final values : x= << x << , y= << y << endl ;
}

Delia Ungureanu - UNITBV

80

Functions
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

Void swap2 (int *x, int *y)


// pass-by-value (pointers)
{
cout << "Function swap2" << endl;
cout << "Initial values: *x=" << *x << ", *y=" << *y << endl;
int temp = *x;
*x = *y;
*y = temp;
cout << "Final values: *x=" << *x << ", *y=" << *y << endl;
}
void swap3 (int &x, int &y)
// pass-by-reference
{
cout << "Function swap3" << endl;
cout << "Initial values: x=" << x << ", y=" << y << endl;
int temp = x;
x = y;
y = temp;
cout << "Final values: x=" << x << ", y=" << y << endl;
}
void main(void)
{
int a, b;
cout << "a= ";
cin >> a;
cout << "b= ";
cin >> b;
swap1( a, b);
cout <<"a= " << a <<", b=" << b << endl;
swap2( &a, &b);
cout <<"a= " << a <<", b=" << b << endl;
swap3( a, b);
cout <<"a= " << a <<", b=" << b << endl;
}

Comments:
swap1 swaps x and y, this has no effect on the arguments passed to the function, because
swap1 receives a copy of the arguments. The change of copy does not affect the original.
swap2 use pointer parameters. By dereferencing the pointers, swap2 gets to the original

values and swaps them. The call syntax of swap2 demands passing the addresses of
variables a and b (see line 43).
swap3 use reference parameters. The parameters become aliases for the arguments passed
to the function and swap them. swap3 has the added advantage that its call syntax is the
same as swap1 and involves no addressing or dereferencing.
Delia Ungureanu - UNITBV

81

Functions
When you run the Listing 30, if you introduce 5 for a and 7 for b, it will produce the following
output (Dialog 13):
Dialog 13
a= 5
b= 7
Function swap1
Initial values: x=5, y=7
Final values: x=7, y=5
a=5, b=7
Function swap2
Initial values: *x=5, *y=7
Final values: *x=7, *y=5
a=7, b=5
Function swap3
Initial values: x=7, y=5
Final values: x=5, y=7
A=5, b=7

There is a significant difference in an array variable and a normal variable: An array variable is
really a pointer in disguise. So when you pass an array as a parameter, you are really passing its
address. This means that when you pass an array, you are effectively passing the contents of the
array by address. Therefore, when you pass an array, the contents of the array can also be
changed.
See for example, Listing 31.
Listing 31 Passing arrays to functions.
1
2
3
4
5
6
7
8
9
10
11
12

/*passing array to a function */


#include <iostream.h>
void reading_array(int Array[10])
{
for (int i=0; i<10; i++)
{
cout<< "Array[" << i << "]=";
cin >> Array[i];
}
}

Delia Ungureanu - UNITBV

82

Functions
13
14
15
16
17
18
19
20
21
22
23
24
25
26

void printing_array(int Array[10])


{
for (int i=0; i<10; i++)
cout << "Array["<< i << "]=" << Array[i] <<endl;
}
void main(void)
{
int myArray[10];
cout << "Reading values for myArray:"<<endl;
reading_array(myArray);
cout << "Printing values of myArray:"<<endl;
printing_array(myArray);
}

Comments:
On line 5-12 and 14-18 are defined two function, reading_array and printing_array,
that have as parameters arrays.
In the main function is declared myArray with 10 elements of type int.
The name of an array is an address, so, when we call the two functions, we specify
the name myArray (line 24 and line 26).
The types of the elements of array parameters and array arguments must be the same.
In that case is int.

Symbolic Constants
A function parameter may also be declared to be constant. This may be used to indicate that the
function does not change the value of a parameter:
int func (const int par1, const int par2)
{
//...
}

A function may also return a constant result. For example,


const char* func (void)
{
return "const string";
}

The usual place for constant definition is within header files so that they can be shared by source
files.

Delia Ungureanu - UNITBV

83

Functions

Global and Local Scope


Variables have either local or global scope. Their scope determines whether or not another
function can use them.
Everything defined outside functions and classes is said to have a global scope. The functions
swap1, swap2, swap3 (Listing 30) all have a global scope.
Variables may also be defined at the global scope.
Uninitialized global variables are automatically initialized to zero.
Global entities are generally accessible everywhere in the program.
Each block in a program defines a local scope. Thus the body of a function represents a local
scope. The parameters of a function have the same scope as the function body. Variables defined
within a local scope are visible to that scope only.
A variable need only be unique within its own scope. Local scopes may be nested, in which case
the inner scopes override the outer scopes. For example, in
int x;

// x is global

void function (int x)

// x is local to the body of function

{
if (x > 0) {
double x;

// x is local to this block

//...
}
}

there are three distinct scopes, each containing a distinct x.


In general, the lifetime of a variable is limited to its scope. So, for example, global variables last
for the duration of program execution, while local variables are created when their scope is
entered and destroyed when their scope is exited. The memory space for global variables is
reserved prior to program execution commencing, whereas the memory space for local variables
is allocated on the fly during program execution.
In C++, global variables are legal, but they are almost never used. They are necessary when the
programmer needs to make data available to many functions and he does not want to pass that
data as a parameter from function to function.
Note: Global variables are dangerous because they are shared data, and one function
can change a global variable in a way that is invisible to another function. This can
and does create bugs that are very difficult to find.

Delia Ungureanu - UNITBV

84

Functions

Scope Operator
Because a local scope overrides the global scope, having a local variable with the same name as a
global variable makes the latter inaccessible to the local scope.
Use the scope access (or resolution) operator ::(two semicolons) to access a global (or file
duration) name even if it is hidden by a local redeclaration of that name.
Listing 32 is an example of scope operator use.
Listing 32 Using scope operator.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#include <iostream.h>
int x=7;

// x is a global variable

void main(void)
{
int x = 9;
// x is local to main
cout << "x= " <<x <<endl;
// refers to local of main x
cout << "::x= " << ::x <<endl;
// refers to global x
{
int x = 11;
// x is local to bloc
cout << "x= " <<x <<endl;
// refers to local of bloc x
cout << "::x= " << ::x <<endl;
// refers to global x
}
}

Comments:
There are three x variable, a global variable x declared in line 3, a variable x with
function main scope declared in line 7 and a variable x declared in line 11 that is local
to nested bloc.
In lines 9 and 13 global variable is accessed using scope operator.
The result of running this listing is Dialog 14Dialog 14.
Dialog 14
x= 9
::x= 7
x= 11
::x= 7

Delia Ungureanu - UNITBV

85

Functions

Auto Variables
Use the auto modifer to define a local variable as having a local lifetime. That variable is also
called automatic.
Syntax of declaration of auto variables is:
[auto] <data-definition> ;

For example:
void func (void)
{
auto int x;

// same as: int x;

//...
}

This is rarely used because all local variables are by default automatic.

Register Variables
As mentioned earlier, variables generally denote memory locations where variable values are
stored. When the program code refers to a variable, the compiler generates machine code which
accesses the memory location denoted by the variable. For frequently-used variables efficiency
gains can be obtained by keeping the variable in a register instead thereby avoiding memory
access for that variable. Objects can be accessed notably faster when placed in a register.
Use the register storage class specifier to store the variable being declared in a CPU register (if
possible), to optimize access and reduce code. Syntax used is:
register <data definition> ;

For example,
register int i;
register point cursor;
register char* p;

Note: It is not possible to take the address of a name declared register, nor can a
register be global.
Note: register is only a hint to the compiler, and in some cases the compiler may
choose not to use a register when it is asked to do so. One reason for this is that any
machine has a limited number of registers and it may be the case that they are all in
use.
Even when the programmer does not use register declarations, many optimizing compilers try
to make an intelligent guess and use registers where they are likely to improve the performance
of the program.
Delia Ungureanu - UNITBV

86

Functions

Static Variables and Functions


It is often useful to confine the accessibility of a global variable or function to a single file. This
is facilitated by the storage class specifier static.
The static storage class specifier with a local variable preserves the last value between successive
calls to that function. A static variable acts like a local variable but has the lifetime of an external
variable.
Syntax of declaration is:
static <data definition> ;
static <function definition> ;

The same argument may be applied to the global variables in this file that are for the private use
of the functions in the file. For example,
static int var;

// static global variable

A local variable in a function may also be defined as static. The variable will remain only
accessible within its local scope; however, its lifetime will no longer be confined to this scope,
but will instead be global. In other words, a static local variable is a global variable which is only
accessible within its local scope.
Like global variables, static local variables are automatically initialized to 0.
Static local variables are useful when we want the value of a local variable to persist across the
calls to the function in which it appears.
An example of using static variable is Listing 33 witch produces Dialog 15.
Listing 33 Using static variable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/*using static variable */


#include <iostream.h>
int func(void)
{
static int m=5;
cout << "m=" << m << endl;
m++;
cout << "m=" << m << endl;
}
void main()
{
cout << "First call of function :" << endl;
func();
cout << "Second call of function :" << endl;
func();
}

Delia Ungureanu - UNITBV

87

Functions
Comments:
Variable m is local of function func. It is declared with static specifier an it is
initialized with 5 (implicit value is 0).
At first call of function func (line 15) m has value 5, and then it is increased, so it
becomes 6.
At second call m has initially value 6, and then it is changed to 7.
Dialog 15
x= 9
::x= 7
x= 11
::x= 7

Extern Variables and Functions


Because a global variable may be defined in one file and referred to in other files, some means of
telling the compiler that the variable is defined elsewhere may be needed. Otherwise, the
compiler may object to the variable as undefined. This is facilitated by an extern declaration. For
example, the declaration
extern int i;

// variable declaration

informs the compiler that i is actually defined somewhere (may be later in this file or in another
file). This is called a variable declaration (not definition) because it does not lead to any storage
being allocated for size.
It is not recommended to include an initializer for an extern variable, since this causes it to
become a variable definition and have storage allocated for it:
extern int size = 10;

// no longer a declaration!

If there is another definition for size elsewhere in the program, it will eventually produces an
error.
Function prototypes may also be declared as extern, but this has no effect when a prototype
appears at the global scope. It is more useful for declaring function prototypes inside a function.
For example:
double Tangent (double angle)
{
extern

double sin(double);

// defined elsewhere

extern

double cos(double);

// defined elsewhere

Delia Ungureanu - UNITBV

88

Functions

return sin(angle) / cos(angle);


}

The best place for extern declarations is usually in header files so that they can
be easily included and shared by source files.

Runtime Stack
When you begin your program, your operating system (such as DOS or Microsoft Windows) sets
up various areas of memory based on the requirements of your compiler. As a C++ programmer,
you'll often be concerned with the global name space, the free store, the code space, and the
stack.
Global variables are in global name space.
The stack is a special area of memory allocated for your program to hold the data required by
each of the functions in your program. It is called a stack because it is a last-in, first-out queue.
Last-in, first-out means that whatever is added to the stack last will be the first thing taken off.
When data is "pushed" onto the stack, the stack grows; as data is "popped" off the stack, the stack
shrinks. It isn't possible to pop a dish off the stack without first popping off all the dishes placed
on after that dish.
C++ function call execution is based on a runtime stack. When a function is called, memory
space is allocated on this stack for the function parameters, return value, and local variables, as
well as a local stack area for expression evaluation. The allocated space is called a stack frame.
When a function returns, the allocated stack frame is released so that it can be reused.
For example, consider a situation where main calls a function called func1 which in turn calls
another function called func2:
int func2 (void)
{
//...
}
int func1 (void)
{
//...
func2();
//...
}

Delia Ungureanu - UNITBV

89

Functions
int main (void)
{
//...
func1();
//...
}

Figure 12 illustrates the stack frame when func1 is being executed.


Figure 12 Function call stack frames.

It is important to note that the calling of a function involves the overheads of creating a stack
frame for it and removing the stack frame when it returns.

Inline Functions
When you define a function, normally the compiler creates just one set of instructions in memory.
When you call the function, execution of the program jumps to those instructions, and when the
function returns, execution jumps back to the next line in the calling function. If you call the
function 10 times, your program jumps to the same set of instructions each time. This means
there is only one copy of the function, not 10.
If a function is declared with the keyword inline, the compiler does not create a real function: it
copies the code from the inline function directly into the calling function. No jump is made; it is
just as if you had written the statements of the function right into the calling function.
If the function is called 10 times, the inline code is copied into the calling functions each of those
10 times. The execution speed increases, but size of executable program increases too.
Syntax of declaration is:
inline <datatype> <class>_<function> (<parameters>) { <statements>; }

Inline functions are best reserved for small, frequently used functions.
For example, a function that return the maximum of two integers :
Delia Ungureanu - UNITBV

90

Functions
inline int Max (int a, int b)
{
return a > b ? a : b;
}

The effect of this is that when Max is called, the compiler, instead of generating code to call Max,
expands and substitutes the body of Max in place of the call. While essentially the same
computation is performed, no function call is involved and hence no stack frame is allocated.
Note: Inline is a hint to the compiler that you would like the function to be inlined.
The compiler is free to ignore the hint and make a real function call.
Use of inline for excessively long and complex functions is almost certainly ignored by the
compiler.

Recursion
A function can call itself. A function which calls itself is said to be recursive. Recursion can be
direct or indirect. It is direct when a function calls itself; it is indirect recursion when a function
calls another function that then calls the first function.
Recursion is a general programming technique applicable to problems which can be defined in
terms of themselves.
Take the factorial problem which is defined as:
 Factorial of 0 is 1.


Factorial of a positive number n is n times the factorial of n-1.

The second line clearly indicates that factorial is defined in terms of itself and hence can be
expressed as a recursive function:
long fact (unsigned int n)
{
if (n<=1)
return 1;
else
return n*Fact(n-1);
}

For n set to 3, Figure 13 provides a trace of the calls to Factorial. The stack frames for these
calls appear sequentially on the runtime stack, one after the other.
Delia Ungureanu - UNITBV

91

Functions
Figure 13 Factorial(3) execution trace.

A recursive function must have at least one termination condition which can be satisfied.
Otherwise, the function will call itself indefinitely until the runtime stack overflows. The Fact
function, for example, has the termination condition n <= 1 which, when satisfied, causes the
recursive calls to fold back. (Note that for a negative n this condition will never be satisfied and
Factorial will fail).
As a general rule, all recursive functions can be rewritten using iteration. An iterative version is
therefore preferred in this case:
long fact (unsigned int n)
{
long res = 1;
for(int i=1; i<=n;i++)

// or: while (n > 0) res=res * n--;

res = res*i;
return res;
}

Default Arguments
For every parameter you declare in a function prototype and definition, the calling function must
pass in a value. The value passed in must be of the declared type. Thus, if you have a function
declared as
int func1(int);

the function must in fact take an integer variable. If the function definition differs, or if you fail to
pass in an integer, you will get a compiler error.
The one exception to this rule is if the function prototype declares a default value for the
parameter. A default value is a value to use if none is supplied. The preceding declaration could
be rewritten as
int func1 (int a = 10);
Delia Ungureanu - UNITBV

92

Functions
This prototype says, "func() returns a long and takes an integer parameter. If an argument is not
supplied, use the default value of 10." Because parameter names are not required in function
prototypes, this declaration could have been written as
int func1 (int = 50);

The function definition is not changed by declaring a default parameter. The function definition
header for this function would be
int func (int a)

If the calling function did not include a parameter, the compiler would fill x with the default
value of 10. The name of the default parameter in the prototype need not be the same as the name
in the function header; the default value is assigned by position, not name.
Any or all of the function's parameters can be assigned default values. The one restriction is this:
If any of the parameters does not have a default value, no previous parameter may have a default
value.
If the function prototype looks like
int func (int par1, int par2, int par3);

you can assign a default value to par2 only if you have assigned a default value to par3. You can
assign a default value to par1 only if you've assigned default values to both par2 and par3. Listing
5.7 demonstrates the use of default values.
Listing 34 Function with default arguments.
1
2
3
4
5
6
7
8
9
10
11
12
13

/*function with default arguments */


#include <iostream.h>
void f(int i, int j=25, float r=2.5)
{cout<<"\n"<<i<<" "<<j<<" "<<r;}
void main()
{
f(3,5,1.5);
f(3,5);
f(3);
f();
}

Delia Ungureanu - UNITBV

// error, too few parameters !

93

Functions
Comments:
On line 4, the f() prototype specifies that the f() function takes three parameters.
The last two have default values. This function prints values passed to parameters.
On line 9 function is called with three arguments, so i is assigned with 3, j with 5 and
r with 1.5.
On line 10 f is called with two arguments: i is assigned with 3, j with 5 and r receives
the default value, 2.5.
On line 11 f is called with one argument, so i is assigned with 3, j and r receive the
default values, 25, respectively 2.5.
On line 12 f is called without argument. This produce an error with the message: too
few parameter in call to f(); i is not default parameter, so it must receive value.
A default argument need not necessarily be a constant. Arbitrary expressions can be used, so long
as the variables used in the expression are available to the scope of the function definition (e.g.,
global variables).
The accepted convention for default arguments is to specify them in function declarations, not
function definitions. Because function declarations appear in header files, this enables the user of
a function to have control over the default arguments. Thus different default arguments can be
specified for different situations. It is, however, illegal to specify two different default arguments
for the same function in a file.

Overloading Functions
C++ enables to create more than one function with the same name. This is called function
overloading. The functions must differ in their parameter list, with a different type of parameter,
a different number of parameters, or both. Here's an example:
int func (int, int);
int func (long, long);
int func (long);

is overloaded with three different parameter lists. The first and second versions differ in
the types of the parameters, and the third differs in the number of parameters.

func()

The return types can be the same or different on overloaded functions. You should note that two
functions with the same name and parameter list, but different return types, generate a compiler
error.
Function overloading is also called function polymorphism (poly means many, and morph means
form).
You can give two or more functions the same function name, and the right one will be called by
Delia Ungureanu - UNITBV

94

Functions
matching the parameters used.
Listing 35 illustrates the use of function overloading.
Listing 35 A demonstration of function polymorphism.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

/*overloading functions*/
#include <iostream.h>
#include<string.h>
int sum(int a,int b)
{ return a+b; }
double sum(double a, double b)
{ return a+b;}
char * sum(char *a, char *b)
{return strcat(a,b);}
void main()
{
cout << "42+17 = " << sum(42,17)<<endl;
cout << "42.0+17.0 = " << sum(42.0,17.0) <<endl;
cout << " C++ + is the best = " <<sum("C++ ", "is the best !")
<<endl;
}

C++ has a sequence for parameter matching to decide which overloaded function to call.
You can't declare two functions with the same parameter list, the call would be ambiguous.
C++ first checks to see whether there is a function that is an exact match. If there is not, it checks
for all possible functions to which it can convert the arguments.
C++ works through the sequence:
1. It looks for an exact match, including default parameters. If only one function is found,
use it. If more than one function is found, report ambiguous function error.
2. It looks for all matches through C++ automatic type conversion (called promotion). If
only one function is found, use it. If more than one function is found, report ambiguous
function error.
3. It looks for user-specified conversions. (In C++, you'll see that you can invent our own
types called classes.) Perform matching again.

Delia Ungureanu - UNITBV

95

Functions
The process becomes even more complicated with multiple parameters, but basically if it does
not find an exact match; it looks at all the nearest matches and chooses the function where the
most parameters match exactly.

Delia Ungureanu - UNITBV

96

Creating New Types

In addition to the regular data types such as int, float, and double, you can now have data types
called as you want and.
You've already learned about a number of variable types, such as int, char, float and so on.
If you declare variables, the type of these variables tells you:


Their size in memory.

What information they can hold.

What actions can be performed on them.

More generally, a type is a category.


Programs are usually written to solve real-world problems. Although it is possible to solve
complex problems by using programs written with only integers and characters, it is far easier to
solve large, complex problems if you can create representations of the objects that you are need.
In C++, the programmer can create any type needed, and each of these new types can have all the
functionality and power of the built-in types.

Typedef
The typedef keyword is used to create a new name for an existing data type. In effect, typedef
creates a synonym. For example, the statement
typedef int integer;

creates integer as a synonym for int. You then can use integer to define variables of type int, as in
this example:
integer count;

Note that typedef doesn't create a new data type; it only lets you use a different name for a
predefined data type.
Other examples:
typedef char string[20];
typedef unsigned int uint;
typedef int bool;

The effect of these definitions is that string becomes an alias for an array of 20 chars, uint
becomes an alias for unsigned int, and bool becomes an alias for int. Therefore:

Delia Ungureanu - UNITBV

97

Creating New Types


string

name;

// is the same as: char name[20];

uint

x;

// is the same as: unsigned int x;

bool

OK;

// is the same as: int OK.

Enumerations
enum keyword is used to define a set of constants of type int, called an enumeration data type.
To define an enumeration we use the syntax:
enum [<enum_name>] {<constant_name> [= <value>], ...} [var_list];

where:
<enum_name> is an identifier that names the set.
<constant_name> is the name of a constant that can optionally be assigned the value

of <value>. These are also called enumeration constants.


<value> must be an integer. If <value> is missing, it is assumed to be: <prev> + 1,

where <prev> is the value of the previous integer constant in the list. For the first
integer constant in the list, the default value is 0.
<var_list> is an optional variable list that assigns variables to the enum type.

For example,
enum bool (false, true);
bool isOdd;

introduces an user-defined type (i.e. the type bool) for representing boolean values, two
enumerators which have integral values starting from 0 (i.e., false is 0 and true is 1) Unlike
symbolic constants, however, which are read-only variables, enumerators have no allocated
memory. isOdd is a variable of type bool.
enum days (sun=1, mon, tues, wed, thur, fri, sat) oneDay;

establishes an integer type named days, a variable oneDay of type days, and a set of enumerators
starting from 1(sun is 1, mon is 2, etc.).
You can omit <enum_type> if no further variables of this enum type are required:
enum {north = 10, south, east = 0, west} dir1, dir2;

introduces four constants (i.e., north is 10, south is 11, east is 0 and west is 1);

Delia Ungureanu - UNITBV

98

Creating New Types


Listing 36 Defining a set of constants using enum.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

/*using enumerations*/
#include <iostream.h>
enum Month {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
char* MonthStr (Month month)
{
switch (month) {
case Jan:
return "January";
case Feb:
return "February";
case Mar:
return "March";
case Apr:
return "April";
case May:
return "May";
case Jun:
return "June";
case Jul:
return "July";
case Aug:
return "August";
case Sep:
return "September";
case Oct:
return "October";
case Nov:
return "November";
case Dec:
return "December";
default:
return "";
}
}
int main (void)
{
cout << MonthStr(Aug) << '\n';
cout << MonthStr(5) << '\n';
return 0;
}

Comments:
On line 4 are defined the user-type named Month and constants: Jan with value 0, Feb
with value 1, etc.
On line 6 is defined the function MonthStr. This function has a parameter of type
Month.
switch statement (lines 8-21) use constants defined with enum Month.
You can call function MonthStr with an integer argument (see line 26, 27);

Delia Ungureanu - UNITBV

99

Creating New Types

Structures
Structures are a very important part of C++. In C, structures provided a way to represent a
collection of data. In C++, structures are far more important because they are a fundamental
building block to representing an object. A structure represents the data needed to describe an
object. In the next chapter, you will explore the concepts behind object-oriented programming.
But first, you will explore the mechanics of structures.
Arrays (and also pointers to data lists) are a powerful method of grouping a lot of data together,
but all data elements must be of the same data type. If you need grouping elements of different
types, you must use structures.
A structure is a collection of one or more variables grouped under a single name for easy
manipulation. A structure can contain any of C++'s data types, including arrays and other
structures.

Defining and Declaring Structures


The syntax used to define a new data type with struct is:
struct [<type-name>] {
[<type> <variable-name[, variable-name, ...]>] ;
.
.
} [<structure-variables>] ;

<type-name> is an optional tag name that refers to the structure type.


<structure-variables>

is a list of variables of type <type-name>, also optional.

Note:
Though both <type-name> and <structure-variables> are optional, one of
the two must appear.
You define elements in the record by naming a <type>, followed by one or more <variablename> (separated by commas).
Each variable within a structure is called a member of the structure.
Note:
Members are often called fields in other programming languages and in
database systems.
Separate different variable types by a semicolon.
For example:
struct exStru { int m1;
char m2;
float m3; } var1,var2 ;
Delia Ungureanu - UNITBV

100

Creating New Types


defines new data type exStru and declares two variables of this type, var1, var2. Both variables
have three members: m1 of type int, m2 of type char and m3 of type float. Organization of
memory is represented in Figure 14:
Figure 14 Allocation of memory for a structure.

Once you create a struct, then you can make many instances of this new type of variable
youve defined. To declare additional variables of the same type, use the < type name> followed
by the variable names, for example:
exStru var3, var4;

Other example:
If you're writing a graphics program, your code needs to deal with the coordinates of points on
the screen. Screen coordinates are written as an x value, giving the horizontal position, and a y
value, giving the vertical position. You can define a structure named coord that contains both the
x and y values of a screen location as follows:
struct coord {
int x;
int y;
};

The following statement declares two instances of type coord:


coord point1, point2;

Accessing Structure Members


Individual structure members can be used like other variables of the same type. They are
accessed using the structure member operator (.), also called the dot operator or record selector.
You can assign values for members of var1:
var1.m1=22;
var1.m2=x;
var1.m3=12.75;

Delia Ungureanu - UNITBV

101

Creating New Types


or if point1 refers to a screen location that has coordinates (50, 100), you could write
point1.x = 50;
point1.y = 100;

To display the screen locations stored in the structure point1, you could write:
cout<< x= << point1.x <<, y= <<point1.y;

Initializing Structures
Like other C++ variable types, structures can be initialized when they're declared. This procedure
is similar to that for initializing arrays. The structure declaration is followed by an equal sign and
a list of initialization values separated by commas and enclosed in braces. For example, look at
the following statement:
struct exStru { int m1;
char m2;
float m3; } myVar = { 99, y, 11.111} ;

When this statement is executed, it performs the following actions:




Define a structure type named exStru.

Declare an instance of structure type exStru named myVar.

Initialize the structure member myVar.m1 to the value 99.

Initialize the structure member myVar.m2 to the character y.

Initialize the structure member myVar.m3 to the value 11.111.

The values are placed in the structure members in the order in which the members are listed in
the structure definition.

Pointers to Structures
A C++ program can declare and use pointers to structures, just as it can declare pointers to any
other data storage type. To create and use pointers to structures, first, define a structure:
struct exStru { int m1;
char m2;
float m3; };

then declare a pointer to type exStru:


exStru * pStru;

Remember, the indirection operator (*) in the declaration says that pStru is a pointer to type
exStrut, not an instance of type exStru.
The pointer pStru can be used only if it was initialized. Because a pointer needs a memory
address to point to, you must declare an instance of type exStru before anything can point to it.
Here's the declaration:
Delia Ungureanu - UNITBV

102

Creating New Types


exStru myVar;

Now you can perform the pointer initialization:


pStru = &myVar;

This statement assigns the address of myStru to pStru.


Note:

A pointer to a structure points to the structure's first byte.

There are two methods to use this pointer:




First method uses the indirection operator (*).

Applying this to the current example, you know that pStru is a pointer to the structure myVar, so
*p_part refers to myVar. You then apply the structure member operator (.) to access individual
members of myVar. To assign the value 100 to myVar.m1, you could write
(*pStru).m1 = 100;

*pStru must be enclosed in parentheses because the (.) operator has a higher precedence than the
(*) operator.
The second method to access structure members using a pointer to the structure is to use the
indirect membership operator, which consists of the characters -> (a hyphen followed by the
greater-than symbol C++ treats them as a single operator, not two.) This symbol is placed
between the pointer name and the member name. For example, to access the number member of
myVar with the pStru pointer, you would write
pStru->m1;

Therefore, there are three ways to access a structure member:




Using the structure name

Using a pointer to the structure with the indirection operator (*)

Using a pointer to the structure with the indirect membership operator (->)

The following expressions are all equivalent:


myVar.m1
(*pStru).m1
pStru->m1

Structures That Contain Structures


As mentioned earlier, a C++ structure can contain any of C++'s data types. For example, a
structure can contain other structures.
The struct coord is defined to represent the coordinates of points on the screen
struct coord {

int x;
int y; };

Delia Ungureanu - UNITBV

103

Creating New Types


Assume that your graphics program needs to deal with rectangles. A rectangle can be defined by
the coordinates of two diagonally opposite corners. You need two such structures to define a
rectangle. You can define a structure as follows:
struct rectangle {

coord topleft;
coord bottomright;

};

This statement defines a structure of type rectangle that contains two structures of type coord.
These two type coord structures are named topleft and bottomright.
The preceding statement defines only the type rectangle structure. To declare a structure, you
must then include a statement such as
rectangle box;

To access the actual data locations (the type int members), you must apply the member operator
(.) twice. Thus, the expression
box.topleft.x

refers to the x member of the topleft member of the type rectangle structure named box.
Figure 15.shows the relationship between the type rectangle structure, the two type coord
structures it contains, and the two type int variables each type coord structure contains.
Figure 15 Allocation of memory for structure rectangle.

To define a rectangle with coordinates (5,10),(25,30), you would write


box.topleft.x = 5;
box.topleft.y = 10;
box.bottomright.x = 25;
box.bottomright.y = 30;

Listing 1 takes input from the user for the coordinates of a rectangle and then calculates and
displays the rectangle's width, length and area.

Delia Ungureanu - UNITBV

104

Creating New Types


Listing 37 A demonstration of structures that contain other structures.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

/* Demonstrates structures that contain other structures. */


#include <iostream.h>
struct coord{

int x;
int y;

};
struct rectangle{

coord topleft;
coord bottomright;

};
void main()
{
int length, width;
long area;
rectangle box;
/* Input the coordinates */
cout <<"\nEnter the top left x coordinate: ";
cin >> box.topleft.x;
cout <<"\nEnter the top left y coordinate: ";
cin >> box.topleft.y;
cout <<"\nEnter the bottom right x coordinate: ";
cin >> box.bottomright.x;
cout <<"\nEnter the bottom right y coordinate: ";
cin >> box.bottomright.y;
/* Calculate and display the length and width of the box */
width = box.bottomright.x - box.topleft.x;
length = box.bottomright.y - box.topleft.y;
cout << "\nThe width is: "<< width ;
cout << "\nThe length is: "<< length;
/* Calculate and display the area */
area = width * length;
cout << "\nThe area is: " << area;
}

Comments:
The coord structure is defined in lines 4 through 6 with its two members, x and y.
Lines 7 through 9 declare the rectangle structure. The two members of the rectangle
structure are topleft and bottomright, both structures of type coord.
Line 14 defines an instance, called box, of the rectangle structure.
Lines 17 through 24 fill in the values in the box structure. Each of box's members has
its own members. topleft and bottomright have two members each, x and y from the
coord structure. This gives a total of four members to be filled.
Delia Ungureanu - UNITBV

105

Creating New Types


After the members are filled with values, the length, width and area are calculated
and displaying using the structure and member names. When using the x and y
values, you must include the structure instance name. Because x and y are in a
structure within a structure, you must use the instance names of both structures,
box.bottomright.x, box.bottomright.y, box.topleft.x, and box.topleft.y, in the
calculations.
Note:

C++ places no limits on the nesting of structures.

While memory allows, you can define structures that contain structures that contain structures, so
on. Rarely are more than three levels of nesting used in any C++ program.

Structures That Contain Arrays


You can define a structure that contains one or more arrays as members. The array can be of any
C data type (int, char, and so on). For example, the statements
struct student

char name[10];
int marks[4];
float average;

};

define a structure of type student that contains a 10-element character array member named
name, a four-element integer array member named marks and a float element named average.
You can then declare a structure named stud1 of type student as follows:
student stud1;

The organization of this structure is shown in Figure 16.


In this figure, every element of array name take a byte because they are of type char, so entire
member name occupies 10 bytes, every element of array marks take two bytes because they are
of type int, so entire member marks occupies 8 bytes and member average is of type float, so it
occupies 4 bytes. (This is because a type int typically requires two bytes of storage, a type char
usually requires only one byte and a type float requires four bytes).
Figure 16 Organization of structure student.

Delia Ungureanu - UNITBV

106

Creating New Types


You access individual elements of arrays that are structure members using a combination of the
member operator and array subscripts:
stud1.name[0] = S;
stud1.marks[0] = 15;
stud1.average =12.5;

Character arrays are most frequently used to store strings. The name of an array, without
brackets, is a pointer to the array.
stud1.name

is a pointer to the first element of array name[] in the structure record. Therefore, you could print
the contents of name[] on-screen using the statement
puts(stud1.name);

or
cout << stud1.name;

To calculate and print on the screen the member average using values of elements of member
marks, you can write next statements:
stud1.average= 0;
for (int i=0; i<4; i++)
stud1.average += stud1.marks[i];
stud1.average /= 4;
cout <<\naverage = << stud1.average;

Pointers as Structure Members


A C++ structure can contain any of C++'s data types, so you have complete flexibility in using
pointers as structure members. Pointer members are declared in the same manner as pointers that
aren't members of structures, that is, by using the indirection operator (*). Here's an example:
struct exStru

{
int *value;
int *rate;
}myVar;

These statements define and declare a structure whose two members are both pointers to type int.
As with all pointers, declaring them is not enough; you must, by assigning them the address of a
variable, initialize them to point to something. If cost and interest have been declared to be type
int variables, you could write
myVar.value = &cost;
myVar.rate = &interest;

Now that the pointers have been initialized, you can use the indirection operator (*). The
expression *myVar.value evaluates to the value of cost, and the expression *myVar.rate
evaluates to the value of interest.
Delia Ungureanu - UNITBV

107

Creating New Types


The type of pointer most frequently used as a structure member is a pointer to type char.
struct msgs {
char *msg1;
char *msg2;
} myVar;
myVar.msg1 = "errors in program";
myVar.msg2 = "conditions are suspicious";

Each pointer member of the structure points to the first byte of a string, stored elsewhere in
memory.
You can use pointer structure members anywhere a pointer can be used. For example, to print the
pointed-to strings, you would write
cout << myVar.msg1;

You can use an array of type char as a structure member and you can use a pointer to type char,
too. These are both methods for "storing" a string in a structure, as shown here in the structure
msg, which uses both methods:
struct msg {
char msg1[30];
char *msg2;
} myVar;

An array name without brackets is a pointer to the first array element. Therefore, you can use
these two structure members in similar fashion:
strcpy(myVar.msg1, "errors in program");
strcpy(myVar.msg2, "conditions are suspicious");

If you define a structure that contains an array of type char, every instance of that structure type
contains storage space for an array of the specified size. For example, the member msg1 is
limited to the specified size, 30 characters; you can't store a larger string in the structure.
If, on the other hand, you define a structure that contains pointers to type char, as member msg2,
these restrictions don't apply. Each instance of the structure contains storage space for only the
pointer. The actual strings are stored elsewhere in memory. There's no length restriction or
wasted space. The actual strings aren't stored as part of the structure. Each pointer in the structure
can point to a string of any length. That string becomes part of the structure, even though it isn't
stored in the structure.

Pointers and Arrays of Structures


A C++ array can contain elements of any data types, so the elements of an array can be of type
structure.
For example, if you define the structure coord:
struct coord { int x, y; };

you can declare an array as follows:


Delia Ungureanu - UNITBV

108

Creating New Types


coord points[100];

This statement declares an array named points that contains 100 elements. Each element is a
structure of type coord and is identified by subscript like other array element types. Each of these
structures has two elements, each of which is of type int. This entire declaration is diagrammed in
Figure 17.
Figure 17 Organization of array points with elements of type coord.

When you have declared the array of structures, you can manipulate the data in many ways.
For example, to assign the data in one array element to another array element, you would write
points[0] = points[99];

This statement assigns to each member of the structure points[0] the values contained in the
corresponding members of points[99].
You can also move data between individual structure members. The statements
points[0].x = points[99].x;

copies the value of member x of points[99] in member x of points[0].


You can combine using arrays of structures and using pointers to access structures.
You can declare a pointer to type coord and initialize it to point to the first structure in the array
points:
coord *pCoord;
pCoord = &points[0];

Recall that the name of an array without brackets is a pointer to the first array element, so the
second line could also have been written as
pCoord = &points[0];

You now have an array of structures of type coord and a pointer to the first array element (that is,
the first structure in the array). For example, you could print the contents of the first element
using the statement
cout << pCoord->x, pCoord->y);

If you wanted to print all the array elements, you would probably use a for loop, printing one
Delia Ungureanu - UNITBV

109

Creating New Types


array element with each iteration of the loop. To access the members using pointer notation, you
must change the pointer pCoord so that with each iteration of the loop it points to the next array
element (that is, the next structure in the array).
You can use the unary increment operator (++). It has a special meaning when applied to a
pointer: It means "increment the pointer by the size of the object it points to." The statement
pCoord++;

has the same effect as


pCoord += sizeof(coord);

If a pointer points to array element n, incrementing the pointer with the (++) operator causes it to
point to element n + 1. If the pointer pCoord was initialized to point to points[0]; each time
pCoord is incremented, it points to the next array element.

Passing Structures as Arguments to Functions


Like any data types, a structure can be passed as an argument to a function.
You can use any style of passing arguments to a function: pass-by-value, pass-by-address and
pass-by-reference.
Listing 38 is an example of passing structures as arguments to functions. We assume to work
with complex numbers. A complex number is expressed as a +bi , where a and b are real
numbers and i is the imaginary unit ( 1 ) . We define a structure named complex with two
members of type double. The members of structure are re for real part of number and im for
imaginary part of number.
Listing 38 Passing structures as arguments to functions.
1
2
3
4
5
6
7
8
9
10
11
12

#include <iostream.h>
struct complex {double re,im;};
void reading_complex(complex *c)
{
cout<<"\nre=";
cin >> c->re;
cout<<"\nim=";
cin >> c->im;
}

Delia Ungureanu - UNITBV

110

Creating New Types


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

complex sum_complex(complex a, complex &b)


{
complex c;
c.re = a.re + b.re;
c.im = a.im + b.im;
return c;
}
void main(void)
{
complex c1, c2, s;
reading_complex(&c1);
reading_complex(&c2);
s= sum_complex(c1, c2);
cout << "\nc1 + c2 is: " << s.re <<" +i* "<< s.im;
}

Comments:
Line 3 defines the structure complex with two members of type double: re and im.
Line 5 through 11 define a function by passing the structure's address (parameter c is
a pointer to the structure complex). You must use the indirect membership operator (>) to access structure members in the function.
Line 13 through 19 define the function sum_complex that pass a parameter by value
and the other by reference. To refer the members of parameters you use the dot
operator (.). That function returns as value a structure complex.
Line 24 and 25 call the function reading_complex. It is necessary to use the address
of an object complex (i.e, &c1 and &c2).
Line 26 call the function sum_complex. It passes the argument c1 by value, and c2 by
reference. The value returned by function is assigned to variable of type complex, s.

Unions
Unions are similar to structures. A union is declared and used in the same ways that a structure is.
A union differs from a structure in that only one of its members can be used at a time. The reason
for this is simple. All the members of a union occupy the same area of memory. They are laid on
top of each other.
Data members of an union are mapped to the same address within its object. The size of an object
of a union is, therefore, the size of its largest data member.
The main use of unions is for situations where an object may assume values of different types,
but only one at a time.
Unions are defined and declared in the same fashion as structures. The only difference in the
Delia Ungureanu - UNITBV

111

Creating New Types


declarations is that the keyword union is used instead of struct.
For example, consider the declaration
For example:
union exUnion { char c;
int i;
float f; } var1 ;

Assuming that a float is 4 bytes, a int 2 bytes, and a char one byte, an object of type exUnion
would be exactly 4 bytes, i.e., the same as the size of a float (see Figure 18).

Figure 18 Allocation of Memory for an Union.

This union, exUnion, can be used to create instances of a union that can hold either a character
value c or an integer value i or a float value f. This is an OR condition. Unlike a structure that
would hold the third values, the union can hold only one value at a time. Figure 18 illustrates
how the shared union would appear in memory.
A union can be initialized on its declaration. Because only one member can be used at a time,
only one can be initialized. To avoid confusion, only the first member of the union can be
initialized. The following code shows an instance of the exUnion union being declared and
initialized:
exUnion var2 = {y};

Notice that the var2 union was initialized just as the first member of a structure would be
initialized.
Individual union members can be used in the same way that structure members can be used, by
using the member operator (.). However, there is an important difference in accessing union
members. Only one union member should be accessed at a time.
Because the members of the union share some memory, if you change the value of one member,
they will be changed the value of all members. Listing 39 illustrates how to use individual union
members and the effect of changing of values of members.

Delia Ungureanu - UNITBV

112

Creating New Types


Listing 39 Using Unions.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

#include <iostream.h>
union exUnion {

char c;
int i;
float f;

};
void main(void)
{
exUnion myVar;
myVar.f=0;
cout <<" c= "<< myVar.c <<", i="<< myVar.i<<", f="<<myVar.f<<endl;
myVar.c= 97;
cout <<" c= "<< myVar.c <<", i="<< myVar.i<<", f="<<myVar.f<<endl;
}

Comments:
Initially you assign the value 0 to member f, so all members have zero values.
Modifying one member, they will be changed all members of unions.

Bit Fields
It is sometimes desirable to directly control an object at the bit level, so that as many individual
data items as possible can be packed into a bit stream without worrying about byte or word
boundaries.
A bit field is an element of a structure that is defined in terms of bits. Using a special type of
struct definition, you can declare a structure element that can range from 1 to 16 bits in length.
For example, this struct
struct bit_field
{
unsigned m1

: 1;

unsigned m2

: 4;

unsigned m3

: 1;

unsigned m4

: 10;

} myVariable;

corresponds to this collection of bit fields (see Figure 19):

Delia Ungureanu - UNITBV

113

Creating New Types


Figure 19 Representation of Bit Fields in Memory.

A bit field is referred to in exactly the same way as any other data member.
myVariable.m1 =0;
myVariable.m2=7;

Because a bit field does not necessarily start on a byte boundary, it is illegal to take its address.
For the same reason, a bit field cannot be defined as static.

Delia Ungureanu - UNITBV

114

Object-Oriented Programming

Until now, the programming you have done has been "traditional" programming. C++ was treated
as a structural language and a procedural language.
In traditional, structured design, the data manipulated by a program and the functions that
manipulate the data are separate.
C++ language is a language that supports object-oriented programming and design. Objectoriented design involves classifying real-world objects and actions as classes that can be created,
manipulated, and destroyed.
The data that makes up an object, and the functions that are performed on that object, are
combined to form a class, or a description of that object. Classes can inherit functionality from
other objects, and you easily can add new classes that leverage existing classes.
So, the first things you will read about object-oriented programming are the three concepts:
 Encapsulation
 Inheritance
 Polymorphism

Let's see what they really mean.

Encapsulation
Encapsulation means hiding away the workings of your code.
Encapsulation means that you hide away the inner workings of your system and present a welldefined interface to the rest of the world that tells it only what it needs to know.
Writing good code means not only that it is fast and does what it is supposed to do, but also that it
can easily be maintained and amended. Hiding the workings of one piece of code away from
another helps the programmer change code, fix errors, or improve its workings without breaking
some piece elsewhere in the program.
This is transposed programming with C++ as creating a new data type that packages data and
functions.

Inheritance
Inheritance is the capability to borrow pieces of code to reuse.
Inheritance is the process of taking an object that does most of the job that you want it to do and
adding some extra bits to do a more useful or specialized job.
Delia Ungureanu - UNITBV

115

Object-Oriented Programming
You can take the existing class, clone it and make additions and modifications to the clone. This
is effectively what you get with inheritance, with the exception that if the original class (called
the base or super or parent class) is changed, the modified clone (called the derived or
inherited or sub or child class) also reflects those changes.
A class which adds new functionality to an existing class is said to derive from that original class.
The original class is said to be the new class's base class.

Polymorphism
Polymorphism is the capabilities to ask different objects to perform the same task and
have the object know how to achieve that task in its own way.
You have two ways to differentiate your new derived class from the original base class. The first
is quite straightforward: you simply add brand new functions to the derived class. These new
functions are not part of the base class interface. This means that the base class simply didnt do
as much as you wanted it to, so you added more functions. This simple and primitive use for
inheritance is, at times, the perfect solution to your problem. However, you should look closely
for the possibility that your base class might also need these additional functions. This process of
discovery and iteration of your design happens regularly in object-oriented programming.
Although inheritance may sometimes imply that you are going to add new functions to the
interface, thats not necessarily true. The second way to differentiate your new class is to change
the behavior of an existing base-class function. This is referred to as overriding that function.
To override a function, you simply create a new definition for the function in the derived class.
Youre saying Im using the same interface function here, but I want it to do something different
for my new type.

Object-oriented programming is a productivity tool. Each of these concepts is a step on the road
to reliable and productive programming. By using prebuilt libraries of code, you can save time
and still have the flexibility of altering the way that they work to suit your own needs.

Classes
A class allows data and functions to be bundled together and used as if they are a single element.
You make a new type by declaring a class. A class is just a collection of variables, often of
different types, combined with a set of related functions. Therefore, a data type consists of two
things:
 A concrete representation of the objects of the type.
 A set of operations for manipulating the objects.

Added to these is the restriction that, other than the designated operations, no other operation
should be able to manipulate the objects. For this reason, we often say that the operations
characterize the type, that is, they decide what can and what cannot happen to the objects. For the
same reason, proper data types as such are often called abstract data types abstract because
the internal representation of the objects is hidden from operations that do not belong to the type.
Delia Ungureanu - UNITBV

116

Object-Oriented Programming
Classes are similar to structures; in fact, classes really are just structures with a different name.
An instance of a class, sometimes called an object, is an occurrence of a class. An instance of one
of your classes can be used or manipulated inside your programs.
Classes and instances of classes are not the same things. Think of a class as the description of an
object; an instance of a class is a concrete occurrence of that class.
A class definition consists of two parts: header and body. The class header specifies the class
name and its base classes. (The latter relates to derived classes and is discussed in next lecture.)
The class body defines the class members. Two types of members are supported:


Data members have the syntax of variable definitions and specify the representation of
class objects. Member variables are part of your class.

Member functions have the syntax of function prototypes and specify the class operations,
also called methods. They are the class interface. They determine what the objects of your
class can do.

C++ uses three explicit keywords to set the boundaries in a class: public, private, protected,
also called access specifiers. These specifiers determine who can use the definitions that follow.
They determine the access permission categories:


Public members are accessible by all class users.

Private members are only accessible by the class members.

Protected members are only accessible by the class members and the members of a derived
class.
Note: The default access permission for a class member is private.

The data type defined by a class is used in exactly the same way as a built-in type.

Declaring a Class
To declare a new type class, you use the syntax:
class <classname> [<:baselist>] { <member list> };

where:
class is a keyword.
<classname> can be any name unique within its scope.
<baselist> lists the base class(es) that this class derives from. <baselist> is optional
<member list> declares the class's data members and member functions.

Use the class keyword to define a C++ class.


Within a class the data are called data members and the functions are called member functions
Delia Ungureanu - UNITBV

117

Object-Oriented Programming
Listing 40 shows the definition of a simple class for representing points in two dimensions.

Listing 40 A simple declaration of class


1
2
3
4
5
6
7
8
9

class point {
set xVal, yVal;
public:
void set( int, int);
int getx(void);
int gety(void);
void move(int dx, int dy);
void print(void);
};

Comments:
First line contains the class header and names the class as point. An open brace
marks the beginning of the class body.
Lines 2-9 contains the body of class point.
Line 2 defines two data members, xVal and yVal, both of type int. The default
access permission for a class member is private. So both xVal and yVal are private.
On line 3 is used keyword public to change access permission for followin g
members. From this point onward the class members are public.
On lines 4-8 are defined member functions. These functions have different type of
parameters and return different types.
The brace on line 9 marks the end of the class body.
You can declare the members in any order. You can use as much access permission specifiers in
any order.

Implementing Class Methods


The declaration of class point includes only prototype of functions. So separately you must define
them.
A public function provides a public interface to the private member data of the class. Any class
methods that you declare must have an implementation. The implementation is called the
function definition.
The definition of a class member function is very similar to a normal function. The function name
should be preceded by the class name and a double-colon.
Listing 41 shows the separate definition of member functions.

Delia Ungureanu - UNITBV

118

Object-Oriented Programming
Listing 41 Example for Definition of Member Functions.
1
2
3
4
5
6

void point::set(int x, int y)


{
xVal=x;
yVal=y;
}
int point::getx(void)
{
return xVal;}

Comments:
The function name should be preceded by the class name and a double-colon. This
identifies set() as being a member of point. The function interface must match its
earlier interface definition within the class (i.e., take two integer parameters and have
the return type void). These functions being members of point is free to refer to xVal
and yVal. The non-member functions do not have permission to refer to xVal, yVal
because they are private.

Inline Implementation
Just as global functions may be defined to be inline, so can the member functions of a class. In
the class point, for example, both member functions are very short (only two statements).
Defining these to be inline improves the efficiency considerably. The keyword inline appears
before the return value.
inline int point::getx(void)
{
return xVal;
}

You can also put the definition of a function into the declaration of the class, which automatically
makes that function inline. For example,

Listing 42 Inline Implementation.


1
2
3
4
5
6
7
8
9
10
11

class point {

Delia Ungureanu - UNITBV

int xVal, yVal;


public:
void set( int x, int y)
{ xVal = x; yVal = y;}
int getx(void)
{ return xVal;
}
int gety(void);
void move(int dx, int dy);
void print(void);

// inline function
// inline function

};

119

Object-Oriented Programming

Comments:
In this example, two functions are completely defined inside the class. The both are
by default inline.

Defining an Object
Once a class is defined, its name denotes a new data type, allowing us to define variables of that
type. For example:
point Point;

define variable Point as type point.


The next declaration
point p1, p2;

defines two objects (p1 and p2) both of the same class (point). Furthermore, operations of a class
are applied to objects of that class, but never the class itself. A class is therefore a concept that
has no concrete existence other than that reflected by its objects.
You should clearly distinguish between object and class. A class denotes a type, of which there is
only one. An object is an element of a particular type (class), of which there may be many.

Accessing Class Members


Member functions are called using the dot operator (.).
For example the statement
p1.set(5,10);

calls function set() for object p1. The arguments passed to functions are (5,10). So the values of
xVal and yVal are changed to 5, respectively 10. p1 is an implicit argument to set().
By making xVal and yVal private members of the class, we have ensured that a user of the class
cannot manipulate them directly:
p1.xVal = 5;

// illegal

Pointers to Classes
A C++ program can declare and use pointers to classes, just as it can declare pointers to
structures or any other data storage type.
Using class pointers is alike using structure pointers (see preview lecture).
To create and use pointers to classes, you use the indirection operator (*) in the declaration:
point * pp;

The pointer p_p can be used only if it was initialized. For example:
Delia Ungureanu - UNITBV

120

Object-Oriented Programming
point myVar;
pp =&myVar

This statement assigns the address of p1 to pp, so *p_p refers to myVar.


You then apply the dot operator (.) or indirect membership operator (->) to access individual
members of myVar. To set values for myVar, you can use set() function :
(*pp).set(2,5);

or:
pp->set(2,5);

To write
(*pp).xVal=99;

or
pp->xVal = 99;

is illegal because xVal is a private member of class.

Listing 43 A simple class


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/* A Simple Class */
# include <iostream.h>
class point{
int xVal, yVal;
public:
void set( int x, int y) //inline
{
xVal=x;
yVal=y;
}
int getx(void)
// inline
{
return xVal;}
int gety(void);
void move(int dx, int dy);
void print(void);
};
inline int point::gety(void)
//inline
{
return yVal;}
void point::move(int dx, int dy)
{
xVal += dx;
yVal += dy;
}
void point::print(void)
{
cout<< "\nx="<< xVal;
cout<< "\ny="<< yVal;
}

Delia Ungureanu - UNITBV

121

Object-Oriented Programming
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

void main(void)
{
point p1, p2, *pp;
p1.print();
p1.set(5,10);
p1.print();
p2 = p1;
p2.print();
p1.move(2,3);
p1.print();
pp = &p1;
cout <<"\np1 has x=" << pp->getx();
cout <<"\np1 has y=" << pp->gety();
}

Comments:
On line 3-15 is declared the class point with tow data members (xVal, yVal) of type
int with access private and five methods. Three of them are inline functions, set() and
getx() are completely defined inside the declaration of the class. The function gety()
is declared explicitly inside.
When you implement the functions gety(), move(), print() you must specify the name
of class which belong to and use the double-colon operator(::) (scop operator) in the
header of functions.
On line 29 are define two objects of type point and a pointer to point.
Line 30 calls the function print() for the p1 object. It will display the values of the
members, xVal and yVal, for p1. The values are residuals because they arent
initialized.
On line 31 function set assigns to xVal, yVal values;
On line 33 is used operator = to assign same values to the object p2. Assignation is
made member by member.
On line 37 the pointer pp is initialised with the address of p1. Further on p1 and *pp
will refer the same object.

this Pointer
Every class member function has a hidden parameter: the this pointer. this points to the
individual object. Therefore, in each call to set(), getx(), gety(), move(), the this pointer for the
object is included as a hidden parameter.
An example of keyword this use:

Delia Ungureanu - UNITBV

122

Object-Oriented Programming
class X {
int a;
public:
X (int b) {this -> a = b;}

In nonstatic member functions, the keyword "this" is a pointer to the object for which the
function is called. All calls to nonstatic member functions pass "this" as a hidden argument.
The keyword "this" is a local variable available in the body of any nonstatic member function.
Use it implicitly within the function for member references. It does not need to be declared and it
is rarely referred to explicitly in a function definition.
For example, in the call x.func(y), where y is a member of X, the keyword "this" is set to &x and
y is set to this->y, which is equivalent to x.y.
For example, you can add a member function in class point (see Listing 43) that displays the
memory address of the object.
class point {
//
void address()
{ cout <<"\nThe address of the object is: " << this;}
//
};

If you add the next lines in function main


cout << "\nThe address of the object is: " << &p1;
p1.address();

at the execution of program they will appear two identical messages like these:
The address of the object is: 0x25472248
The address of the object is: 0x25472248

Constructors
It is possible to define and at the same time initialize objects of a class. This is supported by
special member functions called constructors.

Note:

A constructor always has the same name as the class itself.

Note:

A constructor never has an explicit return type.

For example,

Delia Ungureanu - UNITBV

123

Object-Oriented Programming
class point {
int xVal, yVal;
public:
point (int x,int y) {xVal = x; yVal = y;} // constructor
void move (int,int);
};

is an alternative definition of the point class. The method set() is replaced by a constructor.
You can define objects of type point and initialize them at once. This is in fact compulsory for
classes that contain constructors that require arguments:
point p1 = point(5,10);

or you can use the abbreviated form


point p1(5,10);
point p2;

// illegal,
illegal they are missing the arguments

A class can have more than one constructor. They may be overloaded. To avoid ambiguity,
however, each of these must have a unique signature. For example,
class point {
int xVal, yVal;
public:
point (void)

// default constructor

{ xVal = yVal = 0; }
point (int x, int y)
{ xVal = x; yVal = y; }
point (float, float);

// polar coordinates

// ...
};
point::point (float len, float angle)
{
xVal = (int) (len * cos(angle));
yVal = (int) (len * sin(angle));
}

offers three different constructors. An object of type point can be defined using any of these:
point p0;

// origin

point p1(10,20);

// cartesian coordinates

point p2(1.5,3.14); // polar coordinates

The constructor without parameters is called a default constructor.


If you don't declare a constructor, the compiler makes one for you; it takes no arguments and do
Delia Ungureanu - UNITBV

124

Object-Oriented Programming
nothing.
As with global functions, a member function of a class may have default arguments. The same
rules apply: all default arguments should be trailing arguments, and the argument should be an
expression consisting of objects defined within the scope in which the class appears.
A constructor for the point class may use default arguments. For example,
class point {
int xVal, yVal;
public:
point (int x = 0, int y = 0);
//...
};

where the constructor with default arguments replace the two constructors point(void) and
point(int, int). The following definitions are all valid:
point

p1;

// same as: p1(0, 0)

point

p2(10);

// same as: p2(10, 0)

Ppint

p3(10, 20);

Careless use of default arguments can lead to undesirable ambiguity. For example, given the class
class point {
int xVal, yVal;
public:
point (int x = 0, int y = 0);
point (float x = 0, float y = 0);

// polar coordinates

//...
};

the following definition will be rejected as ambiguous, because it matches both constructors:
Point p;

// ambiguous!
ambiguous

It is important to note that an objects constructor is applied when the object is created. This in
turn depends on the objects scope. For example, a global object is created as soon as program
execution commences; an automatic object is created when its scope is entered; and a dynamic
object is created when the new operator is applied to it.
A special case of constructor is called the copy constructor. This special constructor always
looks like this:
ClassName(const ClassName& name)

This is a constructor that takes a reference to the class object itself as a parameter. This
constructor allows an object to be copied to another object of the same type at the time of
construction.

Delia Ungureanu - UNITBV

125

Object-Oriented Programming
For example,
class point {
int xVal, yVal;
public:
// ...
point (point & p)
{ xVal = p.xVal; yVal = p.yVal; }
// ...
};

defines a copy constructor for class point. It is called like


point p1(5,10);
point p2(p1);

Destructors
Just as a constructor is used to initialize an object when it is created, a destructor is used to clean
up the object just before it is destroyed.

Note:
A destructor always has the same name as the class itself, but is preceded
with a ~ (tilde) symbol.
Note:

Unlike constructors, a class may have at most one destructor.

Note:

A destructor never takes any arguments and has no explicit return type.

Destructors are generally useful for classes which have pointer data members which point to
memory blocks allocated by the class itself. In such cases it is important to release memberallocated memory before the object is destroyed. A destructor can do just that.
For example,
class point {
int xVal, yVal;
public:
point (int x = 0, int y = 0);
~point()
{ cout << Object is destroyed; }
//...
};

Delia Ungureanu - UNITBV

126

Object-Oriented Programming
In general, an objects destructor is applied just before the object is destroyed. This in turn
depends on the objects scope. For example, a global object is destroyed when program execution
is completed; an automatic object is destroyed when its scope is left; and a dynamic object is
destroyed when the delete operator is applied to it.

Static Members
A data member of a class can be defined to be static. This ensures that there will be exactly one
copy of the member, shared by all objects of the class. For example, consider a Window class
which represents windows on a bitmap display:
class point {
static int counter;

// counts declared objects

//...
};

Here, no matter how many objects of type point are defined, there will be only one instance of
counter. Like other static variables, a static data member is by default initialized to 0. It can be
initialized to an arbitrary value in the same scope where the member function definitions appear:
int point::counter = 0;

The alternative is to make such variables global, but this is exactly what static members are
intended to avoid; by including the variable in a class, we can ensure that it will be inaccessible to
anything outside the class.
Member functions can also be defined to be static. Semantically, a static member function is like
a global function which is a friend of the class, but inaccessible outside the class. It does not
receive an implicit argument and hence cannot refer to this. Static member functions are useful
for defining call-back routines whose parameter lists are predetermined and outside the control of
the programmer.
For example,
class point {
//...
static void displayCounter (void);
};

Because static members are shared and do not rely on the this pointer, they are best referred to
using the class::member syntax. For example, displayCounter() would be referred to as
point::displayCounter();

or
point p1::displayCounter();

Delia Ungureanu - UNITBV

127

Object-Oriented Programming

Friends
Occasionally we may need to grant a function access to the nonpublic members of a class. Such
an access is obtained by declaring the function a friend of the class.
The syntax is:
friend <identifier>;

Use friend to declare a function or class with full access rights to the private and protected
members of an outside class, without being a member of that class.
In all other respects, the friend is a normal function in terms of scope, declarations, and
definitions.
If you want to explicitly grant access to a function that isnt a member of the current classyou
must declare that function a friend inside the structure declaration. Its important that the friend
declaration occurs inside the class declaration.
You can declare a global function as a friend, and you can also declare a member function of
another class, or even an entire class, as a friend. Heres an example :
class point {
//...
friend double distance( point, point);
};
double distance(point p1, point p2)
{

return (sqrt(pow(p1.xVal-p2.xVal, 2)+pow(p1.yVal-p2.yVal, 2));


}

The function distance calculate and return the distance between two points. It is declared friend to
class point inside the class, but it is not a member of point. It has access to private members of
point. It is a global function and can be called like:
cout << \nDistance between p1 and p2 is: << distance(p1, p2);

The statement:
p1.distance(p1,p2);

will produce an error message.


The case of having all member functions of a class A as friends of another class B can be
expressed in an abbreviated form:
class A;
class B {
//...
friend class A;

// abbreviated form

};

Although a friend declaration appears inside a class, that does not make the function a member of
that class. In general, the position of a friend declaration in a class is irrelevant: whether it
appears in the private, protected, or the public section, it has the same meaning.
Delia Ungureanu - UNITBV

128

Object-Oriented Programming

Overloading
The term overloading means providing multiple definitions of. Overloading of functions
involves defining distinct functions which share the same name, each of which has a unique
signature. Function overloading is appropriate for:
 Defining functions which essentially do the same thing, but operate on different data types.
 Providing alternate interfaces to the same function, you need different algorithms.

C++ allows functions to be overloaded, that is, the same function to have more than one
definition. When an overloaded function is called, the compiler compares the number and type of
arguments and chooses the one that matches the call. For example:

Listing 44 Example for overloading of functions


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

/* Example for Overloading */


#include <iostream.h>
void g(int a)
{
cout<<"\nfunction 1 with argument: " << a; }
void g( double a )
{
cout<<"\nfunction 2 with argument: " << a; }
void main()
{
int i = 5;
float r = 2.5;
char c = 'a';
long lg = 10000;
g( i );
// call of function 1
g( r );
// call of function 2 - conversion float -> double
g( c );
// call function 1 - conversion char ->int
//
g( lg );
// error - ambiguity between g(int) and g(double)
}

Comments:
On lines 4-5 is defined function g() with one parameter of type int and on lines 7-8 is
defined a function with the same name, g(), but with one parameter of type double.
On line 16 g() is called with an int argument, so it is called the first definition.
On lines 17 the type of argument is different of parameter type. It is made a
conversion of type float to double and it is called the second definition of function.
On line 18 is made a conversion char to int and is called the first definition.
If line 19 is active, it will produce an error message determinate by the ambiguity of
Delia Ungureanu - UNITBV

129

Object-Oriented Programming
conversion (long to int, or long to double);
To avoid ambiguity, each definition of an overloaded function must have a unique signature.
Member functions of a class may also be overloaded. A situation already mooted is overloading
of constructors.
Function overloading is useful for obtaining flavors that are not possible using default arguments
alone. Overloaded functions may also have default arguments.

Operator Overloading
In C++, its possible to define additional meanings for its predefined operators by overloading
them. This definition is just like an ordinary function definition except the name of the function
begins with the keyword operator and ends with the operator itself. Thats the only difference,
and it becomes a function like any other function, which the compiler calls when it sees the
appropriate pattern.
You can overload an operator using member functions or using global functions those are friends
of the class.
Defining an overloaded operator is like defining a function. The syntax used is:
<type> operator <operator symbol>( <parameters> )
{
<statements>;
}

where :
<type> is the data type returned by function;
operator is the keyword;

<operator symbol> is an operator;


<parameter> represent the list of parameters;
<statements> represent the implementation of function.

The number of arguments in the function argument list depends on two factors:
 Whether its a unary (one argument) or binary (two argument) operator.
 Whether the operator is defined as a global function (one argument for unary, two for

binary) or a member function (zero arguments for unary, one for binary the object
becomes the left-hand argument).
Although you can overload almost all the operators available in C++, the use is fairly restrictive.
The next five operators cannot be overloaded:
.
Delia Ungureanu - UNITBV

.*

::

?:

sizeof

// not overloadable

130

Object-Oriented Programming
The overloadable operators are:
 unary:

 binary:

&

++

--

()

->

->*

new

delete

&

<<

>>

+=

-=

/=

%=

&=

|=

^=

<<=

>>=

==

!=

<

>

<=

>=

&&

||

[]

()

A strictly unary operator (e.g., ~) cannot be overloaded as binary, nor can a strictly binary
operator (e.g., =) be overloaded as unary.
C++ does not support the definition of new operator tokens, because this can lead to ambiguity.
Furthermore, the precedence rules for the predefined operators is fixed and cannot be altered. For
example, no matter how you overload *, it will always have a higher precedence than +.
Operators ++ and -- can be overloaded as prefix as well as postfix. Equivalence rules do not hold
for overloaded operators. For example, overloading + does not affect +=, unless the latter is also
explicitly overloaded. Operators ->, =, [], and () can only be overloaded as member functions,
and not globally.

Note:
You cannot combine operators that currently have no meaning in C++
(such as ** to represent exponentiation).
Note:

You cannot change the evaluation precedence of operators.

Note:

You cannot change the number of arguments an operator takes.

Note:

You cannot use a symbol that isnt operator, like @ or $.

Note:

The = , ( ), [ ] and -> operators must be defined as member functions.

When you choose between members and nonmember functions is recommended:


 all unary operators to be defined as members


= ( ) [ ] > must be member

+= = /= *= ^= &= |=

%=

>>= <<= to be defined as members

 all other binary operators to be defined as nonmembers.

To avoid the copying of large objects when passing them to an overloaded operator, references
Delia Ungureanu - UNITBV

131

Object-Oriented Programming
should be used. Pointers are not suitable for this purpose because an overloaded operator cannot
operate exclusively on pointers. If you only need to read from the argument and not change it,
default to passing it as a const reference.
The type of return value you should select depends on the expected meaning of the operator.
All the assignment operators modify the lvalue. To allow the result of the assignment to be used
in chained expressions, like A=B=C, its expected that you will return a reference to that same
lvalue that was just modified.
For the logical operators, everyone expects to get at worst an int back, and at best a bool if it is
defined.

Listing 45 Overloading Operators


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

/* Overloading operators */
# include <iostream.h>
enum bool {false, true};
class point {
int xVal, yVal;
public:
point( int x=0, int y=0)
{
xVal=x; yVal=y; }
void print(void);
point& operator++()
{
xVal++; yVal++;
return *this;
}
friend point& operator--(point&);
point& operator=(point&p)
{
xVal=p.xVal; yVal=p.yVal;
return *this;
}
bool operator==(point);
friend point operator+ (point,point);
};
void point::print(void)
{
cout<< "\nx="<< xVal;
cout<< "\ny="<< yVal;
}
bool point::operator==(point p)
{
if (p.xVal==xVal && p.yVal==yVal) return true;
return false;
}
point& operator--(point&p)
{
p.xVal--; p.yVal-- ;
return p; }
point operator+(point p1, point p2)
{
return point(p1.xVal+p2.xVal , p1.yVal+p2.yVal); }

Delia Ungureanu - UNITBV

132

Object-Oriented Programming
33
34
35
36
37
38
39
40
41
42
43
44

void main(void)
{
point p1(2,5), p2(7,11), p3;
p1++;
p1.print();
p3 = p1;
if (p1==p2)
cout << "\npoints are identical";
else
cout << "\npoints are different";
p3=p1+p2;
p3.print();
}

Comments:
On lines 10-12 is defined the unary operator ++ as member function.
The operator -- is defined with a non-member function. On line 13 it is declared as
friend of class point and on lines 28-30 is defined. Function must have one parameter.
Operator = is defined on lines 14-16. It is a binary operator and it is defined as
member. It cant be defined as non-function.
Binary operator = = is defined as member, so it has one parameter, while operator+ is
defined as friend function, so it has two parameters.

Type Conversion
In C and C++, if the compiler sees an expression or function call using a type that isnt quite the
one it needs, it can often perform an automatic type conversion from the type it has to the type it
wants. In C++, you can achieve this same effect for user-defined types by defining automatic
type-conversion functions. These functions come in two flavors: a particular type of constructor
and an overloaded operator.
In general, given a user-defined type X and another (built-in or user-defined) type Y:
 A constructor defined for X which takes a single argument of type Y will implicitly convert

Y objects to X objects when needed.


 Overloading the type operator Y in X will implicitly convert X objects to Y objects when

needed.
class X {
//...
X (Y&);

// convert Y to X

operator Y ();

// convert X to Y

};

Delia Ungureanu - UNITBV

133

Object-Oriented Programming

Constructor conversion
If you define a constructor that takes as its single argument an object (or reference) of another
type, that constructor allows the compiler to perform an automatic type conversion. For example,
class One

{
public:
One() {}
};

class Two

{
public:
Two(const One&) {}
};

void f(Two) {}
int main()

{
One one;
f(one);
}

When the compiler sees f( ) called with a One object, it looks at the declaration for f( ) and
notices it wants a Two. Then it looks to see if theres any way to get a Two from a One, and it finds
the constructor Two::Two(One), which it quietly calls. The resulting Two object is handed to f( ).
In this case, automatic type conversion has saved you from the trouble of defining two
overloaded versions of f( ). However, the cost is the hidden constructor call to Two, which may
matter if youre concerned about the efficiency of calls to f( ).
In Listing 45 is defined the constructor
point( int x=0, int y=0)
{

xVal=x; yVal=y; }

This constructor can be used to convert int to point. For example,


point p =7;

is equivalent to
point p=point(7);

The effect is an implicit type conversion from int to point. xVal takes the value 7 and yVal
takes 0.

Operator conversion
The second way to effect automatic type conversion is through operator overloading. You can
create a member function that takes the current type and converts it to the desired type using the
operator keyword followed by the type you want to convert to.
If we want to do the conversion from the class type to another type, constructors cannot be used
Delia Ungureanu - UNITBV

134

Object-Oriented Programming
because they always return an object of the class to which they belong. Instead, one can define a
member function which explicitly converts the object to the desired type.
For example, given a rectangle class, we can define a type conversion function which converts
a rectangle to a point, by overloading the type operator point in rectangle:
class rectangle {
point

topLeft;

point

botRight;

public:
rectangle (int left, int top, int right, int bottom);
rectangle (point &p, point &q);
//...
operator point ()

{return botRight - topLeft;}

};

This operator is defined to convert a rectangle to a point, whose coordinates represent the width
and height of the rectangle. Therefore, in the code fragment
point

p(5,5);

rectangle

r(10,10,20,30);

r + p;

rectangle r is first implicitly converted to a point object by the type conversion operator, and
then added to p.
The type conversion point can also be applied explicitly using the normal type cast notation. For
example:
point(r);

// explicit type-cast to a point

(point)r;

// explicit type-cast to a point

Delia Ungureanu - UNITBV

135

Inherita nce
In practice, most classes are not entirely unique, but rather variations of existing ones. Consider,
for example, the class named point for representing points in two dimensions, and another class
named circle for representing circles with the both coordinates of center and the radius. These
two classes would have much in common. For example, they would have similar member
functions such as move(),getx(), gety(), as well as similar data members such as xVal, yVal.
Some of the member functions in both classes would therefore be identical, while a few would be
different. For example, function print() would be different for the two classes, while a function
aria(), that calculates aria of circle can be defined only in class circle.
Given the shared properties of these two classes, it would be tedious to have to define them
independently. Clearly this would lead to considerable duplication of code. The code would not
only take longer to write it would also be harder to maintain: a change to any of the shared
properties would have to be consistently applied to both classes.
Object-oriented programming provides a facility called inheritance to address this problem.
Under inheritance, a class can inherit the properties of an existing class. Inheritance makes it
possible to define a variation of a class without redefining the new class from scratch. Shared
properties are defined only once, and reused as often as desired.
In C++, inheritance is supported by derived classes. A derived class is like an ordinary class,
except that its definition is based on one or more existing classes, called base classes. A derived
class can share selected properties (function as well as data members) of its base classes, but
makes no changes to the definition of any of its base classes. A derived class can itself be the
base class of another derived class. The inheritance relationship between the classes of a program
is called a class hierarchy.
A derived class is also called a subclass, because it becomes a subordinate of the base class in the
hierarchy. Similarly, a base class may be called a superclass, because from it many other classes
may be derived.
When you declare a derived class, you give the name of the class, as usual, but before the
opening brace of the class body, you put a colon and the name of the base class (or classes, for
multiple inheritance). When you do this, you automatically get all the data members and member
functions in the base class.
To declare a new type class, you use the syntax (see lecture 6):
class <classname> [<:baselist>] { <memberlist> };

For example, you may define class circle like


class circle : public point
{

int radius;
public:
// . . .

};

Although the private members of a base class are inherited by a derived class, they are not
accessible to it. For example, circle inherits all the private (and public) members of point, but
Delia Ungureanu - UNITBV

136

Object-Oriented Programming
is not allowed to directly refer to the private members of point. The idea is that private members
should be completely hidden so that they cannot be tampered with by the class clients.
The restriction can be relaxed by defining the base class private members as protected instead. As
far as the clients of a class are concerned, a protected member is the same as a private member: it
cannot be accessed by the class clients. However, a protected base class member can be accessed
by any class derived from it.
For example, the private members of point can be made protected by substituting the keyword
protected for private:
class point {
protected:
int xVal, yVal;
public:
//...
};

The access keywords private, public, and protected can occur as many times as desired in a
class definition. Each access keyword specifies the access characteristics of the members
following it until the next access keyword:
class ex {
public:
// public members...
private:
// private members...
protected:
// protected members...
public:
// more public members...
protected:
// more protected members...
};

A base class may be specified to be private, public, or protected. Unless so specified, the base
class is assumed to be private:
class A {
private:

int x;

void Fx (void);

public:

int y;

void Fy (void);

protected:

int z;

void Fz (void);

};

Delia Ungureanu - UNITBV

137

Object-Oriented Programming
class B : A {};

// A is a private base class of B

class C : private A {};

// A is a private base class of C

class D : public A {};

// A is a public base class of D

class E : protected A {};

// A is a protected base class of E

The behavior of these is as follows (see Table 12 for a summary):


 All the members of a private base class become private members of the derived class. So x,

Fx, y, Fy, z, and Fz all become private members of B and C.


 The members of a public base class keep their access characteristics in the derived class.

So, x and Fx becomes private members of D, y and Fy become public members of D, and z
and Fz become protected members of D.
 The private members of a protected base class become

private members of the derived


class. Whereas, the public and protected members of a protected base class become
protected members of the derived class. So, x and Fx become private members of E, and y,
Fy, z, and Fz become protected members of E.

Table 12 Base class access inheritance rules.


Base Class

Private Derived

Public Derived

Protected Derived

Private Member

private

private

private

Public Member

private

public

protected

Protected Member

private

protected

protected

Thus, private inheritance is useful only if you want to hide part of the functionality of the base
class.

Listing 46 Example for inheritance


1
2
3
4
5
6
7
8
9
10
11
12
13

/*Example for inheritance */


#include <iostream.h>
class point {

Delia Ungureanu - UNITBV

protected:
int xVal, yVal;
public:
point( int x=0, int y=0)
{ xVal=x; yVal=y; }
void move(int x, int y)
{ xVal+=x; yVal+=y;}
void print(void);
};

138

Object-Oriented Programming
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

class circle : public point


{
int radius;
public:
circle(int x=0, int y=0, int r=0):point(x,y)
{radius =r;}
double area(void);
void changeRadius(int r)
{ radius += r;}
void print(void);
};
void point::print(void)
{
cout<< "\nx="<< xVal;
cout<< "\ny="<< yVal;
}
void circle::print(void)
{
cout<< "\nx="<< xVal;
cout<< "\ny="<< yVal;
cout<< "\nradius="<<radius;
}
double circle::area(void)
{return (
3.14 * radius * radius ); }
void main()
{
circle c1(5,10,20);
c1.move(1,2);
c1.print();
cout<<"\nArea="<<c1.area();
}

Comments:
On lines 4-12 is defined class point. The access to xVal, yVal is protected to permit
the access of all derived class.
On line 14 is write the header of class circle. The access to base class is public.
The class circle inherits xVal, yVal as private access member and point(), move(),
print() as public access members.
circle has new members: data member radius and function members area(), circle().
The function print() is overloaded. If it is called by an point object, it is used the
definition of class point and if it is called by an circle object, it is used the definition
of class circle. So on line 43 is called the function declared on line 22.
On line 17 are specified the parameters passed to point constructor. It uses a member
Delia Ungureanu - UNITBV

139

Object-Oriented Programming
initialization list in the definition of the constructor. Otherwise the constructor of
point is called with default values, 0 and 0. The effect is that here members are
initialized before the body of the constructor is executed.
Note:
A member initialization list may be used for initializing any data member
of a class. It is always placed between the constructor header and body. A colon is
used to separate it from the header. It should consist of a comma-separated list of data
members whose initial value appears within a pair of brackets.

Type Conversion
For any derived class there is an implicit type conversion from the derived class to any of its
public base classes. This can be used for converting a derived class object to a base class object,
be it a proper object, a reference, or a pointer:
Such conversions are safe because the derived class object always contains all of its base class
objects.

Listing 47
1 void
2 {
3
4
5
6
7
8
9
10 }

main(void)
// . . .
circle c1(5,10,20);
point p1, *pp;
p1 = c1;
p1.printf();
*pp= &c1;
pp->printf();
point &rp = c1;
rp.printf();
// . . .

In Listing 47 the first assignment, for example, causes the circle component of c1 to be
assigned to p1. They are assigned only the member of base class. The second and third
assignations are legal, but using pp or rp you can access only the base class member. Function
print() called is that witch is defined in class point, so will display only xVal and yVal.
By contrast, there is no implicit conversion from a base class to a derived class. The reason that
such conversion is potentially dangerous due to the fact that the derived class object may have
data members not present in the base class object. The extra data members will therefore end up
with unpredictable values. All such conversions must be defined by you (see paragraph Type
conversion in Lecture 6).

Note:
A base class object cannot be assigned to a derived class object unless
there is a type conversion constructor in the derived class defined for this purpose.
Delia Ungureanu - UNITBV

140

Vous aimerez peut-être aussi