Sie sind auf Seite 1von 36

Pointers and Streams 177

Unit 8: Pointers and Streams

8.1 Introduction
8.2 C++ Memory Map
8.3 Dynamic and Static Allocation of Memory
8.3.1 Static Memory Allocation
8..3.2 Dynamic Memory Allocation
8.3.3 Free Store
8.4 Pointer Variables
8.4.1 The Pointer Operators
8.5 Pointer Expressions
8.6 Pointers and Arrays
8.7 Pointers to Functions
8.8 Arrays of Function Pointer
8.9 Pointers and Arrays
8.10 Deleting Variables
8.11 The this Pointer
8.12 Polymorphism
8.13 Virtual Functions
8.13.1 Virtual Member Functions Accessed With Pointers
8.14 Template
8.15 Streams
8.15.1 C++ Streams
8.16 Inheritance
8.16.1 Access Control and Inheritance
8.16.2 Type of Inheritance
8.16.3 Single Level Inheritance
8.16.4 Multi Level Inheritance
8.16.5 Multiple Inheritances
8.17 Summary
8.18 Check Your Progress
8.19 Questions and Exercises
8.20 Key Terms
8.21 Further Readings

Amity Directorate of Distance & Online Education

178 Object Oriented Programming Concept Using C++

Notes Objectives
After studying this unit, you should be able to:
z Understand pointers.
z Discuss the concept of virtual function.
z Explain the concept of templates and polymorphism.
z Understand the concept of inheritance and streams..

8.1 Introduction
A pointer is a variable that holds a memory address. This address is the location of
other objects (typically another variable) in memory. For example, if one variable
contains the address of another variable, the first variable is said to point to the second.

8.2 C++ Memory Map

Since pointers have a close relation with memory as they store address of a memory
location and also they facilitate C++’s dynamic memory allocation routines, we must
understand the way C++ organizes memory for its programs. After compiling a program,
C++ creates four logically distinct regions of memory that are used for four distinct
specific functions. One region in the memory holds the compiled code of the program.
Every instruction and every function of the program starts at a particular address. The
next region is the memory area where the global variables of the program are stored.
Global variables remain in the memory as long as program continues. The third region
known as Stack, is used for great many things while your program executes. The stack
is used for holding the return addresses at function calls, arguments passed to the
functions, and local variables for functions. The local variables remain in memory as
long as the function continues and after that they are erased from the memory. The
stack also stores the current state of the CPU. The Heap memory area is a region of
free memory from which chunks of memory are allocated via C++’s dynamic memory
allocation functions.

8.3 Dynamic and Static Allocation of Memory

The golden rule of computers states that anything and everything (data or instruction)
that needs to be processed must be loaded into internal memory before its processing
takes place. Therefore, every data and instruction that is being executed must be
allocated some area in the main (internal) memory. The main (internal) memory is
allocated in two ways: statically and dynamically.

8.3.1 Static Memory Allocation

When the amount of memory to be allocated is known beforehand and the memory is
allocated during compilation itself, it is referred to as static memory allocation. For
instance, when you declare a variable as follows:
short avar ;
then, in such a case the computer knows that what the length of a short variable is.
Generally, it is 2 bytes. So, a chunk of 2 bytes internal memory will be allocated variable
avar during compilation itself. Thus, it is an example of static memory allocation.

8.3.2 Dynamic Memory Allocation

Amity Directorate of Distance & Online Education

Pointers and Streams 179
When the amount of memory to be allocated is not known beforehand rather it is
required to allocate (main) memory as and when required during runtime (when the
program is actually executing) itself, then, the allocation of memory at run time is Notes
referred to as dynamic memory allocation.
C++ offers two operators for dynamic memory allocation – new and delete. The
operator new allocates the memory dynamically and returns a pointer storing the
memory address of the allocated memory. The operator delete deallocates the memory
(the reverse of new) pointed by the given pointer. More about dynamic allocation and
the operators new and delete, we’ll learn in the coming sections in this chapter.
8.3.3 Free Store
Every program is provided with a pool of unallocated heap memory that it may utilize
during execution. This pool of available memory is referred to as the program’s free
FREE STORE is a pool of unallocated heap memory given to a program that is used by
the program for dynamic allocation during execution.
The allocated free store memory is unnamed. Objects allocated on the free store are
manipulated indirectly through pointers. Another aspect of free store is that the
allocated memory is uninitialized. The programmer is responsible for initializing it
The free store memory is allocated through the use of new operator and deallocated
through delete operator.
Free store memory is (dynamically) allocated during run-time and static memory
allocation takes place during compile-time. An object’s life time i.e., as long as the
object remains in the memory during the program execution, is known as an object’s
extent. Global variables or the variables having file scope are spoken of as having static
extent. That means, the storage is allocated to them before the program’s start-up and
remains bound to the variable throughout the program execution.
Variables having local scope are spoken of an having local extent. Storage is allocated
to them at each entry into the local scope (i.e., as soon as their local scope starts); and
on exit (from the local scope), the storage is freed up. A local variable with static
specifier has static extent.
Objects that are dynamically allocated on free store as spoken of as having dynamic
The storage allocated through the use of operator new remains bound
to the object untill it is explicitly deallocated by the programmer.
That means, the dynamically allocated objects do not have any predefined scope. They
remain in memory untill explicitly removed using delete.

8.4 Pointer Variables

If a variable is going to hold a pointer, it must be declared as such. A pointer declaration
consists of a base type, an *, and the variable name. The general form for declaring a
pointer variable is
type * name;
where type is the base of the pointer and may be any valid type. The name of the
pointer variable is specified by name.
The base type of the pointer defines what type of variables the pointer can point to.
Technically, any type of pointer can point anywhere in memory. However, all pointer
arithmetic is done relative to its base type, so it is important to declare the pointer
Amity Directorate of Distance & Online Education
180 Object Oriented Programming Concept Using C++

8.4.1 The Pointer Operators

Notes We will take a closer look at the Pointer operators here, beginning with a review of their
basic operation. There are two special pointer operators: * and &. The & is a unary
operator that returns the memory address of its operand. (Remember, a unary operator
only requires one operand.)
For example,
m = &count;
place into m the memory address of the variable count. This address is the computer's
internal location of the variable. It has nothing to do with the value of count. You can
think of & as returning "the address of." Therefore, the preceding assignment statement
means "m receives the address of count".
To understand the above assignment better, assume that the variable count uses
memory location 2000 to store its value. Also assume that count has a value of 100.
Then, after the preceding assignment, m will have the value 2000.
The second pointer operator, *, is the complement of &. It is a unary operator that
returns the value located at the address that follows. For example, if m contains the
memory address of the variable count,
q = *m;
places the value of count into q. Thus, q will have the value 100 because 100 is stored
at location 2000, which is the memory address that was stored in m. You can think of
*ac " at address." In this case, the preceding statement means "q receives the value at
address m".
Both & and * have a higher precedence than all other arithmetic operators except the
unary minus, with which they are equal.
You must make sure that your 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
any address that it holds point to an integer variable – whether it actually does or not.
Because C allows you to assign any address to a pointer variable, the following code
fragment compiles with no error messages (or only warnings, depending upon your
compiler), but does not produce the desired result:
# include <stdio.h>
int main (void)
double x = 100.1, y;
int *p;
/* The next statement causes p (which is an integer
pointer) to point to a double.*/
p = &x;
/* The next statement does not operate as expected.
y = *p;
printf("%i", y); /* won't output 100.1 */
return 0;

Amity Directorate of Distance & Online Education

Pointers and Streams 181
This will not assign the value of x to y. Because p is declared as an integer pointer, only
or 4 bytes of information will be transferred to y, not the 8 bytes that normally make up a
double. Notes
In C++, it is illegal to convert one type of pointer into another without the use of an
explicit type cast. For this reason, the preceding program will not even compile if you try
to compile it as a C++ (rather than as a C) program. However, the type of error
described can still occur in C++ in a more roundabout manner.

8.5 Pointer Expressions

In general, expressions involving pointers conform to the same rules as other
expressions. This section examines a few special aspects of pointer expressions.
Pointer Assignments
As with any variable, you may use a pointer on the right-hand side of an assignment
statement to assign its value to another pointer. For example
# include <stdio.h>
int main (void)
int x;
int *pl, *p2;
p1 = &x;
p2 = p1;
printf ("%p", p2); /* print the address of x, not x's
value! */
return 0;
Both p1 and p2 now point to x. The address of x is displayed by using the %p printf ()
format specifier, which causes printf() to display an address in the format used by the
host computer.
Pointer Arithmetic
There are only two arithmetic operations that you may use on pointers: addition and
subtraction. To understand what occurs in pointer arithmetic, let p1 be an integer
pointer with a current value of 2000. Also assume integers are 2 bytes long. After the
p1 contains 2002, not 2001. The reason for this is that each time p1 is incremented, it
will point to the next integer. The same is true of decrements. For example, assuming
that p1 has the value 2002, the expression
causes p1 to have the value 1998.
Generalizing from the preceding example, the following rules govern pointer arithmetic.
Each time a pointer is incremented, it points to the memory location of the next element
of its base type. Each time it is decremented, it points to the location of the previous
element. When applied to character pointers, this will appear as "normal" arithmetic
because characters are always 1 byte long. All other pointers will increase or decrease

Amity Directorate of Distance & Online Education

182 Object Oriented Programming Concept Using C++

by the length of the data type they point to. This approach ensures that a pointer is
always to an appropriate element of its base type. Figure 9.3 illustrates this concept.
You are not limited to the increment and decrement operators. For example, you may
add or subtract integers to or from pointers. The expression
p1 = p1 + 12;
makes p1 point to the twelfth element of p1's type beyond the one it currently points to.
Besides addition and subtraction of an pointer and a integer, only one other arithmetic
operation is allowed: you may subtract one pointer from another in order to find the
number of objects of their base type that separate the two. All other arithmetic
operations are prohibited. Specifically, you may not multiply or divide pointers; you may
not add two pointers; you may not apply the bitwise operators to them; and you may not
add or substract type float or double to or from pointers.
Pointer Comparisons
You can compare two pointers in a relational expression. For instance, given to pointers
p and q, the following statement is perfectly valid:
if (p<q) printf ("p points to lower memory than g/n");
Generally, pointer comparisons are used when two or more pointers point to a common
object, such as an array. As an example, a pair of stack routines are developed that
store and retrieve integer values. A stack is a list that uses first-in, last-out accessing. It
is often compared to a stack of plates on a table–the first one set down is the last one to
be used. Stacks are used frequently in compilers, interpreters, spreadsheets, and other
system-related software. To create a stack, you need two functions: push () and pop().
The push() function places values on the stack and pop() takes them off. These
routines are shown here with a simple main() function to drive them. The program puts
the values you enter into the stack. If you enter 0, a value is popped from the stack. To
stop the program, enter -1.
#include <stdio.h>
#include <stdlib.h>

#define SIZE 50

void push (int i);

int pop (void);

int *tos, *p1, stack [SIZE];

int main (void)

int value;

tos = stack; /* tos points to the top of stack */

p1 = stack; /* initialize p1 */
do {

Amity Directorate of Distance & Online Education

Pointers and Streams 183
printf (" Enter value: ");
scanf ("%d", &value); Notes
if (value! = 0 push (value);
else printf ("value on top is %d\n", pop());
} while (value! = -1);
return 0;
void push (int i)
if (p1 == (tos+SIZE)) {
printf ("Stack Overflow. \n");
exit (1);
*p1 = i;
int pop (void)
if (p1 == tos) {
printf ("Stack Underflow. \n");
exit (1);
p1 --;
return *(p1+1);
You can see that memory for the stack is provided by the array stack. The pointer p1 is
set to point to the first element in stack. The p1 variable accesses the stack. The
variable tos holds the memory address of the top of the stack. It is used to prevent stack
overflows and underflows. Once the stack has been initialized, push() and pop() may be
used. Both the push() and pop() functions perform a relational test on the pointer p1 to
detect limit errors. In push(), p1 is tested against the end of stack by adding SIZE (the
size of the stack) to tos. This prevents an overflow. In pop(), p1 is checked against tos
to be sure that a stack underflow has not occured.
In pop(), the parentheses are necessary in the return statement. Without them, the
statement would look like this:
return *p1 +1;
which would return the value at location p1 plus one, not the value of the location p1+1.

8.6 Pointers and Arrays

Amity Directorate of Distance & Online Education

184 Object Oriented Programming Concept Using C++

There is a close relationship between pointers and arrays. Consider this program
Initializing Pointers
After a local pointer is declared but before it has been assigned a value, it contains an
unknown value. (Global pointers are automatically initialized to null.) Should you try to
use the pointer before giving it a valid value, you will probably crash your program – and
possibly your computer's operating system as well – a very nasty type of error!
There is an important convention that most C/C++ programmers follows when working
with pointers: A pointer that does not currently point to a valid memory location is given
the value null (which is zero). By convention, any pointer that is null implies that it points
to nothing and should not be used. However, just because a pointer has a null value
does not make it "safe." The use of null is simply a convention that programmers follw. It
is not a rule enforced by the C or C++ languages. For example, if you use a null pointer
on the left side of an assignment statement, you still run the risk of crashing your
program or operating system.
Because a null pointer is assumed to be unused, you can use the null pointer to make
many of your pointer routines easier to code and more efficient. For example, you could
use a null pointer to mark the end of a pointer array. A routine that accesses that array
knows that it has reached the end when it encounters the null value. The search()
function shown here illustrates this type of approach.
/* look up a name */
int search (char *p[], char *name)
register int t;

for (t=0; p[t]; ++t)

if (!strcmp (p[t], name)) return t;
return -1; /* not found */
The for loop inside search() runs until either a match is found or a null pointer is
encountered. Assuming the end of the array is marked with a null, the condition
controlling the loop fails when it is reached.
C/C++ programmers commonly initialize strings. You saw an example of this in the
syntax_error() function in the section "Arrays of Pointers." Another variation on the
initialization theme is the following type of string declaration:
char *p = "hello world";
As you see, the pointer p is not an array. The reason this sort of initialization works is
because of the way the compiler operates. All C/C++ compilers create what is called a
string table, which is used to store the string constants used by the program. Therefore,
the preceding declaration statement places the address of hello world, as stored in the
string table, into the pointer p. Throughout a program, p can be used like any other
string. For example, the following programs is perfectly valid:
#include <stdio.h>
#include <string.h)

char *p = "hello world";

Amity Directorate of Distance & Online Education

Pointers and Streams 185

int main (void) Notes

register int t;
/* print the string forward and backwards */
printf (p);
for (t=strlen (p)-1; t>-1; t--) printf ("%c", p[t]);

return 0.
In Standard C++, the type of a string literal is technically const char*. But C++ provides
an automatic conversion to char*. Thus, the preceding program is still valid. However,
this automatic conversion is a deprecated feature, which means that you should not rely
upon it for new code. For new programs, you should assume that string literals are
constants and the declaration of p in the preceding program should be written like this
const char *p = "hello world";

8.7 Pointers to Functions

A particularly confusing yet powerful feature of C++ is the function pointer. Even though
a function is not a variable, it still has a physical location in memory that can be
assigned to a pointer. This address is the entry point of the function and it is the
address used when the function is called. Once a pointer points to a function, the
function can be called through that pointer. Function pointers also allow functions to be
passed as arguments to other functions.
You obtain the address of a function by using the function's name without any
parentheses or arguments. (This is similar to the way an array's address is obtained
when only the array name, without indexes, is used). To see how this is done, study the
following program, paying close attention to the declarations.
// pointer to a function of void return type,
// which takes an char as argument

void (*my Function Pointer) (char* p);

void f1 (char*);
int f2 (char*);
void f3 (int*);
void Dosomething ()
my Function Pointer = & f1; // correct
my Function Pointer = & f2; // error, wrong return
my Function Pointer = &f3; // error, wrong argument

Amity Directorate of Distance & Online Education

186 Object Oriented Programming Concept Using C++

8.8 Arrays of Function Pointer

Notes Also, arrays of function pointers are useful for menu or switching between functions.
typedef void (* my Function Pointer) (char* p);
// def a new type
void open (char*);
void close (char *);
void print (char *);
void exit (char*);
my Function Pointer List of Tasks [ ] = {
& open, & close, & print, & exit, NULL};
void Dosomething (int i, char *p)
(* List of Tasks [i]) (p);
/* using your own functions */
# include <iostream.h>
int Cout (int, int);
int age;
int grandma;
void main (void)
Cout<<" How old are you?:";
Cout <<" How old is your grandma?:";
int range = count (age, grandma);
Cout << "Your grandma is:" << range
<<"years older than you";
int count (int ae, int ga)
ga = ga-al; // first and last letter in grandma
// and age
return ga;
you first declared a new function:
int count (int, int). The int before count is because you will get a value in return and the
two int after count is because you send two values along-grandma and age. Notice that;

Amity Directorate of Distance & Online Education

Pointers and Streams 187
in the end the line int range = count (age, grandma) tell that it should go to the function
count and bring the values that are stored in age and grandma and then save the result
in range. The last function int count (int all, int ga) gets the two values that we send Notes
counts the result between grandma and age and returns the value to range-return ga.
The two new values or and ga will be declared the values that you send along. The
reason for using two knew is that for example you have two other variables: sister and
grandpa. Then you will still would be able to use this function to see the age between
grandpa and sister.

8.9 Pointers and Arrays

These is a close association between pointers and arrays. Consider the program given
// arr. cpp
// array accessed with array notation
# include <iostream.h>
void main()
int intarrary [5] = {31, 54, 77, 52, 93}; // array
for (int j = 0; j<5i j++) // for each element
Cout <<endl<< intarray [j]; // print value.
The cout statement prints each arrary element in turn. For instance, when j is 3,
the expression intarrary [j] takes on the value intarray [3] and accesses the fourth array
element, the integer 52. Here's the output of ARR:
Surprisingly, array elements can be accessed using pointer notation as well as
array notation. The next program PTR, is similar to ARR except that it uses pointer
// ptr. cpp
// array accessed with pointer notation.
# include <iostream.h>
void main()
int intarray [5] = { 31, 54, 77, 52, 93}; // array
for (int j=0; j<5; j++) // for each element, Cout
<<endl <<* (int array +j); //print value

Amity Directorate of Distance & Online Education

188 Object Oriented Programming Concept Using C++

The expression *(intarray +j) in PTR has exactly the same effect as intarray [j] in
ARR, and the output of the programs is identical. But how do we interpret the
Notes expression * (intarray +j)? Suppose j is 3, so the expression is equivalent to * (intarrary
+3). We want this to represent the contents of the fourth element of the array (52).
Remember that the name of an array is its address. The expression intarray +j is thus
an address with something added to it. You might expect that intarray +3 would cause
three bytes to be added to intarray. But that doesn't produce the result we want: intarray
is an array of integers, and 3 bytes into this array is the middle of the second element,
which is not very useful. We want to obtain the fourth integer in the array, not the fourth
The C++ compiler is smart enough to take the size of the data into account when it
performs arithmetic on data addresses. It knows that intarray is an array of type int
because it was declared that way. So when it sees the expression intarray +3 it
interprets it as the address of the fourth integer in intarray, not the fourth byte.
But we want the value of this fourth array element, not the address. To take the value,
we use the indirection operator. The resulting expression, when j is 3, is * (intarray +3),
which is the contents of the fourth array element, or 52.

8.10 Deleting Variables

Variables that you create with new also have to be destroyed when you're done using
them. To do this, you say "delete" and then the name of the pointer. (Or, if you created
an array, you use "delete[]" and then the name of the pointer to the array) For instance:
int *burrito;
int *enchilada;
burrito = new int [3];
enchilada = new int;
burrito [0] = 4;
burrito [1] = 8;
burrito [2] = 12;
delete enchilada;
delete [] burrito;
Seem easy enough, right? Remember that delete works just like free did in Pascal
– The contents pointed to are removed, but not the pointer. You can create more
variables and give their location to the same pointer, if you want.
You probably noticed that the code created a pointer to "int[3]" and then started
using burrito as though it was an array. How can this be? Well, first a quick explanation
of what an array really is. Say, you create an array of ten integers using the declaration
"int salsa[10];". Inside your computer's memory, the program makes a location big
enough to hold ten integers, and gives the variable "salsa" the location of the first one.
When you say "salsa[5]", it's taking the location of the first part and looking 5 locations
ahead. Don't worry if that's a little confusing. The important part is that you know that if
you want to create arrays using new, you can. In fact, the whole purpose of new, really,
is to create arrays whose size can be determined while the program is running!

Reserving Dynamic Memory

To reserve a block or memory, include the STDLIB. H or ALLOC.H header files (you
may also include both files):

Amity Directorate of Distance & Online Education

Pointers and Streams 189
#include <alloc.h>
That makes two functions available: malloc (memory allocator) and free. Use malloc to Notes
request a block of memory from the heap. First, define a pointer:
float *fp:
Then call malloc to reserve enough space to store an object of the pointer's type.
Assign the address returned by malloc at the pointer:
fp = malloc (size of (float));
Always use size of or another safe method to request the proper amount of memory for
an object. In C++, you can also task on a type cast expression in front of malloc:
fp = (float *) malloc (size of (float));
The type cast expression (float*) is needed because malloc returns a generic address
value, called void*, that has no specific type. A void pointer is just an address. To
assign a void pointer to a typed pointer such as fp, you must use a type cast
expression, information the compiler of your intentions. Prefacing malloc with (float*)
tells the compiler to treat malloc's return value as a float pointer. ANSIC is less than
C++ in this regard, but you should use a type cast expression anyway so that your
programs are compatible with C and C++ compilers.
If you want the memory bytes cleared to all zeros, call the similar function calloc:
fp = (float *) calloc (1, size of (float));
Unlike malloc, calloc requires two parameters-the number of objects to allocate (1 in
this case) and the size in bytes of each object (size of(float)here). If successfully
allocated, the memory is cleared to all zeros.
Use a dynamic object by dereferencing the pointer–exactly as you learned earlier in this
chapter. For example, after allocating memory for a float object and assigning that
memory's address to the float pointer fp, you can assign a value to the object like this:
*fp = 3.14159:
With an asterisk, the expression *fp is treated as the object addressed by fp. To copy
the value to another variable, you can write
float copy = *fp:
If malloc cannot find enough memory to satisfy a memory request, it returns a null
pointer, usually equal to zero. (Some compilers define null pointer differently, but they
are the exceptions. The compiler supplied with this book defines a null pointer as zero.)
You should always test whether a call to malloc succeeded, typically by using an if
statement to check whether the resulting pointer is null. The following statements, for
example, call a function Error (not shown) if malloc fails:
fp = (float *) malloc (sizeof(float));
if (fp == NULL)
Error ();
The if statement's control expression is often abbreviated as
if (! fp)
Remember, zero represents false, A null pointer equals zero, and, therefore, you may
use pointers directly as true-false control expressions. The system constant NULL
equals zero, so the expressions (!fp) and (fp--NULL)are equivalent.

Amity Directorate of Distance & Online Education

190 Object Oriented Programming Concept Using C++

8.11 The this Pointer

Notes When a member function is called, it is automatically passed an implicit argument that is
a pointer to the invoking object (that is, the object on which the function is called).
This pointer is called this. To understand this, first consider a program that creates a
class called pwr that computes the result of a number raised to some power:
#include <iostream>
using namespace std;

class pwr {
double b;
int e;
double va1;
pwr (double base, int exp);
double get_pwr() { return val; }
pwr::pwr (double base, int exp)
b = base;
e = exp;
val= l;
if (exp==0) return;
for (;exp>0; exp--) val = val *b;
int main()
pwr x (4. 0, 2), y(2.5, 1), z (5.7,0);

cout << x.get _pwr() << " ";

cout << y.get _pwr() << " ";
cout << z.get _pwr() << " \n";
return 0;
Within a member function, the members of a class can be accessed directly, without
any object or class qualification. Thus, inside pwr(), the statement
b= base;
means that the copy of b associated with the invoking object will be assigned the value
contained in base. However, the same statement can also be written like this:

Amity Directorate of Distance & Online Education

Pointers and Streams 191
this->b = base;
The this pointer points to the object that invoked pwr(). Thus, this->b refers to that Notes
object's copy of b. For example, if pwr() had been invoked by x (as in x (4.0,2)), then
this in the preceding statement would have been pointing to x, Writing the statement
without using this is really just shorthand.
Here is the entire pwr() function written using the this pointer:
pwr::pwr (double base, int exp)
this->b = base;
this->e = exp;
this->val = 1;
if (exp==0) return;
for ( ; exp>0; exp--)

this->val = this->val * this->b;

Actually, no C++ programmer would write pwr() as just shown because nothing is
gained, and the standard form is easier. However, the this pointer is very important
when operators are overloaded and whenever a member function must utilize a pointer
to the object that invoked it.
Remember that the this pointer is automatically passed to all member functions.
Therefore, get_pwr() could also be rewritten as shown here:
double get_pwr() {return this_>val; }
In this case, if get_pwr() is invoked like this:
Then this will point to object two final points about this. First, friend functions are not
members of a class and, therefore, are not passed this pointer. Second, static member
functions do not have a this pointer.

8.12 Polymorphism
Polymorphism is an important OOP concept. Polymorphism means the ability to take
more than one form. For example, an operation may exhibit different behavior in
different instances. The behavior depends upon the types of data used in the operation.
For example, consider the operation of addition. For two numbers, the operation will
generate a sum. If the operands are strings, then the operation will produce a third
string by contention. The diagram given below, illustrates that a single function name
can be used to handle different number and types of arguments. This is something
similar to a particular word having several different meanings depending on the context.
Polymorphism plays an important role in following objects having different internal
structures to share the same external interface. This means that a general class of
operations may be accessed in the same manner even though specific actions
associated with each operation may differ.
Polymorphism can be implemented using operator and function overloading, where the
same operator and function works differently on different arguments producing different

Amity Directorate of Distance & Online Education

192 Object Oriented Programming Concept Using C++

results. These polymorphisms are brought into effect at compile time itself, hence is
known as early binding, static binding, static linking or compile time polymorphism.
However, ambiguity creeps in when the base class and the derived class both have a
function with same name. For instance, let us consider the following code snippet.
Class aa
Int x;
Void display() {……} //display in base class
Class bb : public aa
Int y;
Void display() {……} //display in derived class
Since, both the functions aa.display() and bb.display() are same but at in different
classes, there is no overloading, and hence early binding does not apply. The
appropriate function is chosen at the run time – run time polymorphism.
C++ supports run-time polymorphism by a mechanism called virtual function. It exhibits
late binding or dynamic linking.
As stated earlier, polymorphism refers to the property by which objects belonging to
different classes are able to respond to the same message, but in different forms.
Therefore, an essential feature of polymorphism is the ability to refer to objects without
any regard to their classes. It implies that a single pointer variable may refer to object of
different classes.
However, a base pointer, even if is made to contain the address of the derived class,
always executes the function in the base class. The compiler ignores the content of the
pointer and chooses the member function that matches the type of the pointer. Thus,
the polymorphism stated above cannot be implemented by this mechanism.
C++ implements the runtime object polymorphism using a function type known as virtual
function. When a function with the same name is used both in the base class and the
derived class, the function in the base class is declared virtual by attaching the keyword
virtual in the base class preceding its normal declaration. Then C++ determines which
function to use at run time based on the type of object pointed to by the base pointer
rather than the type of the pointer. Thus, by making the base pointer to point to different
objects, one can execute different definitions of the virtaul function as given in the
program below.
#include <iostream.h>
class base
void display()

Amity Directorate of Distance & Online Education

Pointers and Streams 193
cout<<”\n print base”;
} Notes
virtual void show() //virtual function
cout<<”\n show base”;
class derived : public base
void display()
cout<<”\n display derived”;
void show()
cout<<”\n show derived”;
base bb;
derived dd;
base *baseptr;
cout <<”\nbaseptr points to the base \n”;
baseptr = &bb;
baseptr -> display(); //calls base function display()
baseptr -> show(); //calls base function show()
cout <<”\n\nbaseptr points to the derived \n”;
baseptr = &dd;
baseptr -> display(); //calls derived function display()
baseptr -> show(); //calls derived function show()
The output of this program would be:
Baseptr points to base
Display base
Show base

Amity Directorate of Distance & Online Education

194 Object Oriented Programming Concept Using C++
Baseptr points to derived

Notes Display derived

Show derived
Here, we see that the same object pointer points to two different objects of different
classes and yet selects the right function to execute. This is implementation of function
polymorphism. Remember, however, that runtime polymorphism is achieved only when
a virtual function is accessed through a pointer to the base class. It is also interesting to
note that since, all the C++ classes are derived from the Object class, a pointer to the
Object class can point to any object of any class in C++.

8.13 Virtual Functions

Virtual means existing in effect but not in reality. A virtual function then is one that does
not really exist but nevertheless appears real to some parts of a program.
Why are virtual functions needed? Suppose you have a number of objects of different
classes but you want to put them all on a list and perform a particular operation on them
using the same function call. For example, suppose a graphics program include several
different shapes: a triangle, a ball, a square, and so on. Each of these class has a
member function draw() that causes the object to be drawn on the screen.
Now suppose you plan to make a picture by grouping a number of these elements
together, and you want to draw the picture in a convenient way. One approach is to
create an array that holds pointers to all the different objects in the picture. The array
might be defined like this.
shape* ptrass [100]; // array of 100 pointers to shapes
If you insert pointers to all the shapes into this array, you can then draw an entire
picture using a simple loop:
for(int j=0; j<N; j++)

ptrass[j] -> draw();

This is an amazing capability: completely different functions are executed by the same
function call. If the pointer in ptrass points to a ball, the function that draws a ball is
called; if it points to a triangle, the triangle-drawing function is drawn. This is an
important example of polymorphism, or giving different meanings to the same thing.
However, for this polymorphic approach to work, several conditions must be met. First,
all the different classes of shapes, such as balls and triangles, must be derived from a
single base class. Second, the draw ( ) function must be declared to be virtual in the
base class.
Consider the program given below to clearly understand the virtual function:
#include <iostream.h>
class Base
void display()
cout <<"\n Display base ";

Amity Directorate of Distance & Online Education

Pointers and Streams 195
virtual void show()
{ Notes
cout <<"\n show base";
Class derived : Public Base
void display()
cout <<"\n Display derived";
void show()
cout <<"\n show derived";
Base B;
Derived D; // Declarations
Base *bptr;

cout <<"\n bptr points to Base\n";

bptr = &B;

bptr ->display(); // calls Base version

bptr ->show(); // calls Base version

cout <<"\n\n bptr points to Derived \n";

bptr = &D;

bptr ->display(); // calls Base version

bptr ->show(); // calls Derived version

The output of the above Program would be:
bptr points to Base
Display base

Amity Directorate of Distance & Online Education

196 Object Oriented Programming Concept Using C++
show base

Notes bptr points to Derived

Display base
Show derived
Note that when bptr is made to point to the object D, the statement

bptr ->display();
calls only the function associated with the Base (i.e. Base :: display( ) ) whereas the

bptr ->show();
Calls the Derived version of show ( ). This is because the function display ( ) has not
been made virtual in the Base class.
One important point to remember is that, we must access virtual functions through the
use of a pointer declared as a pointer to the base class. Why can’t we use the object
name (with the dot operator) the same way as any other member function to call the
virtual function? We can, but remember, runtine polymorphism is achieved only when a
virtual function is accessed through a pointer to the base class.

8.13.1 Virtual Member Functions Accessed With Pointers

Let’s make a single change in our program. We’ll place the keyword virtual in front of
the declarator for the show ( ) function in the base class. Here’s the listing for the
resulting program, VIRT:
// virt, cpp
// virtual functions accessed from pointer
#include <iostream.h>
class base // base class
virtual void show() // virtual function
cout <<"\n Base ";
class Derv1 : Public Base // derived class1
void show()
cout <<"\n Derv1";

Amity Directorate of Distance & Online Education

Pointers and Streams 197
class Derv2 : Public Base // derived class2
{ Notes
void show()
{ cout <<"\n Derv2";}
void main()
Derv1 dv1; // object of derived class1
Derv2 dv2; // object of derived class2
Base* ptr; // pointer to base class
ptr = &dv1; // put address of dv1 in pointer

ptr ->show(); // execute show()

ptr = &dv2; // put address of dv2 in pointer

ptr ->show(); // execute show()

The output of this program is
Now, as you can see, the member functions of the derived classes, not the base class,
are executed. We change the contents of ptr from the address of Derv1 to that of Derv2,
and the particular instance of show ( ) that is executed also changes. So the same
function call, ptr ->show ( );
executes different functions, depending on the contents of ptr. The rule is that the
compiler selects the function based on the contents of the pointer ptr, not on the type of
the pointer, as in NOT VIRTUAL.

8.14 Template
Class template is a template used to generate template classes. You cannot declare an
object of a class template. Template class is an instance of a class template. In this
section, we will discuss about template class. Template classes are ideal for
implementing container classes, because it is highly desirable to have containers work
across a wide variety of data types, and templates allow you to do so without
duplicating code.
A template class takes the form:
template <class T> class MyTemplateClass { ... };
Class template specialization takes the form:
template <> class MyTemplateClass <specific-data-type> { ... };
A templated class may be derived from a regular non-templated C++ class or derived
from another templated class.
Function templates
Amity Directorate of Distance & Online Education
198 Object Oriented Programming Concept Using C++

1. Let us find out what exactly is meant by function templates. A template that defines
an unbounded set of related functions is known as Function Templates.
2. A Function Templates behaves like a function except that the template can have
arguments of many different types.
3. In other words, a function template represents a family of functions. The format for
declaring function templates with type parameters is
4. template <class identifier> function_declaration;
5. template <typename identifier> function_declaration;
6. Both expressions have exactly the same meaning and behave exactly the same
way. The latter form was introduced to avoid confusion because a type parameter
does not need to be a class, it may also be a basic type like int or double.
7. For example, the C++ Standard Library contains the function template max(x, y)
which returns either x or y, whichever is larger. Max() could be defined like this,
using the following template:
template <typename Type>
Type max(Type a, Type b) {
return a > b ? a : b;
8. This single function definition works with many data types. Although usage of a
function template saves space in the source code file (in addition to limiting
changes to one function description) versus separate functions written for various
data types, it does not produce smaller object code than would occur from separate
non-templated versions of a function written for different types.
For example, if a program uses an int and a double version of the max() function
template shown above, the compiler will create an object code version of max() that
takes ints and an object code version that takes doubles. The compiler output will
be identical to what would have been produced if the source code contained two
non-templated versions of max(), one written to handle ints and one written to
handle doubles.

#include <iostream>

int main()
// This will call max <int> (by argument deduction)
std::cout << max(3, 7) << std::endl;
// This will call max<double> (by argument deduction)
std::cout << max(3.0, 7.0) << std::endl;
// This type is ambiguous, so explicitly instantiate
std::cout << max<double>(3, 7.0) << std::endl;
return 0;

Amity Directorate of Distance & Online Education

Pointers and Streams 199
In the first two cases, the template argument Type is automatically deduced by the
compiler to be int and double, respectively. In the third case deduction fails because the
type of the parameters must in general match the template arguments exactly. Notes
This function template can be instantiated with any copy constructible type for which the
expression (y < x) is valid. For user-defined types, this implies that the less-than
operator must be overloaded.
The following example implements the QuickSort algorithm with a function template
named quicksort:
#include <iostream>
#include <cstdlib>
using namespace std;

template<class T> void quicksort(T a[], const int& leftarg,

const int& rightarg)
if (leftarg < rightarg) {

T pivotvalue = a[leftarg];
int left = leftarg - 1;
int right = rightarg + 1;

for(;;) {

while (a[--right] > pivotvalue);

while (a[++left] < pivotvalue);

if (left >= right) break;

T temp = a[right];
a[right] = a[left];
a[left] = temp;

int pivot = right;

quicksort(a, leftarg, pivot);
quicksort(a, pivot + 1, rightarg);

Amity Directorate of Distance & Online Education

200 Object Oriented Programming Concept Using C++
int main(void) {

Notes int sortme[10];

for (int i = 0; i < 10; i++) {

sortme[i] = rand();
cout << sortme[i] << " ";
cout << endl;

quicksort<int>(sortme, 0, 10 - 1);

for (int i = 0; i < 10; i++) cout << sortme[i] << "
cout << endl;
return 0;
The above example will have output similar to the following:
16838 5758 10113 17515 31051 5627 23010 7419 16212 4086
4086 5627 5758 7419 10113 16212 16838 17515 23010 31051
This QuickSort algorithm will sort an array of type T (whose relational and assignment
operators have been defined). The template function takes one template argument and
three function arguments:
the type of the array to be sorted, T
the name of the array to be sorted, a
the lower bound of the array, leftarg
the upper bound of the array, rightarg
In the above example, you can also call the quicksort() template function with the
following statement:
quicksort(sortme, 0, 10 - 1);
You may omit any template argument if the compiler can deduce it by the usage and
context of the template function call. In this case, the compiler deduces that sortme is
an array of type int.

8.15 Streams
C++ supports two complete I/O systems: the one inherited from C and the object-
oriented I/O system defined by C++ (hereafter called simply the C++/O system). The C-
based I/O system was discussed in Part One. Here we will begin to examine the C++/O
system. Like C-based I/O, C++’s I/O system is fully integrated. The different aspects of
C++’s I/O system, such as console I/O and disk I/O, are actually just different
perspectives on the same mechanism. This chapter discusses the foundations of the

Amity Directorate of Distance & Online Education

Pointers and Streams 201
C++/O system. Although the examples in this chapter use “console” I/O, the information
is applicable to other devices, including disk files (discussed in Chapter 21).
Since the I/O system inherited from C is extremely rich, flexible, and powerful, you
might be wondering why C++ defines yet another system. The answer is that C’s I/O
system knows nothing about objects. Therefore, for C++ to provide complete support for
object-oriented programming, it was necessary to create an I/O system that could
operate on user-defined objects. In addition to support for objects, there are several
benefits to using C++’s I/O system even in programs that don’t make extensive (or any)
use of user-defined objects. Frankly, for all new code, you should use the C++I/O
system. The CI/O is supported by C++ only for compatibility.
Old Vs. Modern C++I/O
There are currently two versions of the C++ object-oriented I/O library in use: the older
one that is based upon the original specifications for C++ and the newer one defined by
Standard C++. The old I/O library is supported by the header file <iostream.h>. The new
I/O library is supported by the header <iostream>. For the most part the two libraries
appear the same to the programmer. This is because the new I/O library is, in essence,
simply an updated and improved version of the old one. In fact, the vast majority of
differences between the two occur beneath the surface, in the way that the libraries are
implemented—not in how they are used.
From the programmer’s perspective, there are two main differences between the old
and new C++/O libraries. First, the new I/O library contains a few additional features
and defines some new data types. Thus, the new I/O library is essentially a superset of
the old one. Nearly all programs originally written for the old library will compile without
substantive changes when the new library is used. Second, the old-style I/O library was
in the global namespace. The new-style library is in the std namespace. (Recall that the
std namespace is used by all of the Standard C++ libraries.) Since the old-style I/O
library is now absolete, this book describes only the new I/O library, but most of the
information is applicable to the old I/O library as well.

8.15.1 C++ Streams

A stream is a source of sequence of bytes. A stream abstracts for input/output devices.
It can be tied up with any I/O device and I/O can be performed in a uniform way. The
C++ iostream library is an objet-oriented implementation of this abstraction. It has a
source (producer) of flow of bytes and a sink (consumer) of the bytes. The required
classes for the stream I/O are defined in different library header files.
To use the I/O streams in a C++ program, one must include iostream.h header file in
the program. This file defines the required classes and provides the buffering. Instead of
functions, the library provides operators to carry out the I/O. Two of the Stream
Operators are:
<< : Stream insertion for output.
>>: Stream extraction for input.
The following streams are created and opened automatically:
cin : Standard console input (keyboard).
cout : Standard console output (screen).
cprn : Standard printer (LPT1).
cerr : Standard error output (screen).
clog : Standard log (screen).
caux : Standard auxiliary (screen).

Amity Directorate of Distance & Online Education

202 Object Oriented Programming Concept Using C++

The following program reads an integer and prints the input on the console.

Notes #include <iostream> // Header for stream I/O.

int main(void)
int p; // variable to hold the input integer
cout << "Enter an integer: ";
cin >> p;
cout << "\n You have entered" << p;

8.16 Inheritance
Let’s discuss about derived class in this section. A class can be derived from more than
one class, which means it can inherit data and functions from multiple base classes. To
define a derived class, we use a class derivation list to specify the base class (es). A
class derivation list names one or more base classes and has the form:
class derived-class: access-specifier base-class
Where access-specifier is one of public, protected, or private, and base-class is the
name of a previously defined class. If the access-specifier is not used, then it is private
by default.
Consider a base class Shape and its derived class Rectangle as follows:
#include <iostream>
using namespace std;

// Base class
class Shape
void setWidth(int w)
width = w;
void setHeight(int h)
height = h;
int width;
int height;

Amity Directorate of Distance & Online Education

Pointers and Streams 203

// Derived class Notes

class Rectangle: public Shape
int getArea()
return (width * height);

int main(void)
Rectangle Rect;


// Print the area of the object.

cout << "Total area: " << Rect.getArea() << endl;

return 0;
When the above code is compiled and executed, it produces the following result:
Total area: 35

8.16.1 Access Control and Inheritance

We must remember that a derived class can access all the non-private members of its
base class. Thus, base-class members that should not be accessible to the member
functions of derived classes should be declared private in the base class.
We can summarize the different access types according to who can access them in the
following way:
Table 1.1 Different Types of Access
Access Public Protected Private
Same class Yes Yes yes
Derived classes Yes Yes no
Outside classes yes No no
A derived class inherits all base class methods with the following exceptions:

Amity Directorate of Distance & Online Education

204 Object Oriented Programming Concept Using C++

z Constructors, destructors and copy constructors of the base class.

Notes z Overloaded operators of the base class.

z The friend functions of the base class.
8.16.2 Type of Inheritance
We need to know that when deriving a class from a base class, the base class may be
inherited through public, protected or private inheritance. The type of inheritance is
specified by the access-specifier as explained above.
While using different type of inheritance, following rules are applied:
z Public Inheritance: When deriving a class from a public base class, public
members of the base class become public members of the derived class and
protected members of the base class become protected members of the derived
class. A base class's private members are never accessible directly from a derived
class, but can be accessed through calls to the public and protected members of
the base class.
z Protected Inheritance: When deriving from a protected base class, public and
protected members of the base class become protected members of the derived
z Private Inheritance: When deriving from a private base class, public and
protected members of the base class become private members of the derived
8.16.3 Single Level Inheritance
In single level inheritance, there is only one base class and has only one derived class.
Example: Single Level Inheritance
class Base


class Derv: public Base


8.16.4 Multi Level Inheritance
In multi level inheritance, there will be a chain of inheritance with a class derived from
only one parent and will have only one child class.
Example: Multi Level Inheritance
class A


Amity Directorate of Distance & Online Education

Pointers and Streams 205
class B: public A
{ Notes


class C: public B

8.16.5 Multiple Inheritances
We must understand that a C++ class can inherit members from more than one class
and here is the extended syntax:
class derived-class: access baseA, access baseB....
Where access is one of public, protected, or private and would be given for every
base class and they will be separated by comma as shown above.
Example: Let us try the following example:
#include <iostream>

using namespace std;

// Base class Shape

class Shape
void setWidth(int w)
width = w;
void setHeight(int h)
height = h;
int width;
int height;

Amity Directorate of Distance & Online Education

206 Object Oriented Programming Concept Using C++
// Base class PaintCost

Notes class PaintCost

int getCost(int area)
return area * 70;

// Derived class
class Rectangle: public Shape, public PaintCost
int getArea()
return (width * height);

int main(void)
Rectangle Rect;
int area;


area = Rect.getArea();

// Print the area of the object.

cout << "Total area: " << Rect.getArea() << endl;

// Print the total cost of painting

cout << "Total paint cost: $" << Rect.getCost(area) << endl;

return 0;

Amity Directorate of Distance & Online Education

Pointers and Streams 207
When the above code is compiled and executed, it produces the following result: Notes
Total area: 35
Total paint cost: $2450

8.17 Summary
A template is a piece of code that can be copied and modified to fit a specific
situation. Template classes are instanced in the same way template functions are — the
compile stencils a copy upon demand with the template parameter replaced by the
actual data type the user needs and then compiles the copy. If you don’t ever use a
template class, the compile won’t even compile it. Pointers are much more commonly
used in C++ (and( ) than in many other languages (such as BASIC and Pascal). Is this
emphasis on pointers really necessary? You can do a lot without them, as their absence
from the preceding chapters demonstrates. Some operations that use pointers in C++
can be carried out in other ways. For example, array elements can be accessed with
array notation rather than pointer notation, and a function can modify arguments passed
by reference, as well as those passed by pointer.
However, in some situations pointers provide an essential tool for increasing the
power of C++. A notable example is the creation of data structures such as linked lists
and binary trees. In fact, several key features of C++, such as virtual functions and the
this pointer, require the use of pointrs. So, although you can do a lot of programming in
C++ without using pointers, you will find them essential to obtaining the most from the

8.18 Check Your Progress

Multiple Choice Questions

1. To which does the function pointer point to?

a) variable
b) constants
c) function
d) absolute variables

2. What we will not do with function pointers?

a) allocation of memory
b) de-allocation of memory
c) both a & b
d) none of the mentioned

3. What is the default calling convention for a compiler in c++?

a) __cdecl
b) __stdcall
c) __pascal
d) __fastcall

4. What is the output of this program?

#include <iostream>

using namespace std;

Amity Directorate of Distance & Online Education

208 Object Oriented Programming Concept Using C++

int add(int first, int second)

Notes {

return first + second + 15;

int operation(int first, int second, int (*functocall)(int, int))

return (*functocall)(first, second);

int main()

int a;

int (*plus)(int, int) = add;

a = operation(15, 10, plus);

cout << a;

return 0;

a) 25
b) 35
c) 40
d) 45

5. What is the output of this program?

#include <iostream>

using namespace std;

void func(int x)

cout << x ;

int main()

Amity Directorate of Distance & Online Education
Pointers and Streams 209
void (*n)(int);

n = &func; Notes

(*n)( 2 );

n( 2 );

return 0;

a) 2
b) 20
c) 21
d) 22

6. What is the output of this program?

#include <iostream>

using namespace std;

int n(char, int);

int (*p) (char, int) = n;

int main()

(*p)('d', 9);

p(10, 9);

return 0;

int n(char c, int i)

cout << c << i;

return 0;

a) d99
b) d9d9
c) d9
d) compile time error

Amity Directorate of Distance & Online Education

210 Object Oriented Programming Concept Using C++

7. What is the output of this program?

Notes #include <iostream>

using namespace std;

int func (int a, int b)

cout << a;

cout << b;

return 0;

int main(void)

int(*ptr)(char, int);

ptr = func;

func(2, 3);

ptr(2, 3);

return 0;

a) 2323
b) 232
c) 23
d) compile time error

8. What are the mandatory part to present in function pointers?

a) &
b) retrun values
c) data types
d) none of the mentioned

9. which of the following can be passed in function pointers?

a) variables
b) data types
c) functions
d) none of the mentioned

10. What is meaning of following declaration?

a) ptr is pointer to function.

Amity Directorate of Distance & Online Education

Pointers and Streams 211
b) ptr is array of pointer to function.
c) ptr is pointer to such function which return type is array.
d) ptr is pointer to array of function. Notes

8.19 Questions and Exercises

1. Explain, with an example, how you would create space for an array of objects
using pointers.
2. What does this pointer point to?
3. What does inheritance mean in C++?
4. What are the different forms of inheritance? Give an example for each.
5. What does polymorphism means in C++ language?
6. What is a virtual function? Why do we need virtual function?
7. What is a stream?
8. Describe briefly the features of I/O system supported by C++.

8.20 Key Terms

• Template: It is a piece of code that can be copied and modified to fit a
specific situation.

• Multi-level inheritance: In multi-level inheritance, there will be a chain of

inheritance with a class derived from only one parent and will have only one
child class.

• Single level inheritance: In single level inheritance, there is only one base
class and has only one derived class.

• Stream: A stream is a source of sequence of bytes. A stream abstracts for

input/output devices.

• Class template: It is a template used to generate template classes

Check Your Progress: Answers

1. c) function
2. c) both a & b
3. a) __cdecl
4. c) 40
5. d) 22
6. a) d99
7. d) compile time error
8. c) data types
9. c) functions
10. b) ptr is array of pointer to function.

Amity Directorate of Distance & Online Education

212 Object Oriented Programming Concept Using C++

8.21 Further Readings

Notes • Balagurusamy (2008) Object Oriented Programming With C++ Tata McGraw-
Hill Education.
• Subhash, K. U. (2010) Object Oriented Programming With C++ Pearson
Education India.

Amity Directorate of Distance & Online Education