Beruflich Dokumente
Kultur Dokumente
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.
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;
}
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.
Notes
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
There is a close relationship between pointers and arrays. Consider this program
fragment:
Notes
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;
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";
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
byte.
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.
class pwr {
double b;
int e;
double va1;
public:
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);
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
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.
Notes
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;
Public:
Void display() {……} //display in base class
};
Class bb : public aa
{
Int y;
Public:
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
{
public:
void display()
{
bptr ->display();
calls only the function associated with the Base (i.e. Base :: display( ) ) whereas the
statement
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.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.
Notes
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
max<double>
std::cout << max<double>(3, 7.0) << std::endl;
return 0;
}
T pivotvalue = a[leftarg];
int left = leftarg - 1;
int right = rightarg + 1;
for(;;) {
T temp = a[right];
a[right] = a[left];
a[left] = temp;
}
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
The following program reads an integer and prints the input on the console.
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
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
int main(void)
{
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
return 0;
}
When the above code is compiled and executed, it produces the following result:
Total area: 35
};
};
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
{
};
};
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>
// Derived class
class Rectangle: public Shape, public PaintCost
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
return 0;
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
language
#include <iostream>
Notes {
int main()
int a;
cout << a;
return 0;
}
a) 25
b) 35
c) 40
d) 45
#include <iostream>
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
#include <iostream>
int main()
(*p)('d', 9);
p(10, 9);
return 0;
return 0;
}
a) d99
b) d9d9
c) d9
d) compile time error
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
• Single level inheritance: In single level inheritance, there is only one base
class and has only one derived class.