C++ Syllabus Object Oriented Programming PDF
C++ Syllabus Object Oriented Programming PDF
Syllabus
OBJECT ORIENTED PROGRAMMING C++
1. Introduction :
What is object oriented programming? Why do we need objectoriented. Programming characteristics of object-oriented languages. C
and C++.
2. C++ Programming basics :
Output using cout. Directives. Input with cin. Type bool. The setw
manipulator. Type conversions.
3. Functions :
Returning values from functions. Reference arguments. Overloaded
function. Inline function. Default arguments. Returning by reference.
4. Object and Classes :
Making sense of core object concepts (Encapsulation, Abstraction,
Polymorphism, Classes, Messages Association, Interfaces)
Implementation of class in C++, C++ Objects as physical object, C++
object as data types constructor. Object as function arguments. The
default copy constructor, returning object from function. Structures
and classes. Classes objects and memory static class data. Const
and classes.
5. Arrays and string arrays fundamentals. Arrays as class Member
Data :
Arrays of object, string, The standard C++ String class
6. Operator overloading :
Overloading unary operations. Overloading binary operators, data
conversion, pitfalls of operators overloading and conversion
keywords. Explicit and Mutable.
7. Inheritance :
Concept of inheritance. Derived class and based class.
class constructors, member function, inheritance in the
distance class, class hierarchies, inheritance and graphics
public and private inheritance, aggregation : Classes within
inheritance and program development.
Derived
English
shapes,
classes,
2
8. Pointer :
Addresses and pointers. The address of operator and pointer and
arrays. Pointer and Faction pointer and C-types string. Memory
management : New and Delete, pointers to objects, debugging
pointers.
9. Virtual Function :
Virtual Function, friend function, Static function, Assignment and copy
initialization, this pointer, dynamic type information.
10. Streams and Files :
Streams classes, Stream Errors, Disk File I/O with streams, file
pointers, error handling in file I/O with member function, overloading
the extraction and insertion operators, memory as a stream object,
command line arguments, and printer output.
11. Templates and Exceptions :
Function templates, Class templates Exceptions
12. The Standard Template Library :
Introduction algorithms, sequence containers, iteators, specialized
iteators, associative containers, strong user-defined object, function
objects.
Term work / Practical : Each candidate will submit a journal in which at
least 10 assignments based on the above syllabus and the internal paper.
Test will be graded for 10 marks and assignments will be graded for 15
marks.
1. Object Oriented Programming in C++ by Robert Lafore Techmedia
Publication.
2. The complete reference C by Herbert shieldt Tata McGraw Hill
Publication.
3. Object Oriented Programming in C++ Saurav Sahay Oxford University
Press.
4. Object Oriented Programming in C++ R Rajaram New Age
International Publishers 2nd.
5. OOPS C++ Big C++ Cay Horstmann Wiley Publication.
3
Practical for C++
Programming exercises and project using C++ programming
languages, to study various features of the languages. Stress to be laid
on writing well structured modular and readable programs accompanied
by good documentation.
The topic wise assignments are as follows :
1. Function Blocks
a. Handling default reference arguments
b. Handling inline and overloaded function
1
FUNDAMENTALS OF C++
Unit Structure
1.1 Introduction of C++
1.2 Object-Oriented Programming
1.3 Encapsulation
1.4 Polymorphism
1.5 Inheritance
1.6 The Need for C++
1.7 Characteristics of OOPs
1.8 C++ and C
1.3 ENCAPSULATION
Encapsulation is a programming mechanism that binds
together code and the data it manipulates, and that keeps both safe
from outside interference and misuse. In an object-oriented
language, code and data can be bound together in such a way that
a self-contained black box is created. Within the box are all
necessary data and code. When code and data are linked together
in this fashion, an object is created. In other words, an object is the
device that supports encapsulation.
1.4 POLYMORPHISM
Polymorphism (from Greek meaning many forms) is the
quality that allows one interface to access a general class of
actions. A simple example of polymorphism is found in the steering
wheel of an automobile. The steering wheel (the interface) is the
same no matter what type of actual steering mechanism is used.
That is, the steering wheel works the same whether your car has
manual steering, power steering, or rack-and-pinion steering. Thus,
6
turning the steering wheel left causes the car to go left no matter
what type of steering is used. The benefit of the uniform interface
is, of course, that once you know how to operate the steering
wheel, you can drive any type of car.
The same principle can also apply to programming. For
example, consider a stack (which is a first-in, last- out list). You
might have a program that requires three different types of stacks.
One stack is used for integer values, one for floating-point values,
and one for characters. In this case, the algorithm that implements
each stack is the same, even though the data being stored differs.
In a nonobject-oriented language, you would be required to create
three different sets of stack routines, with each set using different
names. However, because of polymorphism, in C++ you can create
one general set of stack routines that works for all three situations.
This way, once you know how to use one stack, you can use them
all.
1.5 INHERITANCE
Inheritance is the process by which one object can acquire
the properties of another object. This is important because it
supports the concept of hierarchical classification. If you think about
it, most knowledge is made manageable by hierarchical (that is,
top-down) classifications. For example, a Red Delicious apple is
part of the classification apple, which in turn is part of the fruit class,
which is under the larger class food. That is, the food class
possesses certain qualities (edible, nutritious, and so on) which
also, logically, apply to its subclass, fruit. In addition to these
qualities, the fruit class has specific characteristics (juicy, sweet,
and so on) that distinguish it from other food. The apple class
defines those qualities specific to an apple (grows on trees, not
tropical, and so on). A Red Delicious apple would, in turn, inherit all
the qualities of all preceding classes and would define only those
qualities that make it unique.
Without the use of hierarchies, each object would have to
explicitly define all of its characteristics. Using inheritance, an
object need only define those qualities that make it unique within its
class. It can inherit its general attributes from its parent. Thus, it is
the inheritance mechanism that makes it possible for one object to
be a specific instance of a more general case.
7
The answer is complexity. Throughout the history of programming,
the increasing complexity of programs has driven the need for
better ways to manage that complexity. C++ is a response to that
need. To better understand the correlation between increasing
program complexity and computer language development, consider
the following. Approaches to programming have changed
dramatically since the invention of the computer.
For example when computers were first invented
programming was done by using the computers front panel to
toggle in the binary machine instructions. As long as programs
were just a few hundred instructions long, this approach worked. As
programs grew, assembly language was invented so that
programmers could deal with larger, increasingly complex
programs by using symbolic representations of the machine
instructions. As programs continued to grow, high-level languages
were developed to give programmers more tools with which to
handle the complexity.
The first widely used computer language was, of course,
FORTRAN. While FORTRAN was a very impressive first step, it is
hardly a language that encourages clear, easy-to-understand
programs. The 1960s gave birth to structured programming, which
is the method of programming encouraged by languages such as
C. With structured languages it was, for the first time, possible to
write moderately complex programs fairly easily. However, even
with structured programming methods, once a project reaches a
certain size, its complexity exceeds what a programmer can
manage. By the late 1970s, many projects were near or at this
point.
In response to this problem, a new way to program began to
emerge: object-oriented programming (OOP). Using OOP, a
programmer could handle larger, more complex programs. The
trouble was that C did not support object-oriented programming.
The desire for an object-oriented version of C ultimately led to the
creation of C++.
In the final analysis, although C is one of the most liked and
widely used professional programming languages in the world,
there comes a time when its ability to handle complexity is
exceeded. Once a program reaches a certain size, it becomes so
complex that it is difficult to grasp as a totality. The purpose of C++
is to allow this barrier to be broken and to help the programmer
comprehend and manage larger, more complex programs.
10) We can build program from the standard working module that
communicate with one another, rather than having to start
writing the code from scratch. This leads to saving of
development time and higher productivity.
11) The principal of data hiding helps the programmer to build
secure programs that cannot be invaded by code in other part
of the program.
12) It is possible to have multiple instance of an object to co-exist
without any interference
13) It is easy to partition the work in a project, based on objects.
14) Object oriented systems can be easily upgraded from small to
large systems.
15) Message passing techniques for communication between
objects makes the interface description with external systems
much simpler.
16) Software complexity can be easily managed.
10
2
C++ PROGRAMMING BASICS
Unit Structure
2.1 Some of the important concepts in oops are
2.2 Basic Data Types in C++
2.3 Variables in C++
2.4 Operators in C++
11
2.1.2 Classes
i) The entire set of data and code of an object can be made a userdefined data type with the help of a class. Objects are actually
variable of the type class.
ii) Once a class has been defined, we can create any number of
objects belonging to that class. Thus a class is collection of
objects of similar type.
iii) Classes are user defined data types and behaves like the built in
type of a programming language.
iv) The syntax for defining class is class class-name
{
------------------------------}
2.1.3 Data abstraction and Encapsulation
i) The wrapping up of data and functions into a single unit called
class is known as encapsulation.
ii) The data is not accessible to the outside world, and only those
functions which are wrapped in the class can access it.
iii) These functions provide the interface between the objects data
and the program. This insulation of the data from direct access
by the program is called data hiding or information hiding.
iv) Abstraction refers to the act of representing essential features
without including the background details or explanations.
v) Classes use the concept of abstraction and are defined as a list
of abstract attributes such as size, weight and coast, and
functions to operate on these attributes.
2.1.4 Inheritance
i) Inheritance is the process by which object of one class acquire
the properties of objects of another class.
ii) In OOPs, the concept of inheritance provides the idea of
reusability. This means that we can add additional features to
an existing class without modifying it.
iii) This is possible by deriving a new class from the existing one.
The new class will have combined features of both the classes.
2.1.5 Polymorphism
i) Polymorphism is important oops concept. It means ability to take
more than one form.
12
ii) In polymorphism an operation may show different behavior in
different instances. The behavior depends upon the type of data
used in the operation.
For Ex- Operation of addition for two numbers, will generate
a sum. If the operands are strings, then the operation would
produce a third string by concatenation.
iii) The process of making an operator to show different behavior in
different instance is called as operator overloading. C++ support
operator overloading.
2.1.6 Dynamic Binding
i) Binding refers to the linking of a procedure call to the code to be
executed in response to the call.
ii) Dynamic binding means that the code associated with a given
procedure call is not known until the time of the call at run time.
2.1.7 Message Passing
i) OOPs consist of a set of objects that communicate with each
other.
ii) Message passing involves following steps
iii) Creating classes that define objects and their behavior
iv) Creating objects from class definitions and
v) Establishing communication among objects.
vi) A message for an object is a request for execution of a
procedure & therefore will invoke a function in the receiving
object that generates the desired result.
Message passing involves specifying the name of the object,
the name of the function i.e. message and the information to be
sent.
Ex
object
message
information
13
A First Simple C++ Program
# include<iostream.h>
int main()
{
cout<<.Hello World.;
return 0;
}
The iostream file:The header file iostream should be included at the beginning
of all programs that uses one output statement.
1. Input Operator cin :The identifier cin is a predefined object in c++ that
corresponds to the standard input stream. Here this stream
represents keyboard.
Syntax:- cin>>variable;
The operator >> is known as extraction or get from operator
& assigns it to the variable on its right.
2. Output operator cout :The identifier cout is predefined object that represents the
standard output stream in c++. Here standard output stream
represents the screen.
Syntax:- cout<<string;
The operator << is called the insertion or put to operator. It
inserts the contents of the variable on its right to the object on its
left.
3. Return type of main():In C++, main returns an integer type value to the operating
system. So return type for main() is explicitly specified as int.
Therefore every main() in c++ should end with a return 0 statement.
14
Built in type
Derived type
Structure
Union
Class
Enumeration
Array
Function
Pointer
reference
Integral Type
int
void
char
Floating type
Float
double
Built-in-type
1) Integral type : The data types in this type are int and char.
The modifiers signed, unsigned, long & short may be applied to
character & integer basic data type. The size of int is 2 bytes and
char is 1 byte.
2) void void is used
i) To specify the return type of a function when it is not returning
any value.
ii) To indicate an empty argument list to a function.
Ex- Void function1(void)
iii) In the declaration of generic pointers.
EX-
void *gp
15
A generic pointer can be assigned a pointer value of any
basic data type.
Ex .
Void * ptr1;
Char * ptr2;
ptr2 = ptr1;
is allowed in c but not in c++
ptr2 = (char *)ptr1
is the correct statement
3) Floating type:
The data types in this are float & double. The size of the float
is 4 byte and double is 8 byte. The modifier long can be applied to
double & the size of long double is 10 byte.
User-defined type:
i) The user-defined data type structure and union are same as
that of C.
ii) Classes Class is a user defined data type which can be used
just like any other basic data type once declared. The class
variables are known as objects.
iii) Enumeration
a) An enumerated data type is another user defined type which
provides a way of attaching names to numbers to increase
simplicity of the code.
b) It uses enum keyword which automatically enumerates a list of
words by assigning them values 0, 1, 2,..etc.
c) Syntax:enum shape {
circle,
square,
triangle
}
Now shape becomes a new type name & we can declare
new variables of this type.
EX .
shape oval;
16
d) In C++, enumerated data type has its own separate type.
Therefore c++ does not permit an int value to be automatically
converted to an enum value.
Ex.
enum colour {red, blue, pink = 3}; //it will assign red to o, blue
to 1, & pink to 3 or enum colour {red = 5, blue, green}; //it will
assign red to 5, blue to 6 & green to 7.
2) Functions
Functions in c++ are different than in c there is lots of
modification in functions in c++ due to object orientated concepts in
c++.
3) Pointers
Pointers are declared & initialized as in c.
Ex
17
Name
Char
Description
Character
small integer
int Short Integer.
Size*
Range*
or 1byte
signed:
-128
t127
unsigned: 0 to 255
short
2bytes signed: -32768 to 32767
(short)
unsigned: 0 to65535
Int
Integer.
4bytes signed: - 2147483648 to
2147483647
unsigned: 0 to 4294967295
long
int Long integer.
4bytes signed:
-2147483648
to
(long)
2147483647
unsigned: 0 to 4294967295
Bool
Boolean value. It 1byte true or false
can take one of
two values: true
or false.
Float
Floating
point 4bytes 3.4e +/- 38 (7 digits)
number.
double
Double precision 8bytes 1.7e +/- 308 (15 digits)
floating
point
number.
long
Long
double 8bytes 1.7e +/- 308 (15 digits)
double
precision floating
point number.
wchar_t
Wide character.
2bytes 1 wide character
int a;
float mynumber;
18
declared, the variables a and mynumber can be used within the
rest of their scope in the program.
If you are going to declare more than one variable of the
same type, you can declare all of them in a single statement by
separating their identifiers with commas.
For example:
int a, b, c;
This declares three variables (a, b and c), all of them of type
int, and has exactly the same meaning as:
int a;
int b;
int c;
The integer data types char, short, long and int can be
either signed or unsigned depending on the range of numbers
needed to be represented. Signed types can represent both
positive and negative values, whereas unsigned types can only
represent positive values (and zero). This can be specified by using
either the specifier signed or the specifier unsigned before the type
name.
For example:
19
unsigned int respectively. The following two declarations are
equivalent:
unsigned NextYear;
unsigned int NextYear;
To see what variable declarations look like in action within a
program, we are going to see the C++ code of the example about
your mental memory proposed at the beginning of this section:
Scope of variables:
All the variables that we intend to use in a program must
have been declared with its type specifier in an earlier point in the
code, like we did in the previous code at the beginning of the body
of the function main when we declared that a, b, and result were of
type int.
A variable can be either of global or local scope. A global
variable is a variable declared in the main body of the source code,
outside all functions, while a local variable is one declared within
the body of a function or a block.
20
Dynamic initialization of variables.
In c++, a variable can be initialized at run time using
expressions at the place of declaration. This is refereed to as
dynamic initialization.
Ex
int m = 10;
21
When the function call fun(n) is executed, it will assign x to
ni.e. int &x = n;
Therefore x and n are aliases & when function increments x.
n is also incremented. This type of function call is called call by
reference.
Introduction to strings:
Variables that can store non-numerical values that are
longer than one single character are known as strings.
The C++ language library provides support for strings
through the standard string class. This is not a fundamental type,
but it behaves in a similar way as fundamental types do in its most
basic usage.
A first difference with fundamental data types is that in order
to declare and use objects (variables) of this type we need to
include an additional header file in our source code: <string> and
have access to the std namespace (which we already had in all our
previous programs thanks to the using namespace statement).The
following initialization formats are valid for strings:
string mystring = This is a string;
string mystring (This is a string);
Strings can also perform all the other basic operations that
fundamental data types can, like being declared without an initial
value and being assigned values during execution.
22
this moment in a is not considered at all in this operation, and in
fact that value is lost.
2.4.2 Arithmetic operators ( +, -, *, /, % )
The five arithmetical operations supported by the C++ language
are:
+
*
/
%
addition
subtraction
multiplication
division
modulo
2.4.3 Compound assignment (+=, -=, *=, /=, %=, >>=, <<=,
&=, ^=, |=)
When we want to modify the value of a variable by
performing an operation on the value currently stored in that
variable we can use compound assignment operators:
expression
is equivalent to
value += increase;
a -= 5;
a /= b;
price *= units + 1;
23
are all equivalent in its functionality: the three of them increase by
one the value of c.
A characteristic of this operator is that it can be used both as
a prefix and as a suffix. That means that it can be written either
before the variable identifier (++a) or after it (a++). Although in
simple expressions like a++ or ++a both have exactly the same
meaning, in other expressions in which the result of the increase or
decrease operation is evaluated as a value in an outer expression
they may have an important difference in their meaning: In the case
that the increase operator is used as a prefix (++a) the value is
increased before the result of the expression is evaluated and
therefore the increased value is considered in the outer expression;
in case that it is used as a suffix (a++) the value stored in a is
increased after being evaluated and therefore the value stored
before the increase operation is evaluated in the outer expression.
Notice the difference:
Example1
B=3;
A=++B;
Outpu
Example 2
B=3;
A=B++;
Meaning
Equal to
Not equal to
Greater than
Less than
Greater than or equal to
Less than or equal to
24
Here there are some examples:
(7 == 5) // evaluates to false.
(5 > 4)
// evaluates to true.
(3 != 2) // evaluates to true.
(6 >= 6) // evaluates to true.
(5 < 5)
// evaluates to false.
Of course, instead of using only numeric constants, we can use
any valid expression, including variables. Suppose that a=2, b=3
and c=6,
(a == 5) // evaluates to false since a is not equal to 5.
(a*b >= c) // evaluates to true since (2*3 >= 6) is true.
(b+4 > a*c) // evaluates to false since (3+4 > 2*6) is false.
((b=2) == a) // evaluates to true.
Be careful! The operator = (one equal sign) is not the same
as the operator == (two equal signs), the first one is an assignment
operator (assigns the value at its right to the variable at its left) and
the other one (==) is the equality operator that compares whether
both expressions in the two sides of it are equal to each other.
Thus, in the last expression ((b=2) == a), we first assigned the
value 2 to b and then we compared it to a, that also stores the
value 2, so the result of the operation is true.
2.4.6 Logical operators ( !, &&, || ):
The Operator ! is the C++ operator to perform the Boolean
operation NOT, it has only one operand, located at its right, and the
only thing that it does is to inverse the value of it, producing false if
its operand is true and true if its operand is false. Basically, it
returns the opposite Boolean value of evaluating its operand.
For example:
!(5 == 5) // evaluates to false because the expression at its right
(5 == 5) is true.
!(6 <= 4) // evaluates to true because (6 <= 4) would be false.
!true
// evaluates to false
!false
// evaluates to true.
25
&& OPERATOR
a
true
true
false
false
b
true
false
true
false
a && b
true
false
false
false
26
2.4.9 sizeof()
This operator accepts one parameter, which can be either a
type or a variable itself and returns the size in bytes of that type or
object:
a = sizeof (char);
This will assign the value 1 to a, because char is a one-byte
long type.
The value returned by sizeof is a constant, so it is always
determined before program execution.
Some of the new operators in c++ are1.
2.
3.
4.
5.
6.
7.
8.
::
::*
*
.*
delete
endl
new
stew
27
4) Consider following program.
# include<iostream.h >
int m = 10;
int main ( )
{
int m = 20;
{
int k = m;
int m = 30;
cout << .K = . <<k;
cout << .m = .<<m;
cout << : : m = . << : : m;
}
cout << .m. = .<< m;
cout << .::m = <<::m;
return 0;
}
The output of program is
k = 20
m = 30
:: m = 10
m = 20
:: m =10
In the above program m is declared at three places. And ::m
will always refer to global m.
5) A major application of the scope resolution operator is in the
classes to identify the class to which a member functions
belongs.
Member dereferencing operators .
C++ permits us to define a class containing various types of
data & functions as members. C++ also permits us to access the
class members through pointers. C++ provides a set of three
pointer. C++ provides a set of three pointers to member operators.
1)
2)
3)
::*
- To access a pointer to a member of a class.
.*
- To access a member using object name & a pointer
to that member.
*
- To access a member using a pointer in the object &
a pointer to the member.
28
two unary operators new and delete that perform the task of
allocating & freeing the memory.
2) An object can be created by using new and destroyed by using
delete. A data object created inside a block with new, will
remain existence until it is explicitly destroyed by using delete.
3) It takes following form.
variable = new data type
The new operator allocated sufficient memory to hold a data
object of type data-type & returns the address of the object.
EX
p = new int.
29
Manipulators:
Manipulators are operators that are used to format the data
display. There are two important manipulators.
1) endl
2) stew
1) endl : This manipulator is used to insert a linefeed into an output. It
has same effect as using .\n. for newline.
Ex
2) Setw : With the stew, we can specify a common field width for all
the numbers and force them to print with right alignment.
EX
Ex
avg = sum/float(i)
30
3
CONTROL STATEMENTS
Unit Structure
3.1 Introduction :
3.2 if else Statement
3.3 Nested ifs :
3.4 The switch Statement
3.5 The for Loop
3.6 The while Loop
3.7 The do-while Loop
3.8 Using break to Exit a Loop
3.9 Using the goto Statement
3.1 INTRODUCTION :
This module discusses the statements that control a
programs flow of execution. There are three categories of :
selection statements, which include the if and the switch; iteration
statements, which include the for, while, and do-while loops; and
jump statements, which include break, continue, return, and goto.
Except for return, which is discussed later in this book, the
remaining control statements, including the if and for statements to
which you have already had a brief introduction, are examined
here.
31
if(expression)
{
statement sequence
}
else
{
statement sequence
}
If the conditional expression is true, the target of the if will be
executed; otherwise, the target of the else, if it exists, will be
executed. At no time will both be executed. The conditional
expression controlling the if may be any type of valid C++
expression that produces a true or false result.
This program uses the if statement to determine whether
the users guess matches the magic number. If it does, the
message is printed on the screen. Taking the Magic Number
program further, the next version uses the else to print a message
when the wrong number is picked:
#include<iostream>
#include<cstdlib>
int main()
{
int magic;// magic number
int guess;// users guess
magic = rand(); // get a random number
cout << Enter your guess
cin >> guess;
if (guess == magic) cout << Right;
else cout<< sorry , your are wrong;
return 0;
}
32
The general form of the nested if using blocks of statements is
if(expression)
{
statement sequence
if(expression)
{
statement sequence
}
else
{
statement sequence
}
}
else
{
statement sequence
}
Here is an example
if(i)
{
if(j) result =1;
if(k) result =2;
else result = 3;
}
else result = 4;
The final else is not associated with if(j) (even though it is the
closest if without an else), because it is not in the same block.
Rather, the final else is associated with if(i). The inner else is
associated with if(k) because that is the nearest if. You can use a
nested if to add a further improvement to the Magic Number
program. This addition provides the player with feedback about a
wrong guess.
33
an expression is successively tested against a list of constants.
When a match is found, the statement sequence associated with
that match is executed. The general form of the switch statement is
Switch(expression)
{
case constant 1 :
Statement sequence
Break;
case constant 2 :
Statement sequence
Break;
case constant 3 :
Statement sequence
Break;
.
.
.
Default:
Statement sequence
34
The statement sequences associated with each case are not
blocks. However, the entire switch statement does define a block.
The importance of this will become apparent as you learn more
about C++.
The following program demonstrates the switch. It asks for a
number between 1 and 3, inclusive. It then displays a proverb
linked to that number. Any other number causes an error message
to be displayed.
#include <iostream>
using namespace std;
int main()
{
int num;
cout<< Enter a number from 1 to 3;
cin >>num;
switch(num)
{
case 1:
cout << A rolling stone gathers no moss.\n;
break;
case 2:
cout<< A bird in hand is worth two in the bush.\n;
break;
case 3:
cout<< A full and his money soon parted.\n;
break;
default :
cout<< you must enter 1 , 2 or 3.\n;
break;
}
return 0;
}
Here is a sample run
Enter a number from 1 to 32
A bird in hand is worth two in the bush.
35
36
This program uses the standard function sqrt( ). As
explained in Module 2, the sqrt( ) function returns the square root of
its argument. The argument must be of type double, and the
function returns a value of type double. The header <cmath> is
required.
37
38
for(t=0;t<100;t++)
{
if(t==10) break;
cout<<t<< ;
}
return 0;
}
The output from the program is shown here: 0 1 2 3 4 5 6 7 8 9
As the output illustrates, this program prints only the
numbers 0 through 9 on the screen before ending. It will not go to
100, because the break statement will cause it to terminate early.
Using continue
It is possible to force an early iteration of a loop, bypassing
the loops normal control structure. This is accomplished using
continue. The continue statement forces the next iteration of the
loop to take place, skipping any code between itself and the
conditional expression that controls the loop.
For example, the following program prints the even numbers
between 0 and 100:
#include<iostream>
using namespace std;
int main()
{
int x;
for(x=0;x<100;x++)
{
if(x%2) continue;
cout<<x<< ;
}
return 0;
}
Only even numbers are printed, because an odd number will
cause the continue statement to execute, resulting in early iteration
of the loop, bypassing the cout statement. Remember that the %
operator produces the remainder of an integer division. Thus, when
x is odd, the remainder is 1, which is true. When x is even, the
remainder is 0, which is false. In while and do-while loops, a
continue statement will cause control to go directly to the
39
conditional expression and then continue the looping process. In
the case of the for, the increment part of the loop is performed, then
the conditional expression is executed, and then the loop
continues.
40
4
FUNCTIONS
Unit Structure
4.1 Introduction :
4.2 Function
4.3 Arguments passed by value and by reference.
4.4 Default values in parameters
4.5 Overloaded functions
4.6 inline functions
4.7 Recursivity
4.1 INTRODUCTION :
Using functions we can structure our programs in a more
modular way, accessing all the potential that structured
programming can offer to us in C++.
4.2 FUNCTION
A function is a group of statements that is executed when it
is called from some point of the program. The following is its format:
type name ( parameter1, parameter2, ...) { statements
}
where:
41
Here you have the first function example:
// function example
#include <iostream>
using namespace std;
int addition (int a, int b)
{
int r;
r=a+b;
return (r);
}
int main ()
{
int z;
z = addition (5,3);
cout << "The result is " << z;
return 0;
}
The result is 8
In order to examine this code, first of all remember
something said at the beginning of this tutorial: a C++ program
always begins its execution by the main function. So we will begin
there.
We can see how the main function begins by declaring the
variable z of type int. Right after that, we see a call to a function
called addition. Paying attention we will be able to see the similarity
between the structure of the call to the function and the declaration
of the function itself some code lines above:
The parameters
and arguments
have a clear
correspondence. Within the main function we called to addition
passing two values: 5 and 3, that correspond to the int a and int b
parameters declared for function addition.
At the point at which the function is called from within main,
the control is lost by main and passed to function addition. The
42
value of both arguments passed in the call (5 and 3) are copied to
the local variables int a and int b within the function.
Function addition declares another local variable (int r), and
by means of the expression r=a+b, it assigns to r the result of a
plus b. Because the actual parameters passed for a and b are 5
and 3 respectively, the result is 8.
The following line of code:
return (r);
finalizes function addition, and returns the control back to the
function that called it in the first place (in this case, main). At this
moment the program follows it regular course from the same point
at which it was interrupted by the call to addition. But additionally,
because the return statement in function addition specified a value:
the content of variable r (return (r);), which at that moment had a
value of 8. This value becomes the value of evaluating the function
call.
43
int x=5, y=3, z;
z = addition ( x , y );
What we did in this case was to call to function addition
passing the values of x and y, i.e. 5 and 3 respectively, but not the
variables x and y themselves.
The output is
44
The first thing that should call your attention is that in the
declaration of duplicate the type of each parameter was followed by
an ampersand sign (&). This ampersand is what specifies that their
corresponding arguments are to be passed by reference instead of
by value.
When a variable is passed by reference we are not passing
a copy of its value, but we are somehow passing the variable itself
to the function and any modification that we do to the local
variables will have an effect in their counterpart variables passed as
arguments in the call to the function.
45
void prevnext (int x, int& prev, int& next)
{
prev = x-1;
next = x+1;
}
int main ()
{
int x=100, y, z;
prevnext (x, y, z);
cout << "Previous=" << y << ", Next=" << z;
return 0;
}
The output is :
Previous=99, Next=101
46
cout << endl;
cout << divide (20,4);
return 0;
}
The output is :
6
5
As we can see in the body of the program there are two calls
to function divide. In the first one:
divide (12)
we have only specified one argument, but the function
divide allows up to two. So the function divide has assumed that the
second parameter is 2 since that is what we have specified to
happen if this parameter was not passed (notice the function
declaration, which finishes with int b=2, not just int b). Therefore the
result of this function call is 6 (12/2).
In the second call:
divide (20,4)
there are two parameters, so the default value for b (int b=2)
is ignored and b takes the value passed as argument, that is 4,
making the result returned equal to 5 (20/4).
47
{
return (a/b);
}
int main ()
{
int x=5,y=2;
float n=5.0,m=2.0;
cout << operate (x,y);
cout << "\n";
cout << operate (n,m);
cout << "\n";
return 0;
}
The output is :
10
2.5
48
generated by the function body is inserted at each point the
function is called, instead of being inserted only once and perform a
regular call to it, which generally involves some additional overhead
in running time.
The format for its declaration is:
inline type name ( arguments ... ) { instructions ... }
and the call is just like the call to any other function. You do not
have to include the inline keyword when calling the function, only in
its declaration.
Most compilers already optimize code to generate inline
functions when it is more convenient. This specifier only indicates
the compiler that inline is preferred for this function.
4.7 RECURSIVITY
Recursivity is the property that functions have to be called by
themselves. It is useful for many tasks, like sorting or calculate the
factorial of numbers. For example, to obtain the factorial of a
number (n!) the mathematical formula would be:
n! = n * (n-1) * (n-2) * (n-3) ... * 1
more concretely, 5! (factorial of 5) would be:
5! = 5 * 4 * 3 * 2 * 1 = 120
and a recursive function to calculate this in C++ could be:
// factorial calculator
#include <iostream>
using namespace std;
long factorial (long a)
{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
}
int main ()
49
{
long number;
cout << "Please type a number: ";
cin >> number;
cout << number << "! = " << factorial (number);
return 0;
}
The output is :
50
5
OBJECT AND CLASSES
Unit Structure
5.1 Introduction to Classes
5.2 Class Definition
5.3 Classes and Objects
5.4 Access specifis- Private Public and Protected members
5.5 Member Functions of a Class
5.6 Passing and Returning Objects
5.7 Creating and Using a Copy Constructor
51
example:class tag_name
{
public : // Must
type member_variable_name;
:
type member_function_name();
:
private: // Optional
type member_variable_name;
:
type member_function_name();
:
};
The keyword class is used to define a class template. The
private and public sections of a class are given by the keywords
private and public respectively. They determine the accessibility
of the members. All the variables declared in the class, whether in
the private or the public section, are the members of the class.
Since the class scope is private by default, you can also omit the
keyword private. In such cases you must declare the variables
before public, as writing public overrides the private scope of the
class.
e.g.
class tag_name
{
type member_variable_name; // private
:
type member_function_name(); // private
:
public : // Must
type member_variable_name;
:
type member_function_name();
:
};
The variables and functions from the public section are
accessible to any function of the program. However, a program can
access the private members of a class only by using the public
member functions of the class. This insulation of data members
from direct access in a program is called information hiding.
52
e.g.
class player
{
public :
void getstats(void);
void showstats(void);
int no_player;
private :
char name[40];
int age;
int runs;
int tests;
float average;
float calcaverage(void);
};
The above example models a cricket player. The variables in
the private section name, age, runs, highest, tests, and average
can be accessed only by member functions of the class
calcaverage(), getstats() and showstats(). The functions in the
public section - getstats() and showstats() can be called from the
program directly , but function calcaverage() can be called only
from the member functions of the class getstats() and
showstats().
With information hiding one need not know how actually the
data is represented or functions implemented. The program need
not know about the changes in the private data and functions. The
interface(public) functions take care of this. The OOP methodology
is to hide the implementation specific details, thus reducing the
complexities involved.
53
player Sachin, Dravid, Mohan ;
[Or]
class player Sachin , Dravid, Mohan ;
where Sachin and Dravid are two objects of the class player.
Both the objects have their own set of member variables. Once the
object is declared, its public members can be accessed using the
dot operator with the name of the object. We can also use the
variable no_player in the public section with a dot operator in
functions other than the functions declared in the public section of
the class.
e.g.
Sachin.getstats();
Dravid.showstats();
Mohan.no_player = 10;
5.4
PUBLIC
AND
54
e.g.
void player :: getstats (void)
{
:
:
}
void player :: showstats (void)
{
:
:
}
This notation indicates that the functions getstats () and
showstats() belong to the class player.
EXAMPLE OF CLASS: Find the area of the rectangle
// class example
#include <iostream.h>
class CRectangle
{
int x, y;
public:
void set_values (int,int);
55
int area (void) {return (x*y);}
};
void CRectangle::set_values (int a, int b)
{
x = a;
y = b;
}
int main ()
{
CRectangle rect, rectb;
rect.set_values (3,4);
rectb.set_values (5,6);
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
}
The output is :
rect area: 12
rectb area: 30
56
cin >> a;
}
void put()
{
cout << a;
}
private :
int a;
};
void main()
{
check c1,c2,c3;
c1.get();
c2.get();
c3 = c1.add(c2);
c3.put();
}
check check :: add ( check c2)
{
check temp;
temp.a = a + c2.a;
return ( temp);
}
The above example creates three objects of class check. It
adds the member variable of two classes, the invoking class c1 and
the object that is passed to the function , c2 and returns the result
to another object c3.
You can also notice that in the class add() the variable of the
object c1 is just referred as a where as the member of the object
passed .i.e. c2 is referred as c2.a . This is because the member
function will be pointed by the pointer named this in the compiler
where as what we pass should be accessed by the extraction
operator .. we may pass more than one object and also normal
variable. we can return an object or a normal variable from the
function. We have made use of a temporary object in the function
add() in order to facilitate return of the object.
57
58
The most common form of copy constructor is shown here:
classname (const classname &obj)
{
// body of constructor
}
Here, obj is a reference to an object that is being used to
initialize another object. For example, assuming a class called
MyClass,and y as an object of type MyClass, then the following
statements would invoke the MyClass copy constructor:
MyClass x = y; // y explicitly initializing x
func1(y); // y passed as a parameter
y = func2(); // y receiving a returned object
In the first two cases, a reference to y would be passed to
the copy constructor. In the third, a reference to the object returned
by func2( ) would be passed to the copy constructor. Thus, when
an object is passed as a parameter, returned by a function, or used
in an initialization, the copy constructor is called to duplicate the
object.
Remember, the copy constructor is not called when one
object is assigned to another. For example, the following sequence
will not invoke the copy constructor:
MyClass x;
MyClass y; x = y; // copy constructor not used here.
Again, assignments are handled by the assignment operator, not
the copy constructor. The following program demonstrates a copy
constructor:
#include <iostream>
using namespace std;
class Myclass
{
int val;
int copynumber;
public:
//Normal constructor
Myclass(int i)
{
59
val=i;
copynumber = 0;
cout<< Inside normal constructor\n;
}
//Copy constructor
Myclass(const Myclass &o)
{
val=o.val;
copynumber=o.copynumber+1;
cout<< Inside copy constructor \n;
}
~Myclass()
{
if (copynumber==0)
cout<< Destructing original \n;
else
cout<< Destructing Copy<< copynumber <<
\n;
}
int getval()
{
return val;
}
};
void display(Myclass ob)
{
cout<< ob.getval()<< \n;
}
int main()
{
Myclass a(10);
display a;
return 0;
}
60
The output is:
Inside normal constructor
Inside copy constructor
10
Destructing copy 1
Destructing original
Here is what occurs when the program is run: When a is
created inside main( ), the value of its copy number is set to 0 by
the normal constructor. Next, a is passed to ob of display( ). When
this occurs, the copy constructor is called, and a copy of a is
created. In the process, the copy constructor increments the value
of copy number. When display( ) returns, ob goes out of scope.
This causes its destructor to be called. Finally, when main( )
returns, a goes out of scope.
You might want to try experimenting with the preceding
program a bit. For example, create a function that returns a My
Class object, and observe when the copy constructor is called.
61
6
STRUCTURES AND UNION
Unit Structure
6.1 Structures
6.2 Pointers to structures
6.3 Nesting structures
6.4 User Defined Data Types
6.5 Unions
6.6 Enumerations (enum)
6.1 STRUCTURES
A data structure is a set of diverse types of data that may
have different lengths grouped together under a unique declaration.
Its form is the following:
struct model_name
{
type1 element1;
type2 element2;
type3 element3;
.
.
} object_name;
where model_name is a name for the model of the structure
type and the optional parameter object_name is a valid identifier (or
identifiers) for structure object instantiations. Within curly brackets {
} they are the types and their sub-identifiers corresponding to the
elements that compose the structure.
If the structure definition includes the parameter
model_name (optional), that parameter becomes a valid type name
equivalent to the structure. For example:
62
struct products
{
char name [30];
float price;
};
products apple;
products orange, melon;
We have first defined the structure model products with two
fields: name and price, each of a different type. We have then used
the name of the structure type (products) to declare three objects of
that type: apple, orange and melon.
Once declared, products has become a new valid type name
like the fundamental ones int, char or short and we are able to
declare objects (variables) of that type.
The optional field object_name that can go at the end of the
structure declaration serves to directly declare objects of the
structure type. For example, we can also declare the structure
objects apple, orange and melon this way:
struct products {
char name [30];
float price;
} apple, orange, melon;
Moreover, in cases like the last one in which we took
advantage of the declaration of the structure model to declare
objects of it, the parameter model_name (in this case products)
becomes optional. Although if model_name is not included it will not
be possible to declare more objects of this same model later.
It is important to clearly differentiate between what is a
structure model, and what is a structure object. Using the terms we
used with variables, the model is the type, and the object is the
variable. We can instantiate many objects (variables) from a single
model (type).
Once we have declared our three objects of a determined
structure model (apple, orange and melon) we can operate with the
fields that form them. To do that we have to use a point (.) inserted
between the object name and the field name. For example, we
63
could operate with any of these elements as if they were standard
variables of their respective types:
apple.name
apple.price
orange.name
orange.price
melon.name
melon.price
each one being of its corresponding data type: apple.name,
orange.name and melon.name are of type char[30], and
apple.price, orange.price and melon.price are of type float.
We are going to leave apples, oranges and melons and go
with an example about movies:
// example about structures
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
struct movies_t {
char title [50];
int year;
} mine, yours;
void printmovie (movies_t movie);
int main ()
{
char buffer [50];
strcpy (mine.title, "2001 A Space Odyssey");
mine.year = 1968;
cout << "Enter title: ";
cin.getline (yours.title,50);
cout << "Enter year: ";
cin.getline (buffer,50);
yours.year = atoi (buffer);
64
cout << "My favourite movie is:\n ";
printmovie (mine);
cout << "And yours:\n ";
printmovie (yours);
return 0;
}
void printmovie (movies_t movie)
{
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
Output :
Enter title: Alien
Enter year: 1979
My favourite movie is:
2001 A Space Odyssey (1968)
And yours:
Alien (1979)
The example shows how we can use the elements of a
structure and the structure itself as normal variables. For example,
yours.year is a valid variable of type int, and mine.title is a valid
array of 50 chars.
Notice that mine and yours are also treated as valid
variables of type movies_t when being passed to the function
printmovie(). Therefore, one of the most important advantages of
structures is that we can refer either to their elements individually or
to the entire structure as a block.
Structures are a feature used very often to build data bases,
specially if we consider the possibility of building arrays of them.
// array of structures
#include <iostream.h>
#include <stdlib.h>
#define N_MOVIES 5
65
struct movies_t
{
char title [50];
int year;
} films [N_MOVIES];
void printmovie (movies_t movie);
int main ()
{
char buffer [50];
int n;
for (n=0; n<N_MOVIES; n++)
{
cout << "Enter title: ";
cin.getline (films[n].title,50);
cout << "Enter year: ";
cin.getline (buffer,50);
films[n].year = atoi (buffer);
}
cout << "\nYou have entered these
movies:\n";
for (n=0; n<N_MOVIES; n++)
printmovie (films[n]);
return 0;
}
void printmovie (movies_t movie)
{
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
Output :
Enter title: Alien
Enter year: 1979
Enter title: Blade Runner
66
Enter year: 1982
Enter title: Matrix
Enter year: 1999
Enter title: Rear Window
Enter year: 1954
Enter title: Taxi Driver
Enter year: 1975
You have entered these movies:
Alien (1979)
Blade Runner (1982)
Matrix (1999)
Rear Window (1954)
Taxi Driver (1975)
67
#include <stdlib.h>
struct movies_t
{
char title [50];
int year;
};
int main ()
{
char buffer[50];
movies_t amovie;
movies_t * pmovie;
pmovie = & amovie;
cout << "Enter title: ";
cin.getline (pmovie->title,50);
cout << "Enter year: ";
cin.getline (buffer,50);
pmovie->year = atoi (buffer);
cout << "\nYou have entered:\n";
cout << pmovie->title;
cout << " (" << pmovie->year << ")\n";
return 0;
}
Output:
Enter title: Matrix
Enter year: 1999
You have entered:
Matrix (1999)
The previous code includes an important introduction:
operator ->. This is a reference operator that is used exclusively
with pointers to structures and pointers to classes. It allows us not
to have to use parenthesis on each reference to a structure
member. In the example we used:
68
pmovie->title
that could be translated to:
(*pmovie).title
both expressions pmovie->title and (*pmovie).title are valid and
mean that we are evaluating the element title of the structure
pointed by pmovie. You must distinguish it clearly from:
*pmovie.title
that is equivalent to
*(pmovie.title)
and that would serve to evaluate the value pointed by element title
of structure movies, that in this case (where title is not a pointer) it
would not make much sense.
struct friends_t
{
char name [50];
char email [50];
movies_t favourite_movie;
} charlie, maria;
friends_t * pfriends = &charlie;
69
Therefore, after the previous declaration we could use the following
expressions:
charlie.name
maria.favourite_movie.title
charlie.favourite_movie.year
pfriends->favourite_movie.year
(where, by the way, the last two expressions are equivalent).
The concept of structures that has been discussed in this
section is the same as used in C language, nevertheless, in C++,
the structure concept has been extended up to the same
functionality of a class with the peculiarity that all of its elements are
considered public.
70
C achar, anotherchar, *ptchar1;
WORD myword;
string_t ptchar2;
field name;
Typedef can be useful to define a type that is repeatedly
used within a program and it is possible that we will need to change
it in a later version, or if a type you want to use has too long a name
and you want it to be shorter.
6.5 UNIONS
Unions allow a portion of memory to be accessed as
different data types, since all of them are in fact the same location
in memory. Its declaration and use is similar to the one of structures
but its functionality is totally different:
union model_name
{
type1 element1;
type2 element2;
type3 element3;
.
.
} object_name;
All the elements of the union declaration occupy the same
space of memory. Its size is the one of the greatest element of the
declaration.
For example:
union mytypes_t
{
char c;
int i;
float f;
} mytypes;
defines three elements:
mytypes.c mytypes.i
mytypes.f
71
each one of a different data type. Since all of them are referring to a
same location in memory, the modification of one of the elements
will afect the value of all of them.
One of the uses a union may have is to unite an elementary
type with an array or structures of smaller elements. For example,
union mix_t
{
long l;
struct
{
short hi;
short lo;
} s;
char c[4];
} mix;
defines three names that allow us to access the same group
of 4 bytes: mix.l, mix.s and mix.c and which we can use according
to how we want to access it, as long, short or char respectively.
Anonymous unions
In C++ we have the option that unions be anonymous. If we
include a union in a structure without any object name (the one that
goes after the curly brackets { }) the union will be anonymous and
we will be able to access the elements directly by its name. For
example, look at the difference between these two declarations:
Union
struct
{
char title[50];
char author[50];
union
{
float dollars;
int yens;
};
} book;
72
anonymous union
struct
{
char title[50];
char author[50];
union
{
float dollars;
int yens;
} price;
} book;
The only difference between the two pieces of code is that in
the first one we gave a name to the union (price) and in the second
we did not. The difference is when accessing members dollars and
yens of an object.
In the first case it would be:
book.price.dollars
book.price.yens
whereas in the second it would be:
book.dollars
book.yens
Once again I remind you that because it is a union, the fields
dollars and yens occupy the same space in the memory so they
cannot be used to store two different values. That means that you
can include a price in dollars or yens, but not both.
73
For example, we could create a new type of variable called
color to store colors with the following declaration:
enum colors_t {black, blue, green, cyan, red, purple, yellow,
white};
Notice that we do not include any fundamental data type in
the declaration. To say it another way, we have created a new data
type without it being based on any existing one: the type color_t,
whose possible values are the colors that we have enclosed within
curly brackets {}. For example, once declared the colors_t
enumeration in the following expressions will be valid:
colors_t mycolor;
mycolor = blue;
if (mycolor == green) mycolor = red;
In fact our enumerated data type is compiled as an integer
and its possible values are any type of integer constant specified. If
it is not specified, the integer value equivalent to the first possible
value is 0 and the following ones follow a +1 progression. Thus, in
our data type colors_t that we defined before, black would be
equivalent to 0, blue would be equivalent to 1, green to 2 and so
on.
If we explicitly specify an integer value for some of the
possible values of our enumerated type (for example the first one)
the following values will be the increases of this, for example:
enum months_t
{
january=1, february, march, april,
may, june, july, august,
september, october, november, December
} y2k;
In this case, variable y2k of the enumerated type months_t
can contain any of the 12 possible values that go from January to
December and that are equivalent to values between 1 and 12, not
between 0 and 11 since we have made January equal to 1.
74
7
ARRAYS
Unit Structure
7.1 Arrays
7.2 One-dimensional arrays
7.3 Two-Dimensional Arrays
7.4 Arrays of Strings
7.5 Arrays of Objects
7.6 Introduction to strings class
7.1 ARRAYS
An array is a collection of variables of the same type that are
referred to by a common name. Arrays may have from one to
several dimensions, although the one-dimensional array is the most
common. Arrays offer a convenient means of creating lists of
related variables.
The array that you will probably use most often is the
character array, because it is used to hold a character string. The
C++ language does not define a built-in string data type. Instead,
strings are implemented as arrays of characters. This approach to
strings allows greater power and flexibility than are available in
languages that use a distinct string type.
75
The general form of a one-dimensional array declaration is
type name[size];
Here, type declares the base type of the array. The base
type determines the data type of each element that makes up the
array. The number of elements the array can hold is specified by
size. For example, the following declares an integer array named
sample that is ten elements long:
int sample[10];
An individual element within an array is accessed through an
index. An index describes the position of an element within an
array. In C++, all arrays have zero as the index of their first
element. Because sample has ten elements, it has index values of
0 through 9. You access an array element by indexing the array
using the number of the element. To index an array, specify the
number of the element you want, surrounded by square brackets.
Thus, the first element in sample is sample[0], and the last element
is sample[9].
For example, the following program loads sample with the numbers
0 through 9:
#include <iostream>
using namespace std;
int main();
{
int sample[10]; // this reserves 10 integer
elements
int t;
//Load the array
for(t=0; t<10; ++t)
cout<<
sample[<<t<<]:<<sample[t]<<\n;
return 0;
}
this
is
76
The output from this example is shown here:
This is sample[0]: 0
This is sample[1]: 1
This is sample[2]: 2
This is sample[3]: 3
This is sample[4]: 4
This is sample[5]: 5
This is sample[6]: 6
This is sample[7]: 7
This is sample[8]: 8
This is sample[9]: 9
In C++, all arrays consist of contiguous memory locations.
(That is, all array elements reside next to each other in memory.)
The lowest address corresponds to the first element, and the
highest address corresponds to the last element.
Arrays are common in programming because they let you
deal easily with sets of related ariables. Here is an example.
The following program creates an array of ten elements and
assigns each element a value. It then computes the average of
those values and finds the minimum and the maximum value.
#include <iostream>
using namespace std;
int main()
{
int i, avg, min_val, max_val;
int nums[10];
num[0]=10;
num[1]=18;
num[2]=75;
num[3]=0;
num[4]=1;
77
num[5]=56;
num[6]=100;
num[7]=12;
num[8]=-19;
num[9]=88;
//Compute the average
avg=0;
for(i=0;i<10;i++)
{
avg+=nums[i];
}
avg /=10;
cout<< Average is <<avg<< \n;
//find minimum and maximum values
min_val=max_val=num[0];
for(i=1;i<10;i++)
{
if(nums[i]<min_val)
{
min_val=nums[i];
}
if(nums[i]>max_val)
{
max_val=nums[i];
}
}
cout<< Minimum value:<< min_val<< \n;
cout<< Maximum value:<<max_val<< \n;
return 0;
}
78
The output from the program is shown here:
Average is 34
Minimum value: -19
Maximum value: 100
Notice how the program cycles through the elements in the
nums array. Storing the values in an array makes this process
easy. As the program illustrates, the loop control variable of a for
loop is used as an index. Loops such as this are very common
when working with arrays.
79
nums[t][i]=(t*4)+i+1;
cout<<nums[t][i]<< ;
}
cout<< \n;
}
return 0;
}
In this example, nums[0][0] will have the value 1, nums[0][1]
the value 2, nums[0][2] the value 3, and so on. The value of
nums[2][3] will be 12. Conceptually, the array will look like that
shown here:
0
10
11
12
num[1][2]
80
To access an individual character within the third string, you
will use a statement like this:
cout << str_array[2][3];
This displays the fourth character of the third string.
The following program demonstrates a string array by
implementing a very simple computerized telephone directory. The
two-dimensional array numbers holds pairs of names and numbers.
To find a number, you enter the name. The number is displayed.
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int i;
char str[80];
char numbers[10][80]= {
Tom=, 555-3322,
Mary, 555-8976,
Jon, 555-1037,
Rachel, 555-1400
};
cout<< Enter name:;
cin>> str;
for(i=0;i<10;i+=2)
{
if(!strcmp(str,numbers[i]))
{
cout<< Number is <<numbers[i+1] << \n;
break;
}
if(i==10)
{
cout<< Not found\n;
}
}
return 0;
}
Here is a sample run:
Enter name: Jon
Number is 555-1037
81
Notice how the for loop increments its loop control variable, i,
by 2 each time through the loop. This is necessary because names
and numbers alternate in the array.
obs[
<<i<<].get_x():
82
83
int main ()
{
string mystring;
mystring = "This is the initial string content";
cout << mystring << endl;
mystring = "This is a different string content";
cout << mystring << endl;
return 0;
}
The output is :
This is the initial string content
This is a different string content
84
8
OPERATOR OVERLOADING
Unit Structure
8.1 Operator Overloading
8.2 Defining operator overloading
8.3 Unary Operator over loading 8.4 Binary Operator overloading
85
Where return type is the type of value returned by the
specified operation and op
is the operator being overloaded. Operator op is the function name.
ii) Operator functions must be either member functions or friend
function. The difference is a friend function will have only one
argument for unary operators and two for binary operators.
While a member function has no arguments for unary operators
and only one for binary operators. This is because the object
used to invoke the member function is passed implicitly and
therefore is available for the member function. This is not case
with friend function, because arguments may be passed either
by value or by reference.
iii) Example .
Vector operator . ( ) ; // unary minus
Vector operator + (vector); // vector addition
Friend vector operator + (vector, vector) // vector
addition
Friend vector operator . (vector); // unary minus
Vector operator . (vector & a); // subtraction
Int operator == (vector); // comparision
Friend int operator == (vector,vector) //comparision
iv) The process of overloading involves .
a)
b)
c)
86
for friend functions and x op y would be interpreted as
x.operator op (y)
in member function and
operator op (x,y) in friend function.
8.3 UNARY OPERATOR OVER LOADING i) In overloading unary operator, a friend function will have only
one argument, while a member function will have no arguments.
ii) Let us consider the unary minus operator. A minus operator,
when used as a unary takes just one operand.
iii) This operator changes the sign of an operand when applied to a
basic data item.
Following example shows how to overload this operator so
that it can be applied to an object in much the same way as is
applied to an int or float variables.
# include <iostream.h>
class unary
{
int x, y, z;
public:
void getdata (int a, int , intc);
void display (void);
void operator . (); // overload unary minus.
};
void unary :: getdata (int a, int b, int c)
{
x = a;
y = b;
z = c;
}
void unary : : display (void)
{
cout << x << . . << y << . . << z << .\n.;
}
void unary ::operator .()
{
87
x = -x ;
y = -y ;
z = -z ;
}
main ( )
{
unary u;
u.getdata(20, -30, 40);
cout << . u : . ;
u. display ( ) ;
-u;
cout << . u : . ;
u. display ( ) ;
}
The output is : -
u : 20 -30 40
u : -20 30 -40
88
c1 = 2.5 + j 3.5
c2 = 1.6 + j 2.7
c3 = 4.1 + j 6.2
89
iii) In the above program, the function operator +, is expected to
add two complex values and return a complex value as a result
but receives only one value as argument.
iv) The function is executed by the statement c3 = c1 + c2
Here, the object c1 is used to invoke the function and c2 plays
the role of an argument that is passed to the function. The
above statement is equivalent to c3 = c1.operator +(c2)
Here, in the operator +() function, the data members of c1
are accessed directly and the data member of c2 are accessed
using the dot operator. Thus in overloading binary operators, the
left-hand operand is used to invoke the operator function and the
right-hand operand is passed
as an argument.
Type Casting
Converting an expression of a given type into another type is
known as type-casting. We have already seen some ways to type
cast:
Implicit conversion
Implicit conversions do not require any operator. They are
automatically performed when a value is copied to a compatible
type. For example:
short a=2000;
int b;
b=a;
Here, the value of a has been promoted from short to int and
we have not had to specify any type-casting operator. This is
known as a standard conversion. Standard conversions affect
fundamental data types, and allow conversions such as the
conversions between numerical types (short to int, int to float,
double to int...), to or from bool, and some pointer conversions.
Some of these conversions may imply a loss of precision, which the
compiler can signal with a warning. This can be avoided with an
explicit conversion.
Implicit conversions also include constructor or operator
conversions, which affect classes that include specific constructors
or operator functions to perform conversions.
90
For example:
class A {};
class B { public: B (A a) {} };
A a;
B b=a;
Here, a implicit conversion happened between objects of
class A and class B, because B has a constructor that takes an
object of class A as parameter. Therefore implicit conversions from
A to B are allowed.
Explicit conversion
C++ is a strong-typed language. Many conversions, specially
those that imply a different interpretation of the value, require an
explicit conversion. We have already seen two notations for explicit
type conversion: functional and c-like casting:
short a=2000;
int b;
b = (int) a; // c-like cast notation
b = int (a); // functional notation
The functionality of these explicit conversion operators is
enough for most needs with fundamental data types. However,
these operators can be applied indiscriminately on classes and
pointers to classes, which can lead to code that while being
syntactically correct can cause runtime errors.
For example, the following code is syntactically correct:
// class type-casting
#include <iostream>
using namespace std;
class CDummy
{
float i,j;
};
class CAddition
{
int x,y;
public:
CAddition (int a, int b)
{
x=a;
y=b;
}
91
int result()
{
return x+y;}
};
int main ()
{
CDummy d;
CAddition * padd;
padd = (CAddition*) &d;
cout << padd->result();
return 0;
}
The program declares a pointer to CAddition, but then it
assigns to it a reference to an object of another incompatible type
using explicit type-casting:
padd = (CAddition*) &d;
Traditional explicit type-casting allows to convert any pointer
into any other pointer type, independently of the types they point to.
The subsequent call to member result will produce either a run-time
error or a unexpected result.
Pitfalls in automatic type conversion
Because the compiler must choose how to quietly perform a
type conversion, it can get into trouble if you dont design your
conversions correctly. A simple and obvious situation occurs with a
class X that can convert itself to an object of class Y with an
operator Y( ) . If class Y has a constructor that takes a single
argument of type X, this represents the identical type conversion.
The compiler now has two ways to go from X to Y, so it will
generate an ambiguity error when that conversion occurs:
// Ambiguity in type conversion
class Y; // Class declaration
class X
{
public:
operator Y() const; //
};
class Y
{
public:
Y(X); // Convert X to Y
Convert X to Y
92
};
void f(Y);
int main()
{
X x;
//! f(x); // Error: ambiguous conversion
} ///:~
The obvious solution to this problem is not to do it: Just
provide a single path for automatic conversion from one type to
another.
A more difficult problem to spot occurs when you provide
automatic conversion to more than one type. This is sometimes
called fan-out:
// Type conversion fanout
class A {};
class B {};
class C
{
public:
operator A() const;
operator B() const;
};
// Overloaded h():
void h(A);
void h(B);
int main()
{
C c;
//! h(c); // Error: C -> A or C -> B ???
} ///:~
Class C has automatic conversions to both A and B. The
insidious thing about this is that theres no problem until someone
innocently comes along and creates two overloaded versions of
h( ). (With only one version, the code in main( ) works fine.)
Again, the solution and the general watchword with
automatic type conversion is to only provide a single automatic
conversion from one type to another. You can have conversions to
93
other types; they just shouldnt be automatic. You can create
explicit function calls with names like make_A( ) and make_B( ).
What is explicit keyword?
EXAMPLE:
Demonstrate
the
usage
of
explicit
keyword
#include <iostream>
using namespace std;
class MyClass
{
int data;
public:
explicit MyClass(int aData) {
cout << "Constructor invoked" << endl;
data = aData;
}
};
int main ()
{
MyClass obj1(100);
/*
* Object creation by conversion as below reports a compiler error.
* Error E2034 explicit.cpp 15: Cannot convert 'int' to 'MyClass'
* in function main()
*/
// MyClass obj2 = 200;
}
94
9
INHERITANCE
Unit Structure
9.1 Introduction
9.2 Types of Inheritance
9.3 Derived and Base Class
9.4 Public Inheritance
9.5 Private Inheritance
9.1 INTRODUCTION :
C++ supports the concept of reusability once a class has
been written and tested, it can be adapted by other programmers to
suit their requirements. This is basically done by creating new
classes, reusing the properties of the existing ones. The
mechanism of deriving a new class from an old one is called
inheritance.
The old class is referred to as base class or super class. And
the new one is called as derived class or subclass.
Inheritance:
The Inheritance is the mechanism of deriving one class from
the other class. Let us assume that the class def is derived from the
existing base class abc. In that case abc is called as base class
and def is called as derived class. The feature that is facility of the
base class will be inherited to the derived class. The derived class
will have its own features. The features of the derived class will
never be inherited to the base class.
Need of Inheritance:
In object oriented programming there are applications for
which the classes are develop, every classes will have its own
features .Consider a situation where we require all the features of a
particular existing class and we also need some additional features.
The above requirement can be satisfied with three different
methods.
95
1) Modify the original existing class by acting new features into it.
The disadvantage of this method is that the users of the original
class will get some extra facility and they can misuse them
2) Rewrite the new class with all the required features i.e. the
features of the existing class plus the new features. The
disadvantage of this method is that it will be consuming more time
and space.
3) Derive the new class from the existing class and only write the
new features in the derived class. The features of the original class
will be inherited to the new class. This method consumes less
space and time. Moreover the original class is not modified. Hence
user of original class will not get extra facilities.
9.2 TYPES OF INHERITANCE: 1. Single Inheritance : A derived class with only one base class, is
called Single Inheritance.
A
96
3. Hierarchical Inheritance : The properties of one class may be
inherited by more than one class is called hierarchical Inheritance.
BASE CLASS
BASE CLASS
DERIVED CLASS C
B
D
97
2. Derived Class: i). A class which acquires properties from base class is called
derived class.
ii). A derived class can be defined by class in addition to its own
detail.
The general form is .
class derived-class-name:
base-class-name
{
:::::
}
visibility-mode
98
iv) Let us consider a simple example to illustrate public
inheritance.
# include<iostream.h>
class base
{
int no1;
public:
int no2;
void getdata();
int getno1();
void showno1();
};
class derived: public Base // public derivation.
{
int no3;
public:
void add();
void display();
};
void Base :: getdata()
{
no1 = 10;
no2 = 20;
}
int Base :: getno1()
{
return no1;
}
void Base :: showno1()
{
cout <<.Number1 =.<<no1 <<.\n.;
}
void Derived :: add()
{
no3 = no2 + getno1(); // no1 is private
}
void Derived :: display()
{
cout << .Number1 = .<<getno1() <<.\n.;
cout << .Number2 = .<<no2<<\n.;
99
cout << .Sum . <<no3 << .\n.;
}
main ( )
{
derived d;
d.getdata ( );
d.add ( );
d.showno1 ( );
d.display ( ) ;
d.b = 100;
d.add ( ) ;
d.display ( ) ;
return 0;
}
The output of the program is
Number1 =
Number1 =
Number2 =
Sum = 30
Number1 =
Number2 =
Sum = 110
10
10
20
10
100
100
iii) Public member of a class can be accessed by its own
objects using the dot operator. So in private Inheritance, no
member of the base class is accessible to the objects of the
derived class.
iv) Syntax is .
class ABC: private PQR
{
member of ABC
}
v) Let us consider a simple example to illustrate private
inheritance.
#include <iostream.h>
class base
{
int x;
public :
int y;
void getxy() ;
int get_x(void) ;
void show_x(void) ;
};
void base ::getxy(void)
{
cout<<.Enter Values for x and y : . ;
cin >> x >> y ;
}
int base : : get_x()
{
return x;
}
void base :: show_x()
{
cout <<.x = . << x << .\n.;
}
void Derived : : mul( )
{
getxy();
z = y * get_x ( ) ;
}
void Derived ::display()
101
{
show_x ( ) ;
cout <<.y = . <<y<<.\n.;
cout<<.z = . <<z<<.\n.;
}
main ( )
{
Derived d;
d. mul();
d.display() ;
//d.y = 4a; won.t work y has become
private.
d.mul();
d.display();
}
The output is Output: Enter values for x and y: 510
X=5
Y = 10
Z = 50
Enter values for x and y:1220
X = 12
Y = 20
Z = 240
Derived Class Constructor
When a base class has a constructor, the derived class
must explicitly call it to initialize the base class portion of the
object. A derived class can call a constructor defined by its base
class by using an expanded form of the derived class
constructor declaration.
The general form of this expanded declaration is shown here:
derived-constructor(arg-list) : base-cons(arg-list);
{
body of derived constructor
}
102
Here, base-cons is the name of the base class inherited
by the derived class. Notice that a colon separates the
constructor declaration of the derived class from the base class
constructor. (If a class inherits more than one base class, then
the base class constructors are separated from each other by
commas.)
103
double
double area()
{
return getWidth() *getHeight()/2;
}
void showStyle()
{
cout<<Triangle is<<style<<\n;
}
};
int main()
{
Triangle t1(isosceles,4.0,4.0);
Triangle t2(right,8.0, 12.0);
cout<<Info for t1:\n;
t1.showStyle();
t1.showDim();
cout<<Area is << t1.area()<<\n;
cout<<\n;
cout<<Info for t2:\n;
t2.shwoStyle();
t2.showDim();
cout<<Area is<<t2.area()<<\n;
return0;
}
h)
104
Here, Triangle( ) calls TwoDShape with the parameters w
and h, which initializes width and height using these values.
Triangle no longer initializes these values itself. It need only
initialize the value unique to it: style. This leaves TwoDShape
free to construct its subobject in any manner that it so chooses.
Furthermore, TwoDShape can add functionality about which
existing derived classes have no knowledge, thus preventing
existing code from breaking.
Any form of constructor defined by the base class can be
called by the derived class constructor. The constructor
executed will be the one that matches the arguments
Summary of access privileges
1. If the designer of the base class wants no one, not even a
derived class to access a member, then that member should be
made private.
2. If the designer wants any derived class function to have access
to it, then that member must be protected.
3. if the designer wants to let everyone, including the instances,
have access to that member , then that member should be
made public.
Summary of derivations
1. Regardless of the type of derivation, private members are
inherited by the derived class, but cannot be accessed by the new
member function of the derived class , and certainly not by the
instances of the derived class .
2. In a private derivation, the derived class inherits public and
protected members as private. a new members function can access
these members, but instances of the derived class may not. Also
any members of subsequently derived classes may not gain access
to these members because of the first rule.
3. In public derivation, the derived class inherits public members as
public , and protected as protected . a new member function of the
derived class may access the public and protected members of the
base class ,but instances of the derived class may access only the
public members.
4. In a protected derivation, the derived class inherits public and
protected members as protected .a new members function of the
derived class may access the public and protected members of the
base class, both instances of the derived class may access only the
public members .
105
Table of Derivation and access specifiers
Derivation Type
Private
Base
Member
Private
Public
Protected
Private
Public
Protected
Private
Public
Protected
Public
Protected
(inaccessible )
Private
Private
(inaccessible )
Public
Protected
(inaccessible )
Protected
Protected
public
yes
protected
yes
private
yes
yes
yes
no
yes
no
no
106
10
POINTERS
Unit Structure
10.1 Introduction :
10.2 Pointer
10.3 The Pointer Operators
10.4 The Base Type of a Pointer
10.5 Assigning Values through a Pointer
10.6 Pointers and Arrays
10.7 Arrays of Pointers
10.8 Function Pointer
10.9 Assign an Address to a Function Pointer
10.10 Calling a Function using a Function Pointer
10.11 Pass a Function Pointer as an Argument
10.12 Return a Function Pointer
10.13 Pointers to Objects
10.14 Operators new and new[]
10.15 Operator delete and delete[]
10.1 INTRODUCTION :
The pointer is one of C++s most powerful features. It is also
one of its most troublesome. Despite their potential for misuse,
pointers are a crucial part of C++ programming. For example, they
allow C++ to support such things as linked lists and dynamic
memory allocation. They also provide one means by which a
function can alter the contents of an argument. However, these and
other uses of pointers will be discussed in subsequent modules. In
this module, you will learn the basics about pointers and see how to
manipulate them.
In a few places in the following discussions, it is necessary
to refer to the size of several of C++s basic data types. For the
sake of discussion, assume that characters are one byte in length,
integers are four bytes long, floats are four bytes long, and doubles
have a length of eight bytes. Thus, we will be assuming a typical
32-bit environment
107
10.2 POINTER
A pointer is an object that contains a memory address. Very
often this address is the location of another object, such as a
variable. For example, if x contains the address of y, then x is said
to point to y.
Pointer variables must be declared as such. The general
form of a pointer variable declaration is
type *var-name;
Here, type is the pointers base type. The base type
determines what type of data the pointer will be pointing to. varname is the name of the pointer variable. For example, to declare ip
to be a pointer to an int, use this declaration:
int *ip;
Since the base type of ip is int, it can be used to point to int
values. Here, a float pointer is declared:
float *fp;
In this case, the base type of fp is float, which means that it
can be used to point to a float value. In general, in a declaration
statement, preceding a variable name with an * causes that
variable to become a pointer.
ptr = &total;
This puts into ptr the memory address of the variable total.
This address is the location of total in the computers internal
memory. It has nothing to do with the value of total. The operation
of & can be remembered as returning the address of the variable
it precedes. Therefore, the preceding assignment statement could
be verbalized as ptr receives the address of total. To better
understand this assignment, assume that the variable total is
located at address 100. Then, after the assignment takes place, ptr
has the value 100.
The second operator is *, and it is the complement of &. It is
a unary operator that returns the value of the variable located at the
108
address specified by its operand. Continuing with the same
example, if ptr contains the memory address of the variable total,
then
val = *ptr;
will place the value of total into val. For example, if total
originally had the value 3,200, then val will have the value 3,200,
because that is the value stored at location 100, the memory
address that was assigned to ptr. The operation of * can be
remembered as at address. In this case, then, the statement
could be read as val receives the value at address ptr.
The following program executes the sequence of the operations
just described:
#include <iostream>
using namespace std;
int main()
{
int total;
int *ptr;
int val;
total = 3200; // assign 3,200 to total
ptr = &total; // get address of total
val = *ptr; // get value at that address
cout << "Total is: " << val << '\n';
return 0;
}
It is unfortunate that the multiplication symbol and the at
address symbol are the same. This fact sometimes confuses
newcomers to the C++ language. These operators have no
relationship to each other. Keep in mind that both & and * have a
higher precedence than any of the arithmetic operators except the
unary minus, with which they have equal precedence. The act of
using a pointer is often called indirection because you are
accessing one variable indirectly through another variable.
109
the type of data upon which the pointer operates. In this case,
because ptr is an int pointer, four bytes of information are copied
into val (assuming a 32-bit int) from the address pointed to by ptr.
However, if ptr had been a double pointer, for example, then eight
bytes would have been copied.
It is important to ensure that pointer variables always point
to the correct type of data. For example, when you declare a
pointer to be of type int, the compiler assumes that anything it
points to will be an integer variable. If it doesnt point to an integer
variable, then trouble is usually not far behind!
For example, the following fragment is incorrect:
int *p; double f; // ... p = &f; // ERROR
This fragment is invalid because you cannot assign a double
pointer to an integer pointer. That is, &f generates a pointer to a
double, but p is a pointer to an int. These two types are not
compatible. (In fact, the compiler would flag an error at this point
and not compile your program.)
Although two pointers must have compatible types in order
for one to be assigned to another, you can override this restriction
(at your own risk) using a cast.
For example, the following fragment is now technically correct: 26
C++ A Beginners Guide by Herbert Schildt
int *p ; double f; // ... p = (int *) &f; // Now
technically OK
The cast to int * causes the double pointer to be converted to
an integer pointer. However, to use a cast for this purpose is
questionable practice. The reason is that the base type of a pointer
determines how the compiler treats the data it points to. In this
case, even though p is actually pointing to a floating-point value,
the compiler still thinks that p is pointing to an int (because p is an
int pointer).
To better understand why using a cast to assign one type of
pointer to another is not usually a good idea, consider the following
short program:
#include<iostream>
using namespace std;
int main()
{
double x, y;
110
int *p;
x=123.23;
p=(int *);
y=*p;
desire result
cout<<y;
return 0;
}
Here is the output produced by the program. (You might see
a different value.)
1.37439e+009
This value is clearly not 123.23! Here is why. In the program,
p (which is an integer pointer) has been assigned the address of x
(which is a double). Thus, when y is assigned the value pointed to
by p, y receives only four bytes of data (and not the eight required
for a double value), because p is an integer pointer. Therefore, the
cout statement displays not 123.23, but a garbage value instead
111
*p=100;
cout<<num<< \n;
(*p)++;
cout<<num<< \n;
(*p)--;
cout<<num<< \n;
return 0;
}
The output from the program is shown here:
100
101
100
or
*(p1+4)
Both statements obtain the fifth element. Remember, array
indices start at zero, so when str is indexed, a 4 is used to access
the fifth element. A 4 is also added to the pointer p1 to get the fifth
element, because p1 currently points to the first element of str.
112
The parentheses surrounding p1+4 are necessary because
the * operation has a higher priority than the + operation. Without
them, the expression would first find the value pointed to by p1 (the
first location in the array) and then add 4 to it. In effect, C++ allows
two methods of accessing array elements: pointer arithmetic and
array indexing. This is important because pointer arithmetic can
sometimes be faster than array indexingespecially when you are
accessing an array in strictly sequential order. Since speed is often
a consideration in programming, the use of pointers to access array
elements is very common in C++ programs. Also, you can
sometimes write tighter code by using pointers instead of array
indexing.
Here is an example that demonstrates the difference
between using array indexing and pointer arithmetic to access the
elements of an array. We will create two versions of a program that
reverse the case of letters within a string. The first version uses
array indexing. The second uses pointer arithmetic. The first
version is shown here:
// Reverse case using array indexing.
#include <iostream>
#include <cctype>
using namespace std;
int main()
{
int i;
char str[80] = "This Is A Test";
cout << "Original string: " << str << "\n";
for(i = 0; str[i]; i++)
{
if(isupper(str[i])) str[i] = tolower(str[i]);
else if(islower(str[i])) str[i] = toupper(str[i]);
}
cout << "Inverted-case string: " << str;
return 0
}
The output from the program is shown here:
Original string: This Is A Test Inverted-case string:
tHIS iS a tEST
Notice that the program uses the isupper( ) and islower( )
library functions to determine the case of a letter. The isupper( )
function returns true when its argument is an uppercase letter;
islower( ) returns true when its argument is a lowercase letter.
Inside the for loop, str is indexed, and the case of each letter is
113
checked and changed. The loop iterates until the null terminating
str is indexed. Since a null is zero (false), the loop stops.
114
{
if(!strcmp(dictionary[i][0], word);
{
cout<<dictionary[i][1]<< \n;
break;
}
}
if(!*dictionary[i][0]
cout<<word<< not found. \n
return 0;
}
Here is a sample run:
Enter word: network
An interconnected group of computers.
When the array dictionary is created, it is initialized with a set
of words and their meanings. Recall, C++ stores all string constants
in the string table associated with your program, so the array need
only store pointers to the strings. The program works by testing the
word entered by the user against the strings stored in the
dictionary. If a match is found, the meaning is displayed. If no
match is found, an error message is printed.
Notice that dictionary ends with two null strings. These mark
the end of the array. Recall that a null string contains only the
terminating null character. The for loop runs until the first character
in a string is null. This condition is tested with this expression:
*dictionary[i][0]
The array indices specify a pointer to a string. The * obtains
the character at that location. If this character is null, then the
expression is false and the loop terminates. Otherwise, the
expression is true and the loop continues.
115
Since a function pointer is nothing else than a variable, it
must be defined as usual. In the following example
we define two function pointers named pt2Function and
pt2Member. They point to functions, which take one float and two
char and return an int. In the C++ example it is assumed, that the
function, our pointer points to, is a member function of TMyClass.
10.9
ASSIGN AN
POINTER
ADDRESS
TO
FUNCTION
116
{
cout << "TMyClass::DoMore" << endl;
return a-b+c;
};
/* more of TMyClass */
};
pt2Member = TMyClass::DoIt; // assignment
pt2Member = &TMyClass::DoMore; // alternative
using address operator
10.11
PASS A FUNCTION
ARGUMENT
POINTER
AS
AN
117
}
// execute example code - DoIt is a suitable function like
defined above in 2.1-4
void Pass_A_Function_Pointer()
{
cout
<<
endl
Pass_A_Function_Pointer" << endl;
PassPtr(&DoIt);
}
<<
"Executing
"Executing
118
float (*pt2Function)(float, float); // define a function
pointer
pt2Function=GetPtr1(+); // get function pointer from
function GetPtr1
cout << pt2Function(2, 4) << endl; // call function
using the pointer
pt2Function=GetPtr2(-); // get function pointer from
function GetPtr2
cout << pt2Function(2, 4) << endl; // call function
using the pointer
}
#include<iostream>
using namespace std;
class P_example
{
int num;
public:
void set_num(int val)
{Num=val;}
void show_num(){cout<<num<< \n;
};
int main()
{
P_example ob, *p;
ob.set_num(1);
ob.show_num();
119
P=&ob;
// Assign P the address of ob
P ->set_num(20); //Call functions through a pointer
to tob
P ->show_num();
return 0;
}
120
array has to be a constant value, which limits its size to what we
decide at the moment of designing the program, before its
execution, whereas the dynamic memory allocation allows us to
assign memory during the execution of the program (runtime) using
any variable or constant value as its size.
The dynamic memory requested by our program is allocated
by the system from the memory heap. However, computer memory
is a limited resource, and it can be exhausted. Therefore, it is
important to have some mechanism to check if our request to
allocate memory was successful or not.
C++ provides two standard methods to check if the
allocation was successful:
One is by handling exceptions. Using this method an
exception of type bad_alloc is thrown when the allocation fails.
Exceptions are a powerful C++ feature explained later in these
tutorials. But for now you should know that if this exception is
thrown and it is not handled by a specific handler, the program
execution is terminated.
This exception method is the default method used by new,
and is the one used in a declaration like:
bobby = new int [5]; // if it fails an exception is thrown
The other method is known as nothrow, and what happens
when it is used is that when a memory allocation fails, instead of
throwing a bad_alloc exception or terminating the program, the
pointer returned by new is a null pointer, and the program continues
its execution.
This method can be specified by using a special object
called nothrow as parameter for new:
bobby = new (nothrow) int [5];
In this case, if the allocation of this block of memory failed,
the failure could be detected by checking if bobby took a null
pointer value:
int * bobby;
bobby = new (nothrow) int [5];
if (bobby == 0)
{
// error assigning memory. Take measures.
};
121
This nothrow method requires more work than the exception
method, since the value returned has to be checked after each and
every memory allocation, but I will use it in our examples due to its
simplicity. Anyway this method can become tedious for larger
projects, where the exception method is generally preferred. The
exception method will be explained in detail later in this tutorial.
122
cout << "You have entered: ";
for (n=0; n<i; n++)
cout << p[n] << ", ";
delete[] p;
}
return 0;
}
123
11
VIRTUAL FUNCTION
Unit Structure
11.1 Virtual Base Classes
11.2 Abstract Classes
11.3 Virtual Functions
11.4 Pure Virtual Functions
124
125
function of the base class can be declared with the keyword virtual.
The program with this change and its output is given below.
class Shape
{
public :
virtual void print()
{
cout << I am a Shape << endl;
}
};
class Triangle : public Shape
{
public :
void print()
{
cout << I am a Triangle << endl;
}
};
class Circle : public Shape
{
public :
void print()
{
cout << I am a Circle << endl;
}
};
void main()
{
Shape S;
Triangle T;
Circle C;
S.print();
T.print();
C.print();
Shape *ptr;
ptr = &S;
ptr -> print();
ptr = &T;
ptr -> print();
ptr = &C;
ptr -> print();
}
126
The output of the program is given below:
I am a Shape
I am a Triangle
I am a Circle
I am a Shape
I am a Triangle
I am a Circle
Now, the output of the derived classes are invoked correctly.
When declared with the keyword virtual, the compiler selects the
function to be invoked, based upon the contents of the pointer and
not the type of the pointer. This facility can be very effectively used
when many such classes are derived from one base class .
Member functions of each of these can be ,then, invoked using a
pointer to the base class .
127
{
Shape S;
Triangle T;
Circle C;
Shape *ptr;
ptr = &T;
ptr -> print();
ptr = &C;
ptr -> print();
}
The output of the program is given below:
I am a Triangle
I am a Circle
It can be seen from the above example that , the print()
function from the base class is not invoked at all . even though the
function is not necessary, it cannot be avoided, because , the
pointer of the class Shape must point to its members. Object
oriented programming has altered the program design process.
Exciting OOP concepts like polymorphism have given a big boost to
all this. Inheritance has further enhanced the language. This
session has covered some of the finer aspects of inheritance. The
next session will resolve some finer aspects of the language.
EXAMPLE:// virtual members
#include <iostream.h>
class CPolygon
{
protected:
int width, height;
public:
void set_values (int a, int b)
{
width=a; height=b;
}
virtual int area (void)
{
return (0);
}
};
class CRectangle: public CPolygon
128
{
public:
int area (void)
{
return (width * height);
}
};
class CTriangle: public CPolygon
{
public:
int area (void)
{
return (width * height / 2);
}
};
int main ()
{
CRectangle rect;
CTriangle trgl;
CPolygon poly;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
CPolygon * ppoly3 = &poly;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly3->set_values (4,5);
cout << ppoly1->area() << endl;
cout << ppoly2->area() << endl;
cout << ppoly3->area() << endl;
return 0;
}
The output is :
20
10
0
129
Now the three classes (CPolygon, CRectangle and
CTriangle) have the same members: width, height, set_values()
and area(). area() has been defined as virtual because it is later
redefined in derived classes. You can verify if you want that if you
remove this word (virtual) from the code and then you execute the
program the result will be 0 for the three polygons instead of
20,10,0. That is because instead of calling the corresponding area()
function for each object (CRectangle::area(), CTriangle::area() and
CPolygon::area(), respectively), CPolygon::area() will be called for
all of them since the calls are via a pointer to CPolygon.
Therefore what the word virtual does is to allow that a
member of a derived class with the same name as one in the base
class be suitably called when a pointer to it is used, as in the above
example. Note that in spite of its virtuality we have also been able
to declare an object of type CPolygon and to call its area() function,
that always returns 0 as the result.
130
12
STREAMS AND FILES
Unit Structure
12.1 Input Output With Files
12.2 Methods of Input and Output Classes
12.3 Text mode files
12.4 State flags
12.5 get and put stream pointers
12.6 Binary files
12.8 I/O Manipulators
131
Open a file
The first operation generally done on an object of one of
these classes is to associate it to a real file, that is to say, to open a
file. The open file is represented within the program by a stream
object (an instantiation of one of these classes) and any input or
output performed on this stream object will be applied to the
physical file.
In order to open a file with a stream object we use its
member function open():
void open (const char * filename, openmode mode);
where filename is a string of characters representing the
name of the file to be opened and mode is a combination of the
following flags:
ios::in Open file for reading
ios::out Open file for writing
ios::ate Initial position: end of file
ios::app Every output is appended at the end of file
ios::trunc If the file already existed it is erased
ios::binary Binary mode
These flags can be combined using bitwise operator OR: |.
For example, if we want to open the file "example.bin" in binary
mode to add data we could do it by the following call to functionmember open:
ofstream file;
file.open ("example.bin", ios::out | ios::app | ios::binary);
All of the member functions open of classes ofstream,
ifstream and fstream include a
default mode when opening files that varies from one to the other:
class
ofstream
ifstream
fstream
132
member function and has the same parameters as this. This way,
we could also have declared the previous object and conducted the
same opening operation just by writing:
ofstream file ("example.bin", ios::out | ios::app | ios::binary);
Both forms to open a file are valid.
You can check if a file has been correctly opened by calling
the member function is_open():
bool is_open();
that returns a bool type value indicating true in case that indeed
the object has been correctly associated with an open file or false
otherwise.
Closing a file
When reading, writing or consulting operations on a file are
complete we must close it so that it becomes available again. In
order to do that we shall call the member function close(), that is in
charge of flushing the buffers and closing the file. Its form is quite
simple:
void close ();
Once this member function is called, the stream object can
be used to open another file, and the file is available again to be
opened by other processes.
In case that an object is destructed while still associated with
an open file, the destructor automatically calls the member function
close.
133
2) get()
This form of get extracts a single character from the input
stream, that is, from the standard input, a file or a buffer. It does not
skip white space. It returns type int.
3) get(char &ch)
This form of get also extracts a single character from the
input stream, but it stores the value in the character variable
passed in as an argument.
4) get(char *buff, int buffsize, char delimiter='\n')
This form of get reads characters into the C-style buffer
passed as an argument buffsize characters are read, the delimiter
is encountered or an end of file is encountered. The '\n' is the new
line character. The delimiter is not read into the buffer but is instead
left in the input stream. It must be removed separately but using
either another get or an ignore. Because of this added step, this
form of get is a frequent source of errors and should be avoided.
Fortunately, another method shown below, getline, reads in the
delimiter as well and should be used in place of this form of get.
5) Getline
There are several useful forms of getline.
ignore(int count=1, int delim=traits_type::eof)
This method reads and discards "count" characters from the
input stream.
6) peek()
This method returns the next character from the input
stream, but does not remove it. It is useful to look ahead at what
the next character read will be.
7) putback(char &ch)
This method puts ch onto the input stream. The character in
ch will then be the next character read from the input stream.
8) unget()
This method puts the last read character back into the input
stream.
9) read(char *buff, int count)
This method is used to perform an unformatted read of count
bytes from the input stream into a character buffer.
The ofstream class has several useful methods for writing to
an output stream. An output stream is standard output (usually the
screen), a file or a buffer. These methods are also in the object
134
cout, which is used for standard output. The simplest way to
understand how to use these methods is by looking at a few
examples. Since we have seen the extraction, >>, and insertion, <<
in several lessons, let's look at the other methods. Getline, which is
very useful to read entire lines of text into a string.
Suppose we need to read a file and determine the number of
alphanumeric characters, the number of blanks and the number of
sentences. To determine the number of sentences we will count the
number of periods (dots). We will disregard newlines and tabs.
Here is a program that solves the problem.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int blank_count = 0;
int char_count = 0;
int sentence_count = 0;
char ch;
ifstream iFile("c:/lesson12.txt");
if (! iFile)
{
cout << "Error opening input file" << endl;
return -1;
}
while (iFile.get(ch))
{
switch (ch)
{
case ' ':
blank_count++;
break;
case '\n':
case '\t':
break;
case '.':
sentence_count++;
break;
default:
char_count++;
break;
}
135
}
cout << "There are " << blank_count << " blanks" <<
endl;
cout << "There are " << char_count << " characters"
<< endl;
cout << "There are " << sentence_count << "
sentences" << endl;
return 0;
}
As a second example, let's implement a program that will
copy the contents of one file to another. The program will prompt
the user for the input and output file names, and then copy.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char ch;
string iFileName;
string oFileName;
cout << "Enter the source file name: ";
cin >> iFileName;
cout << "Enter the destination file name: ";
cin >> oFileName;
ofstream oFile(oFileName.c_str());
ifstream iFile(iFileName.c_str());
//Error checking on file opens omitted for brevity.
while (iFile.get(ch))
{
oFile.put(ch);
}
return 0;
}
136
As in the following example, where we use the overloaded
insertion operator <<:
// writing on a text file
#include <fstream.h>
int main ()
{
ofstream examplefile ("example.txt");
if (examplefile.is_open())
{
examplefile << "This is a line.\n";
examplefile << "This is another line.\n";
examplefile.close();
}
return 0;
}
The output is :
This is a line.
This is another line.
Data input from file can also be performed in the same way that we
did with cin:
The output is :
This is a line.
This is another line.
This last example reads a text file and prints out its content on the
screen. Notice how
137
we have used a new member function, called eof that ifstream
inherits from class ios and that returns true in case that the end of
the file has been reached.
138
is an integer data type representing the current position of get
stream pointer (in case of tellg) or put stream pointer (in case of
tellp).
seekg() and seekp()
This pair of functions serve respectively to change the
position of stream pointers get and put. Both functions are
overloaded with two different prototypes:
seekg ( pos_type position );
seekp ( pos_type position );
Using this prototype the stream pointer is changed to an
absolute position from the beginning of the file. The type required is
the same as that returned by functions tellg and tellp.
seekg ( off_type offset, seekdir direction );
seekp ( off_type offset, seekdir direction );
Using this prototype, an offset from a concrete point
determined by parameter direction can be specified. It can be:
ios::beg Offset specified from the beginning of the stream
ios::cur Offset specified from the current position of the
stream pointer
ios::end Offset specified from the end of the stream
The values of both stream pointers get and put are counted
in different ways for text files than for binary files, since in text mode
files some modifications to the appearance of some special
characters can occur. For that reason it is advisable to use only the
first prototype of seekg and seekp with files opened in text mode
and always use nonmodified values returned by tellg or tellp. With
binary files, you can freely use all the implementations for these
functions. They should not have any unexpected behavior.
The following example uses the member functions just seen to
obtain the size of a binary file:
// obtaining file size
#include <iostream.h>
#include <fstream.h>
const char * filename = "example.txt";
int main ()
{
long l,m;
ifstream file (filename, ios::in|ios::binary);
l = file.tellg();
139
file.seekg (0, ios::end);
m = file.tellg();
file.close();
cout << "size of " << filename;
cout << " is " << (m-l) << " bytes.\n";
return 0;
}
The output is :
140
file.read (buffer, size);
file.close();
cout << "the complete file is in a buffer";
delete[] buffer;
return 0;
}
The output is :
141
state of iostream objects. These control how data is formatted.
They are defined in the include file, <ios>. It is not usually
necessary to explicitly include this file because it is included
indirectly via the use of other includes such as <iostream> or
<fstream>.
Let's see how some of these manipulators work in a simple
program.
Manipulator
Use
Boolalpha
Noboolalhpa
(default)
Dec (default)
Hex
Specifies that
hexadecimal.
Oct
Left
Right
Internal
Noshowbase
(default)
Showbase
Noshowpoint
(default)
Showpoint
noshowpos
(default)
Showpos
Skipws (default)
Noskipws
Fixed (default)
integers
are
displayed
in
142
Scientific
Nouppercase
(default)
Uppercase
143
cout << "Hex: " << hex << intValue << endl;
cout << "Turning showbase on" << showbase <<
endl;
cout << "Dec: " << dec << intValue << endl;
cout << "Octal: " << oct << intValue << endl;
cout << "Hex: " << hex << intValue << endl;
cout << "Turning showbase off" << noshowbase <<
endl;
cout << endl;
double doubleVal = 12.345678;
cout << "Floating Point Number" << endl;
cout << "Default: " << doubleVal << endl;
cout << setprecision(10);
cout << "Precision of 10: " << doubleVal << endl;
cout << scientific << "Scientific Notation: " <<
doubleVal << endl;
cout << uppercase;
cout << "Uppercase: " << doubleVal << endl;
cout << endl;
bool theBool = true;
cout << "Boolean" << endl;
cout << "Default: " << theBool << endl;
cout << boolalpha << "BoolAlpha set: " << theBool <<
endl;
cout << endl;
string myName = "John";
cout << "Strings" << endl;
cout << "Default: " << myName << endl;
cout << setw(35) << right << "With setw(35) and right:
"<< myName << endl;
cout.width(20);
cout << "With width(20): " << myName << endl;
cout << endl;
return 0;
}
144
13
TEMPLATES
Unit Structure :
13.1
13.2
Function templates
Class templates
145
function template GetMax returns the greater of two parameters of
this still-undefined type.
To use this function template we use the following format for the
function call:
function_name <type> (parameters);
For example, to call GetMax to compare two integer values of type
int we can write:
int x,y;
GetMax <int> (x,y);
When the compiler encounters this call to a template
function, it uses the template to automatically generate a function
replacing each appearance of myType by the type passed as the
actual template parameter (int in this case) and then calls it. This
process is automatically performed by the compiler and is invisible
to the programmer.
Here is the entire example:
// function template
#include <iostream>
using namespace std;
template <class T>
T GetMax (T a, T b)
{
T result;
result = (a>b)? a : b;
return (result);
}
int main ()
{
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax<int>(i,j);
n=GetMax<long>(l,m);
cout << k << endl;
cout << n << endl;
return 0;
}
The output is:
6
10
146
In this case, we have used T as the template parameter
name instead of myType because it is shorter and in fact is a very
common template parameter name. But you can use any identifier
you like.
In the example above we used the function template
GetMax() twice. The first time with arguments of type int and the
second one with arguments of type long. The compiler has
instantiated and then called each time the appropriate version of
the function.
As you can see, the type T is used within the GetMax()
template function even to declare new objects of that type:
T result;
Therefore, result will be an object of the same type as the
parameters a and b when the function template is instantiated with
a specific type.
In this specific case where the generic type T is used as a
parameter for GetMax the compiler can find out automatically which
data type has to instantiate without having to explicitly specify it
within angle brackets (like we have done before specifying <int>
and <long>). So we could have written instead:
int i,j;
GetMax (i,j);
Since both i and j are of type int, and the compiler can
automatically find out that the template parameter can only be int.
This implicit method produces exactly the same result:
// function template II
#include <iostream>
using namespace std;
template <class T>
T GetMax (T a, T b)
{
return (a>b?a:b);
}
int main ()
{
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax(i,j);
n=GetMax(l,m);
cout << k << endl;
147
cout << n << endl;
return 0;
}
The output is :
6
10
Notice how in this case, we called our function template
GetMax() without explicitly specifying the type between anglebrackets <>. The compiler automatically determines what type is
needed on each call.
Because our template function includes only one template
parameter (class T) and the function template itself accepts two
parameters, both of this T type, we cannot call our function
template with two objects of different types as arguments:
int i;
long l;
k = GetMax (i,l);
This would not be correct, since our GetMax function
template expects two arguments of the same type, and in this call
to it we use objects of two different types.
We can also define function templates that accept more than
one type parameter, simply by specifying more template
parameters between the angle brackets. For example:
template <class T, class U>
T GetMin (T a, U b)
{
return (a<b?a:b);
}
In this case, our function template GetMin() accepts two
parameters of different types and returns an object of the same
type as the first parameter (T) that is passed. For example, after
that declaration we could call GetMin() with:
int i,j;
long l;
i = GetMin<int,long> (j,l);
or simply:
i = GetMin (j,l);
148
even though j and l have different types, since the compiler can
determine the appropriate instantiation anyway.
149
a=first;
b=second;
}
T getmax ();
};
template <class T>
T mypair<T>::getmax ()
{
T retval;
retval = a>b? a : b;
return retval;
}
int main ()
{
mypair <int> myobject (100, 75);
cout << myobject.getmax();
return 0;
}
The output is:
100
150
14
EXCEPTIONS
Unit Structure:
14.1
14.2
Exceptions
Exception specifications
14.1 EXCEPTIONS
Exceptions provide a way to react to exceptional
circumstances (like runtime errors) in our program by transferring
control to special functions called handlers.
To catch exceptions we must place a portion of code under
exception inspection. This is done by enclosing that portion of code
in a try block. When an exceptional circumstance arises within that
block, an exception is thrown that transfers the control to the
exception handler. If no exception is thrown, the code continues
normally and all handlers are ignored.
A exception is thrown by using the throw keyword from
inside the try block. Exception handlers are declared with the
keyword catch, which must be placed immediately after the try
block:
// exceptions
#include <iostream>
using namespace std;
int main ()
{
try
{
throw 20;
}
catch (int e)
{
cout << "An exception occurred. Exception Nr.
" << e << endl;
}
return 0;
}
151
The output is :
An exception occurred. Exception Nr. 20
The code under exception handling is enclosed in a try block. In
this example this code simply throws an exception:
throw 20;
A throw expression accepts one parameter (in this case the
integer value 20), which is passed as an argument to the exception
handler.
The exception handler is declared with the catch keyword.
As you can see, it follows immediately the closing brace of the try
block. The catch format is similar to a regular function that always
has at least one parameter. The type of this parameter is very
important, since the type of the argument passed by the throw
expression is checked against it, and only in the case they match,
the exception is caught.
We can chain multiple handlers (catch expressions), each
one with a different parameter type. Only the handler that matches
its type with the argument specified in the throw statement is
executed.
If we use an ellipsis (...) as the parameter of catch, that
handler will catch any exception no matter what the type of the
throw exception is. This can be used as a default handler that
catches all exceptions not caught by other handlers if it is specified
at last:
try
{
// code here
}
catch (int param)
{
cout << "int exception";
}
catch (char param)
{
cout << "char exception";
}
catch (...)
{
cout << "default exception";
}
152
In this case the last handler would catch any exception
thrown with any parameter that is neither an int nor a char.
After an exception has been handled the program execution
resumes after the try-catch block, not after the throw statement!.
It is also possible to nest try-catch blocks within more
external try blocks. In these cases, we have the possibility that an
internal catch block forwards the exception to its external level. This
is done with the expression throw; with no arguments. For example:
try
{
try
{
// code here
}
catch (int n)
{
throw;
}
}
catch (...)
{
cout << "Exception occurred";
}
153
154
All exceptions thrown by components of the C++ Standard
library throw exceptions derived from this std::exception class.
These are:
Exception
Description
bad_alloc
bad_cast
bad_exception
bad_typeid
thrown by typeid
For example, if we use the operator new and the memory cannot
be allocated, an exception of type bad_alloc is thrown:
try
{
int * myarray= new int[1000];
}
catch (bad_alloc&)
{
cout << "Error allocating memory." << endl;
}
It is recommended to include all dynamic memory allocations
within a try block that catches this type of exception to perform a
clean action instead of an abnormal program termination, which is
what happens when this type of exception is thrown and not
caught. If you want to force a bad_alloc exception to see it in
action, you can try to allocate a huge array; On my system, trying to
allocate 1 billion ints threw a bad_alloc exception.
Because bad_alloc is derived from the standard base class
exception, we can handle that same exception by catching
references to the exception class:
// bad_alloc standard exception
#include <iostream>
#include <exception>
using namespace std;
155
int main ()
{
try
{
int* myarray= new int[1000];
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() <<
endl;
}
return 0;
}
156
15
THE C++ STANDARD TEMPLATE
LIBRARY
Unit Structure :
15.1
15.2
15.3
15.4
15.5
15.6
15.7
15.8
15.9
15.10
Introduction
Standard Templates
Stacks
Older Stacks
Queues
Older Queues
Lists
Vectors
Iterators and Containers
Algorithms
15.1 INTRODUCTION
This is a short primer on the STL or "Standard Template
Library" for the programming language C++ as defined in the 1997
standard. The STL is a collection C++ libraries that allow you to use
several well known kinds of data structures with out having to
program them. They are designed so that the code runs efficiently.
The compiler does most of the work of generating the efficient
implementations. The libraries include a large number of
possibilities. we describe some of things you can do with the STL
versions of stacks, queues, vectors, and lists. I define some
important and useful ideas in the Glossary below. The is a table
summarizing the methods used with stacks, queues, vectors and
lists at Summary below.For each kind of data structure I give
working examples of how to declare, access and use objects of that
type.
157
Library
Description
<vector>
<list>
<stack>
<queue>
<deque>
<bitset>
<set>
<map>
15.3 STACKS
Stacks are only accessed at their top. To be able to use STL
stacks in a file of C++ source code or a header file add
#include <stack>
at the beginning of the file.
Suppose that T is any type or class - say an int, a float, a struct, or
a class, then
stack<T> s;
declares a new and empty stack called s. Given s you can:
1) test to see if it is empty:
s.empty()
2) find how many items are in it:
s.size()
3) push a t of type T onto the top:
s.push(t)
4) pop the top off s:
s.pop()
158
5) get the top item of s
s.top()
6) change the top item:
s.top() = expression.
159
15.5 QUEUES
Queues allow data to be added at one end and taken out of
the other end. To be able to use STL queues add this before you
start using them in your source code:
#include <queue>
Suppose that T is any type or class - say an int, a float, a struct, or
a class, then
1) declares a new and empty queue called q. Given an
object q:
queue<T> q;
2) test to see if q is empty:
q.empty()
3) find how many items are in q:
q.size()
4) push a t:T onto the end of q:
q.push(t)
5) pop the front of q off q:
q.pop()
6) get the front item of q:
q.front()
7) change the front item:
q.front() = expression.
8) get the back item of q:
q.back()
9) change the back item:
q.back() = expression.
Example of putting three items into a queue and then taking them
off the queue.
#include <iostream.h>
#include <list>
#include <queue>
int main()
{
160
queue<char> q;
q.push('a');
q.push('b');
q.push('c');
cout << q.front();
q.pop();
cout << q.front();
q.pop();
cout << q.front();
q.pop();
}
15.7 LISTS
Lists are good when data needs to be reorganized a lot. To
be able to use STL lists add this before you start using them in your
source code:
161
#include <list>
Suppose that T is any type or class - say an int, a float, a struct, or
a class, then
1) To declares a new and empty list called l. Given an object l:
list<T> l;
2) test to see if l is empty:
l.empty()
3) find how many items are in l:
l.size()
4) push a t:T onto the end of l:
l.push_back(t)
5) pop the last off l:
l.pop_back()
6) push a t:T onto the start of l:
l.push_front(t)
7) pop the front of l off l:
l.pop_front()
8) get the front item of l:
l.front()
9) change the front item:
l.front() = expression.
10) get the back item of l:
l.back()
11) change the back item:
l.back() = expression.
12) Sort the list:
l.sort()
13) Clear the list:
l.clear()
14) Merge in a sorted list into a sorted list:
l.merge(list_of_sorted_elements)
162
15) Reverse the list:
l.reverse()
16) Assign a copy of q1 to q:
q = q1
[ Lists and Iterators ]
Example of List Processing
This uses a utility function 'print' that is implemented below [ An
Example of Iterating Through a List ]
Building and Sorting a List
//Using a list to sort a sequence of 9 numbers.
#include <iostream.h>
#include <list>
// #include <algorithm>
void print(list<int> a);//utility function print lists of ints
int main()
{
list<int> a;
//Put 9,8,7,6,5,4,3,2,1 onto the list
for(int i=0; i<9;++i)
a.push_back(9-i);// put new element after all the others
print(a); //here the list contains (9,8,7,6,5,4,3,2,1)
a.sort();//in the <list> library!
print(a); //here the list contains (1,2,3,4,5,6,7,8,9)
}
. . . . . . . . . ( end of section Lists) <<Contents | End>>
15.8 VECTORS
Vectors are good when we have an unknown sequence of
items to store but we want to access the by their sequence
numbers. To be able to use STL vectors add this before you start
using them in your source code:
#include <vector>
Suppose that T is any type or class - say an int, a float, a struct, or
a class, then
1) to declares a new and empty vector called v. Given object v
declare like the above:
vector<T> v;
163
2) test to see if v is empty:
v.empty()
3) find how many items are in v:
v.size()
4) push a t:T onto the end of v:
v.push_back(t)
5) pop the front of v off v:
v.pop_back()
6) get the front item of v:
v.front()
7) change the front item:
v.front() = expression.
8) get the back item of v:
v.back()
9) change the back item:
v.back() = expression.
10) Access the i'th item (0<=i<size()) without checking to see if it
exists:
v[i]
11) Access the i'th item safely:
v.at(i)
12) Assign a copy of v1 to v:
v = v1
164
const int MAX = 10;
float a[MAX];
...
for(int i=0; i<10; ++i)
process(a[i]);
...
Lists, Vectors, Stacks, Queues, etc are all Containers.
C arrays were designed so that they could be accessed by using a
variable that stores the address of an item. These variables are
called pointers. They are used like this with an array:
for(float *p=a; p!=p+MAX; ++p)
process(*p);
...
Iterators:
Items in Containers are referred to be special objects called:
iterators. They are generalization of C's pointers. With an iterator
class Iter you can process each item in a vector or a list by similar
code:
for( Iter p=c.begin(); p!=c.end(); ++p)
process(*p);
All Containers C in the STL have a number of iterator objects.
Container class C has an iterator called
C::iterator
For any type T, list<T> and vector<T> are Containers. So there
are iterator classes called list<T>::iterator and they are used like
this:
for( list<T>::iterator p=c.begin(); p!=c.end(); ++p)
process(*p);
Vector iterators have type
vector<T>::iterator
and used like this:
for( vector<T>::iterator p=c.begin(); p!=c.end(); ++p)
process(*p);
If you change your choice from a vector to a list then the code is
almost identical. This makes your code easier to modify.
For any container class C of objects type T and any object c of
type C:
165
Declare an iterator for container of type C.
C::iterator p
Move iterator p onto the next object in c(if any!).
++p
The value selected by p.
*p
The iterator that refers to the first item in c
c.begin()
The iterator that refers to one beyond c.
c.end()
Declare an iterator for container of type C and set to the start of c.
C::iterator
p
=
c.begin();
Test to see if iterator p has come to the end of object c:
p != c.end();
assign p1 to p -- afterwards both refer to same item
p = p1;
166
cout <<" "<< *p<<endl; // p refers to the 'o' in
('o', 'a', 't')
print(l);
l.insert(p, 'c');
// l is now ('c', 'o', 'a', 't') and p still refers to 'o'
cout <<" "<< *p<<endl;
print(l);
l.erase(p);
cout <<" "<< *p<<endl; // p refers to an 'o' but it
is not in l!
print(l);
l.erase(l.begin()); //removes front of l
print(l);
}
Ranges:
A pair of iterators describes a range of items in their container.
The items in the range start with the first iterator in the pair. The
range has all the following items up to just before the item referred
to by the last iterator of the pair.
Suppose that first and last form a range and it is an iterator then:
for( it=first; it != last; it++)
will refer to each element in the range [first..last) in turn. In the
body of the for loop the value of the element is *it.
Given a container c, then c.begin() and c.end() form a range.
An Example of Iterating Through a List
void print( list<int> a)
{
for(list<int>::iterator ai=a.begin(); ai!=a.end(); ++ai)
cout << *ai << " ";
cout << endl;
cout << "----------------"<<endl;
}
15.10 ALGORITHMS
Ranges and Iterators are used several useful functions and
algorithms in the STL. Suppose you have a type or class of data
called T and in a program are working with a vector v of type
vector<T> then
vector<T>::iterator
is the class of suitable iterators. Here are two useful values:
v.begin()
v.end()
167
These always form a range of all the items in v from the front up to
and including the back. You can sort a vector v simply by writing:
sort(c.begin(), c.end());
Example : Sorting a vector with 9 integers
#include <iostream.h>
#include <vector>
#include <algorithm>
void print( vector<int> ) ;//utility function outputs a $container
int main()
{
vector<int> a;
// Place 9,8,7,6,5,4,3,2,1 into the vector
for(int i=0; i<9;++i)
a.push_back(9-i);// put new element after all the others
print(a); // elements of a are (9,8,7,6,5,4,3,2,1)
sort( a.begin(), a.end() ); //in the STL <algorithm> library
print(a); // elements are nor in order.
}
void print( vector<int> a)
{
for(vector<int>::iterator ai=a.begin(); ai!=a.end(); ++ai)
cout << *ai << " ";
cout << endl;
cout << "----------------"<<endl;
}
. . . . . . . . . ( end of section Iterators) <<Contents | End>>
Summary
Templat
e
push/pop
Commo
n
items
Extras
stack
pop(),push(T)
empty(),
size()
top()
queue
pop(),push(T)
empty(),
size()
front(),back(
)
vector
push_back(T
), pop_back()
empty(),
size()
front(),
back()
[int], at(int), =
list
push_back(),
pop_back(),
push_front(T)
, pop_front()
empty(),
size()
front(),
back()
sort(), clear(),
reverse(),
merge(l),at(int
), =
168
Note:
You must always #include headers if you use the words: vector,
list,string,queue, or stack in your program or in a header file.
Their must be a space between the two ">" signs below:
stack< vector< T > > s;
If the standard <list> and <vector> is not found then you are using
an older C++ compiler.
On some older compilers and currant libraries when you need a
<string> as well as either <list> or <vector> you need to
#include <string>
before including the list or vector rather in the reverse order! Older
string library appear to define some special versions of vector and
list operators and the older compilers can not make up its mind
which to use.
169
EXERCISE
Exercise : 1
1. It has been said that C++ sits at the center of the modern
programming universe. Explain this statement.
2. A C++ compiler produces object code that is directly executed by
the computer. True or false?
3. What are the three main principles of object-oriented
programming?
4. Where do C++ programs begin execution?
5. What is a header?
6. What is <iostream>? What does the following code do?
#include <iostream>
7. What is a namespace?
8. What is a variable?
9. Which of the following variable names is/are invalid?
a. count
b. _count
c. count27
d. 67count
e. if
170
16. Write a program that averages the absolute value of five values
entered by the user. Display the result.
Exercise: 2
1. What type of integers are supported by C++?
2. By default, what type is 12.2?
3. What values can a bool variable have?
4. What is the long integer data type?
5. What escape sequence produces a tab? What escape sequence
rings the bell?
6. A string is surrounded by double quotes. True or false?
7. What are the hexadecimal digits?
8. Show the general form for initializing a variable when it is
declared.
9. What does the % do? Can it be used on floating-point values?
10. Explain the difference between the prefix and postfix forms of
the increment operator.
11. Which of the following are logical operators in C++?
a. &&
b. ##
c. ||
d. $$
e. !
Exercise: 3
1. Write a program that reads characters from the keyboard until a
$ is typed. Have the program count the number of periods. Report
the total at the end of the program.
2. In the switch, can the code sequence from one case run into the
next? Explain.
171
3. Show the general form of the if-else-if ladder.
4. Show the for statement for a loop that counts from 1000 to 0
by 2.
5. Explain what break does.
6. In the following fragment, after the break statement executes,
what is displayed?
7. The increment expression in a for loop need not always alter the
loop control variable by a fixed amount. Instead, the loop control
variable can change in any arbitrary way. Using this concept, write
a program that uses a for loop to generate and display the
progression 1, 2, 4, 8, 16, 32, and so on.
8. The ASCII lowercase letters are separated from the uppercase
letters by 32. Thus, to convert a lowercase letter to uppercase,
subtract 32 from it. Use this information to write a program that
reads characters from the keyboard. Have it convert all lowercase
letters to uppercase, and all uppercase letters to lowercase,
displaying the result. Make no changes to any other character.
Have the program stop when the user enters a period. At the end,
have the program display the number of case changes that have
taken place.
9. What is C++s unconditional jump statement?
Exercise: 4
1. Show how to declare a short int array called hightemps that is 31
elements long.
2. In C++, all arrays begin indexing at ________.
3. Write a program that searches an array of ten integers for
duplicate values. Have the program
display each duplicate found.
4. What is a null-terminated string?
5. Write a program that prompts the user for two strings and then
compares the strings for
equality, but ignores case differences. Thus, ok and OK will
compare as equal.
6. When using strcat( ), how large must the recipient array be?
7. In a multidimensional array, how is each index specified?
172
8. Show how to initialize an int array called nums with the values 5,
66, and 88.
9. What is the principal advantage of an unsized array declaration?
10. What is a pointer? What are the two pointer operators?
11. Can a pointer be indexed like an array? Can an array
beaccessed through a pointer?
12. Write a program that counts the uppercase letters in a string.
Have it display the result.
13. What is it called when one pointer points to another pointer?
14. Of what significance is a null pointer in C++?
Exercise : 5
1. Show the general form of a function.
2. Create a function called hypot( ) that computes the length of the
hypotenuse of a right triangle given the lengths of the two opposing
sides. Demonstrate its use in a program. For this problem, you will
need to use the sqrt( ) standard library function, which returns the
square root of its argument. It has this prototype:
double sqrt(double val); It uses the header <cmath>.
3. Can a function return a pointer? Can a function return an array?
4. Create your own version of the standard library function strlen( ).
Call your version mystrlen( ), and demonstrate its use in a program.
5. Does a local variable maintain its value between calls to the
function in which it is declared?
6. Give one benefit of global variables. Give one disadvantage.
7. Create a function called byThrees( ) that returns a series of
numbers, with each value 3 greater than the preceding one. Have
the series start at 0. Thus, the first five numbers returned by
byThrees( ) are 0, 3, 6, 9, and 12. Create another function called
reset( ) that causes byThrees( ) to start the series over again from
0. Demonstrate your functions in a program. Hint: You will need to
use a global variable.
8. Write a program that requires a password that is specified on the
command line. Your program doesnt have to actually do anything
173
except report whether the password was entered correctly or
incorrectly.
9. A prototype prevents a function from being called with the
improper number of arguments. True or false?
10. Write a recursive function that prints the numbers 1 through 10.
Demonstrate its use in a program.
Exercise : 6
1. What are the two ways that an argument can be passed to a
subroutine?
2. In C++, what is a reference? How is a reference parameter
created?
3. Given this fragment,
int f(char &c, int *i); // ... char ch = 'x'; int i = 10; show how to call f( )
with the ch and i.
4. Create a void function called round( ) that rounds the value of its
double argument to the nearest whole value. Have round( ) use a
reference parameter and return the rounded result in this
parameter. You can assume that all values to be rounded are
positive. Demonstrate round( ) in a program. To solve this problem,
you will need to use the modf( ) standard library function, which is
shown here:
double modf(double num, double *i);
The modf( ) function decomposes num into its integer and fractional
parts. It returns the fractional portion and places the integer part in
the variable pointed to by i. It requires the header <cmath>.
5. Modify the reference version of swap( ) so that in addition to
exchanging the values of its arguments, it returns a reference to the
smaller of its two arguments. Call this function min_swap( ).
6. Why cant a function return a reference to a local variable?
7. How must the parameter lists of two overloaded functions differ?
8. In Project 6-1, you created a collection of print( ) and println( )
functions. To these functions, add a second parameter that
specifies an indentation level. For example, when print( ) is called
like this,
174
print("test", 18); output will indent 18 spaces and then will display
the string test. Have the indentation parameter default to 0 so that
when it is not present, no indentation occurs.
9. Given this prototype,
bool myfunc(char ch, int a=10, int b=20); show the ways that
myfunc( ) can be called.
10. Briefly explain how function overloading can introduce
ambiguity.
Exercise : 7
1. Show how to declare an int variable called test that cant be
changed by the program. Give it an initial value of 100.
2. The volatile specifier tells the compiler that a variable might be
changed by forces outside the program. True or false?
3. In a multifile project, what specifier do you use to tell one file
about a global variable declared in another file?
4. What is the most important attribute of a static local variable?
5. Write a program that contains a function called counter( ), which
simply counts how many times it is called. Have it return the current
count.
6. How does & differ from &&?
7. What does this statement do? x *= 10;
8. Using the rrotate( ) and lrotate( ) functions from Project 7-1, it is
possible to encode and decode a string. To code the string, leftrotate each letter by some amount that is specified by a key. To
decode, right-rotate each character by the same amount. Use a key
that consists of a string of characters. There are many ways to
compute the number of rotations from the key. Be creative. The
solution shown in the online answers is only one of many.
9. On your own, expand show_binary( ) so that it shows all bits
within an unsigned int rather than just the first eight.
Exercise : 8
1. What is the difference between a class and an object?
2. What keyword is used to declare a class?
175
3. What does each object have its own copy of?
4. Show how to declare a class called Test that contains two private
int variables called count and max.
5. What name does a constructor have? What name does a
destructor have?
6. Given this class declaration:
class sample
{int i;
public:
sample int x {i = x;}
//..
};
show how to declare a Sample object that initializes i to the value
10.
7. When a member function is declared within a class declaration,
what optimization automatically takes place?
8. Create a class called Triangle that stores the length of the base
and height of a right triangle in two private instance variables.
Include a constructor that sets these values. Define two functions.
The first is hypot( ), which returns the length of the hypotenuse. The
second is area( ), which returns the area of the triangle.
9. Expand the Help class so that it stores an integer ID number that
identifies each user of the class. Display the ID when a help object
is destroyed. Return the ID when the function getID( ) is called.
Exercise: 9
1. What is a copy constructor and when is it called? Show the
general form of a copy constructor.
2. Explain what happens when an object is returned by a function.
Specifically, when is its destructor called?
3. Given this class:
class T {
int i,j;
public:
int sum(){return i+j;}
};
show how to rewrite sum( ) so that it uses this.
176
4. What is a structure? What is a union?
5. Inside a member function, to what does *this refer?
6. What is a friend function?
7. Show the general form used for overloading a binary member
operator function.
8. To allow operations involving a class type and a built-in type,
what must you do?
9. Can the ? be overloaded? Can you change the precedence of an
operator?
10. For the Set class developed in Project 9-1, define < and > so
that they determine if one set is a subset or a superset of another
set. Have < return true if the left set is a subset of the set on the
right, and false otherwise. Have > return true if the left set is a
superset of the set on the right, and false otherwise.
11. For the Set class, define the & so that it yields the intersection
of two sets.
12. On your own, try adding other Set operators. For example, try
defining | so that it yields the symmetric difference between two
sets. The symmetric difference consists of those elements that the
two sets do not have in common.
Exercise: 10
1. A class that is inherited is called a _______ class. The class that
does the inheriting is called a ________ class.
2. Does a base class have access to the members of a derived
class? Does a derived class have access to the members of a base
class?
3. Create a derived class of TwoDShape called Circle. Include an
area( ) function that computes the area of the circle.
4. How do you prevent a derived class from having access to a
member of a base class?
5. Show the general form of a constructor that calls a base class
constructor.
177
6. Given the following hierarchy:
Class alpha{...
Class beta :public alpha{..
Class gamma : public beta{...
in what order are the constructors for these classes called when a
Gamma object is instantiated?
7. How can protected members be accessed?
8. A base class pointer can refer to a derived class object. Explain
why this is important as it relates to function overriding.
9. What is a pure virtual function? What is an abstract class?
10. Can an object of an abstract class be instantiated?
11. Explain how the pure virtual function helps implement the one
interface, multiple methods aspect of polymorphism.
Exercise : 11
1. What are the four predefined streams called?
2. Does C++ define both 8-bit and wide-character streams?
3. Show the general form for overloading an inserter.
4. What does ios::scientific do?
5. What does width( ) do?
6. An I/O manipulator is used within an I/O expression. True or
false?
7. Show how to open a file for reading text input.
8. Show how to open a file for writing text output.
9. What does ios::binary do?
10. When the end of the file is reached, the stream variable will
evaluate as false. True or false?
11. Assuming a file is associated with an input stream called strm,
show how to read to the end of the file.
12. Write a program that copies a file. Allow the user to specify the
name of the input and output file on the command line. Make sure
that your program can copy both text and binary files.
178
13. Write a program that merges two text files. Have the user
specify the names of the two files on the command line in the order
they should appear in the output file. Also, have the user specify
the name of the output file. Thus, if the program is called merge,
then the following command line will merge the files MyFile1.txt and
MyFile2.txt into Target.txt: merge MyFile1.txt MyFile2.txt Target.txt
14. Show how the seekg( ) statement will seek to the 300th byte in
a stream called MyStrm.
Exercise : 12
1. Explain how try, catch, and throw work together to support
exception handling.
2. How must the catch list be organized when catching exceptions
of both base and derived classes?
3. Show how to specify that a MyExcpt exception can be thrown out
of a function called func( ) that returns void.
4. Define an exception for the generic Queue class shown in
Project 12-1. Have Queue throw this exception when an overflow or
underflow occurs. Demonstrate its use.
5. What is a generic function, and what keyword is used to create
one?
6. Create generic versions of the quicksort( ) and qs( ) functions
shown in Project 5-1. Demonstrate their use.
7. Using the Sample class shown here, create a queue of three
Sample objects using the generic Queue shown in Project 12-1:
class sample
{
int id;
public :
sample()
{ id =0; }
sample(int x){id=x;}
void show(){cout<<id<<endl;}
};
8. Rework your answer to question 7 so that the Sample objects
stored in the queue are dynamically allocated.
9. Show how to declare a namespace called RobotMotion.
10. What namespace contains the C++ standard library?
179
11. Can a static member function access the non-static data of a
class?
12. What operator obtains the type of an object at runtime?
13. To determine the validity of a polymorphic cast at runtime, what
casting operator do you use?
14. What does const_cast do?
15. On your own, try putting the Queue class from Project 12-1 in
its own namespace called QueueCode, and into its own file called
Queue.cpp. Then rework the main( ) function so that it uses a using
statement to bring QueueCode into view.
16. Continue to learn about C++. It is the most powerful computer
language currently available. Mastering it puts you in an elite
league of programmers.