Professional Documents
Culture Documents
Pointers, Virtual Functions & Polymorphism
Pointers, Virtual Functions & Polymorphism
Polymorphism
In C++
Pointers
Pointer is a derived data type that refers to the address of another
variable. A pointer variable tells that where to get the data
instead of telling the actual data.
At any point of time a pointer variable can point to only one data
type. Int *ptr;
Here ptr contains the memory location of any integer variable.
e.g. int *ptr , a; //Declaration
ptr=&a; //Initialization
Pointers
We can also declare a Pointer variable that points to
another variable.
Important:
1. Generic Pointers or Void Pointers: Pointers that can
refer to variables of any data type. Before using
these pointers, we must type cast the variables to the
specific data types that they point to.
2. Null Pointers: The Pointers that are not initialized in
the program.
3. Pointers of any data type can be assigned with one
value i.e. ‘0’ called null address.
Manipulation of Pointers
To access the values and making the changes in the
values of the variables, we use the indirection
operator i.e. “*”, It is also called deference operator.
e.g the statement A.max() will set the pointer this to the address
of the object A.
• The function will return the object B (argument object) if the age of the
person B is greater than that of A, otherwise, it will return the object A
(invoking object) using the pointer this.
#include <iostream> int main()
using namespace std; {
class pwr { pwr x(4.0, 2), y(2.5, 1), z(5.7, 0);
cout << x.get_pwr() << " ";
double b;
cout << y.get_pwr() << " ";
int e; cout << z.get_pwr() << "\n";
double val; return 0;
public: }
pwr(double base, int exp);
double get_pwr() { return val; }
};
//Version of pwr using this pointer
pwr::pwr(double base, int exp)
pwr::pwr(double base, int exp)
{ {
b = base; this->b = base;
e = exp; this->e = exp;
val = 1; this->val = 1;
if(exp==0) return; if(exp==0) return;
for( ; exp>0; exp--)
for( ; exp>0; exp--) val = val * b;
this->val = this->val * this->b;
} }
Memory Management Operators
• C++ supports two unary operators to perform DMA, As these operators
manage memory on free store they are called free store operators .
• An object created by new can be destroyed by delete operator. Such as:
pointer_variable=new data_type
• Here new allocates the sufficient memory to the object of type data_type,
and assigns the address of that location in pointer_variable.
• If sufficient memory is not available then the new will return a null pointer.
• So it is better to check dynamically that memory has been allocated or not.
p=new int;
if(!p)
{ cout<<“Allocation Failed \n”; }
#include <iostream> #include <iostream>
#include <new> #include <new>
using namespace std; using namespace std;
int main()
int main()
{
{ int *p, i;
int *p; try {
try { p = new int [10]; // allocate 10 integer array
p = new int (87); // initialize to 87 } catch (bad_alloc xa) {
} catch (bad_alloc xa) { cout << "Allocation Failure\n";
return 1;
cout << "Allocation Failure\n";
}
return 1;
} for(i=0; i<10; i++ )
cout << "At " << p << " "; p[i] = i;
cout << "is the value " << *p << "\n"; for(i=0; i<10; i++)
delete p; cout << p[i] << " ";
delete [] p; // release the array
return 0;
return
}
Advantages of new over malloc()
1. It automatically computes the size of the data object. We need not use the
operator sizeof.
Problem: here is that pointer to the object of the derived class will
point only to those members of D that have been inherited
from the base class. It cannot access the original members of
the class D. If we have a member function with the same
name in the base class and in the derived class then cptr will
always access the base class member.
In C++
Introduction
We may have a case where all the kinds of Inheritance namely multilevel,
multiple, hierarchical are involved.
Grand Parent
Parent 1 Parent 2
Child
Here the Grandparent is sometime referred to a Indirect base Class. Here the
problem arises that the members of the Grandparent class are inherited
twice, through Parent1 and Parent2, hence it gets the duplicate copies.
This duplication can be avoided by making the common Base class as Virtual
base class, while declaring the direct or Intermediate base classes.
Introduction
As Shown:
Class A // Grandparent
{ :::::::
};
Class B1 : Virtual Public A // Parent1
{ ::::::::::
};
Class B2: public Virtual A // Parent2
{ :::::::::
};
Class c: public B1, public B2 //Child
{ :::::::::::: // Here only one copy of A will be
}; // Inherited
Here Virtual and Public can be used in either order. Program Example:
Abstract Class
An Abstract Class is the one, that is not used to create objects. It is used
only to act as Base Class. It is just a design concept in programming, It acts
as a base on which the other classes may be built.
Constructors in Derived Classes
When both the base class and the derived class have the constructors, then the
base constructor is executed first, then the Derived Constructor.
As long as the base class Constructor doesn’t takes any arguments, the derived
class need not have a constructor function. We know that in Inheritance the
object generally is created of the derived class, then it Is the responsibility
of the derived class to pass the arguments to the base class.
In case of Multiple Inheritance: The base classes are constructed in the order
in which they appear in the declaration of the derived class. Similarly
When we create an object of the derived class only then by which mechanism
the arguments are distributed to the various base classes?
Constructors in Derived Classes
The constructor of the derived class receives the entire arguments and then distributes
all of them in the order in which they have been declared in the derived class.
The Base class Constructors are called and executed first then only the derived class
constructors are called and executed.
Derived-Constructer ( ArgList1, Arglist2, … ArglistN, Arglist(D)) :
base(arglist1),
base(arglist2),
:::::::::::::::::
base N(arglistN), arguments for base(N)
{ Body of derived Constructor
}
The header line of the derived-constructor function contains two parts separated by
colon , The first part provides the declaration of the arguments that are passed to the
derived-constructor and the second part lists the function calls to the base
constructors.
base(arglist1), base(arglist2) .. Are the function calls to the base constructors base1(),
base2(). ArglistD provides the parameters that are necessary to initialize the
members of the derived class.
Constructors in Derived Classes
For Example:
D(int a1, int a2, float b1, float b2, int d1):
A(a1, a2),
B(b1,b2)
{
d=d1;
}
Here A(a1, a2) invokes the constructor of Class A and B(b1, b2) invokes the
constructor of Class B. The D() has one argument for itself.
D objD(5, 12, 2.5, 7.54, 30) ;
5 goes to a1, 12 goes to a2, 2.5 goes to b1, 7.54 goes to b2, and 30goes to d1.
The Constructors for virtual base class are invoked before any non-virtual base classes.
If there are multiple virtual base classes, they are invoked in the order in which they
are declared. Any Non-virtual bases are then constructed before the derived class
constructor is executed.
Example;
Constructors in Derived Classes
• Another method to initialize the objects is by using the initialization List in the Constructor
Function.
constructor (arglist): initialization-section
{ assignment-section
}
We can use the initialization section to provide initial values to the base constructors and also to
initialize its own class members. E.g.
Class xyz
{
int a; int b;
Public:
xyz( int I, int j) : a(i), b( 2 * j ) { }
};
Main()
{
xyz x(2 3,);
}
Here a is 2, b is 6.
If we have xyz(int I, int j) : b( I ) , a ( I + j ) { } Then the values are a=5, b=2
Example:
Virtual Functions
• Virtual function is a member function that is declared within a base class and
redefined by a derived class
• When a class containing a virtual function is inherited, the derived class redefines
the virtual function to fit its own needs.
• Virtual functions implement the "one interface, multiple methods" philosophy that
underlies polymorphism.
• When a base pointer points to a derived object that contains a virtual function, C++
determines which version of that function to call based upon the type of object
pointed to by the pointer
• This determination is made at runtime. Thus, when different objects are pointed to,
different versions of the virtual function are executed.
#include <iostream> int main()
using namespace std; {
class base { base *p, b;
public: derived1 d1;
derived2 d2; // point to base
virtual void vfunc() {
p = &b;
cout << "This is base's vfunc().\n"; p->vfunc(); // access base's vfunc()
}
}; // point to derived1
class derived1 : public base { p = &d1;
public: p->vfunc();
// access derived1's vfunc()
void vfunc() {
cout << "This is derived1's vfunc().\n"; // point to derived2
} p = &d2;
}; p->vfunc(); //access derived2's vfunc()
class derived2 : public base { return 0;
public: }
void vfunc() {
cout << "This is derived2's vfunc().\n";
}
};
#include <iostream>
using namespace std; int main()
{
class base { base* bptr;
public: derived d;
virtual void print() bptr = &d;
{
cout << "print base class" << endl; // virtual function, binded at runtime
} bptr->print();
//Here, Derived version of print will be called
void show()
{
cout << "show base class" << endl; // Non-virtual function, binded at compile time
} bptr->show();
}; //Base version of show will be called
}
class derived : public base {
public:
void print()
{
cout << "print derived class" << endl;
}
void show()
{
cout << "show derived class" << endl;
}
};
Virtual Functions
Note:
•We must access virtual functions through the use of a pointer declared as a
pointer to a base class.
•Although you can call a virtual function in the "normal" manner by using an
object's name and the dot operator, it is only when access is through a
base-class pointer (or reference) that run-time polymorphism is achieved.
The opposite of early binding is late binding. As it relates to C++, late binding refers to
function calls that are not resolved until run time. Virtual functions are used to achieve
late binding. As you know, when access is via a base pointer or reference, the virtual
function actually called is determined by the type of object pointed to by the pointer.
Because in most cases this cannot be determined at compile time, the object and the
function are not linked until run time. The main advantage to late binding is flexibility.
Unlike early binding, late binding allows you to create programs that can respond to
events occurring while the program executes without having to create a large amount
of "contingency code." Keep in mind that because a function call is not resolved until
run time, late binding can make for somewhat slower execution times.
Virtual Destructor
• A virtual destructor is used to free up the memory space allocated by the derived
class object or instance while deleting instances of the derived class using a base
class pointer object.
• A base or parent class destructor use the virtual keyword that ensures both base
class and the derived class destructor will be called at run time, but it calls the
derived class first and then base class to release the space occupied by both
destructors.
• When an object in the class goes out of scope or the execution of the main()
function is about to end, a destructor is automatically called into the program to free
up the space occupied by the class' destructor function. When a pointer object of the
base class is deleted that points to the derived class, only the parent class destructor
is called due to the early bind by the compiler. In this way, it skips calling the
derived class' destructor, which leads to memory leaks issue in the program. And
when we use virtual keyword preceded by the destructor tilde (~) sign inside the
base class, it guarantees that first the derived class' destructor is called. Then the
base class' destructor is called to release the space occupied by both destructors in
the inheritance class.
#include<iostream> class Derived: public Base
{
using namespace std;
public:
class Base Derived() // Constructor function
{ {
public: cout << "\n Constructor Derived class" ;
Base() // Constructor function. }
{ ~Derived() // Destructor function
{
cout<< "\n Constructor Base class";
cout << "\n Destructor Derived class" ; /* Destructor
} function is not called to release its space. */
~Base() // Destructor function }
{ };
cout<< "\n Destructor Base class"; int main()
} {
Base *bptr = new Derived; // Create a base class pointer
};
object
delete bptr; /* Here pointer object is called to delete the
space occupied by the destructor.*/
}
Output:
Constructing base
Constructing derived
Destructing base
#include<iostream> class Derived: public Base
using namespace std; {
class Base public:
Derived() // Constructor function.
{
{
public: cout << "\n Constructor Derived class" ; /* After
Base() // Constructor member function. print the Constructor Base, now it will prints. */
{ }
cout << "\n Constructor Base class"; ~Derived() // Destructor function
} {
cout << "\n Destructor Derived class"; /* The
virtual ~Base() // Define the virtual destructor
virtual Base Class Destructor calls it before calling
function to call the Destructor Derived function.
the Base Class Destructor. */
{ }
cout << "\n Destructor Base class"; / };
}
}; int main()
{
Base *bptr = new Derived; // A pointer object
reference the Base class.
Output: delete bptr; // Delete the pointer object.
Constructing base }
Constructing derived
Destructing derived
Destructing base