Uploaded by ANUBHAV GAUTAM

Polymorphism

advertisement
Polymorphism
contents
• Dynamic Memory Allocation
– new and delete operators
•
•
•
•
this pointer
Method overriding & virtual function
Pure virtual Function
abstract base class
2
Pointers and Dynamic Memory
Allocation with
new and delete operators
3
Pointer’s review
• Let a variable aa be defined as ‘int *aa;’, what is
stored in aa?
• Why we should NOT return a pointer to a local
variable?
• What is the pointer form of aa[100]?
• What does the NULL pointer mean?
• What is the relation between pointer and
reference?
• What is the output of the following code?
int a = 5;
int *ptr = &a;
cout << ptr;
cout << *ptr;
4
Memory Allocation
• There are essentially two types of memory
allocation
Static – Done by the compiler automatically (implicitly).
Global variables or objects -- memory is allocated at the start
of the program, and freed when program exits; alive
throughout program execution
– Can be access anywhere in the program.
Local variables (inside a routine) – memory is allocated when
the routine starts and freed when the routine returns.
– A local variable cannot be accessed from another routine.
Allocation and free are done implicitly.
No need to explicitly manage memory is nice (easy to work
with), but has limitations!
Using static allocation, the array size must be fixed.
Consider the grade roster for the class? What is the number of
people in the class?
5
Memory Allocation
• There are essentially two types of memory
allocation
Wouldn’t it be nice to be able to have an array
whose size can be adjusted depending on needs.
Dynamic memory allocation deals with this situation.
Dynamic
Dynamic – Done explicitly by programmer.
Programmer explicitly requests the system to allocate
memory and return starting address of memory
allocated (what is this?). This address can be used by
the programmer to access the allocated memory.
When done using memory, it must be explicitly freed.
6
Explicitly allocating memory in C++: The
‘new’ Operator
• Used to dynamically allocate memory
• Can be used to allocate a single variable/object or an array of
variables/objects
• The new operator returns pointer to the type allocated
• Examples:
– char *my_char_ptr = new char;
– int *my_int_array =new int[20];
– Mixed *m1 = new Mixed(1,1,2);
– Before the assignment, the pointer may or may not point to a legitimate
memory
– After the assignment, the pointer points to a legitimate memory.
7
Explicitly freeing memory in C++: the
‘delete’ Operator
• Used to free memory allocated with new operator
• The delete operator should be called on a pointer to dynamically
allocated memory when it is no longer needed
• Can delete a single variable/object or an array
delete PointerName;
delete [] ArrayName;
• After delete is called on a memory region, that region should no
longer be accessed by the program
• Convention is to set pointer to deleted memory to NULL
Any new must have a corresponding delete --- if not, the program has
memory leak.
New and delete may not be in the same routine.
8
Why use dynamic memory allocation?
• Allows data (especially arrays) to take on
variable sizes (e.g. ask the user how many
numbers to store, then generate an array of
integers exactly that size).
• Allows locally created variables to live past
end of routine.
• Allows us to create many structures used in
Data Structures and Algorithms
9
The . and -> operators
• The dot operator is used to access an object’s
members
– M1.Simplify();
– M1.num = 5;
• But how do we access an objects members if we
only have a pointer to the object?
• If we have M1_ptr = &M1, Perhaps we would
use (*(M1_ptr)).Simplify()
• A shorthand for this is the arrow operator
– M1_ptr->Simplifly() is equivalant
to(*(M1_ptr)).Simplify()
10
Objects and Pointers
• Objects can also be pointed to by pointers
– Once declared, a class becomes a valid type, so it can be used as
the type pointed to by a pointer.
– For example:
Class Rectangle
{
//definition
};
main()
{
Rectangle * prect;
}
is a pointer to an object of class Rectangle.
• the members of an object can be accessed directly from a
pointer by using the arrow operator (->).
11
Example#1
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char *MyCharPointer = new char;
char *MyCharArray = new char[30];
strcpy(MyCharArray,"This is a basic example\n");
*MyCharPointer='a';
cout<<MyCharArray<<*MyCharPointer;
delete MyCharPointer;
delete [] MyCharArray;
return 0;
}
12
Example 2: Pointer to a class
// pointer to classes example
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
Rectangle(int x, int y) : width(x),
height(y) {}
int area(void)
{ return width * height; }
};
int main() {
Rectangle obj (3, 4);
Rectangle * foo, * bar, * baz;
foo = &obj;
bar = new Rectangle (5, 6);
baz = new Rectangle[2] { {2,5}, {3,6} };
cout << "obj's area: " << obj.area() << '\n';
cout << "*foo's area: " << foo->area() << '\n';
cout << "*bar's area: " << bar->area() << '\n';
cout << "baz[0]'s area:" << baz[0].area() << '\n';
cout << "baz[1]'s area:" << baz[1].area() << '\n';
delete bar;
delete[] baz;
return 0;
}
13
this pointer
14
this pointer: Introduction
• The Problem: “Inside of a class you have access to all of the private data,
but how do you access the object itself like a client would?”
• Each object maintains a pointer to itself which is called the “this” pointer.
• Each object can determine it’s own address by using the “this” keyword.
• this is a local object pointer in every instance member function containing
the address of caller object
– this cannot be modify
– It is used to refer caller object in member function
• Many member functions of a class in C++ require no arguments because of
the use of the implicit pointer “this”.
• It may seem redundant but the “this” pointer does have some uses:
– Prevents an object from being assigned to itself.
– Enables cascading member function calls.
15
Example # 1
// Example of using the this pointer
#include <iostream.h>
using namespace std;
class Test{
public:
Test (int=0);
void print () const;
private:
int x;
};
16
Example # 1 : contd
Test::Test (int a ) // Constructor
{ x = a;}
void Test::print() const
{
cout << " x is equal to " << x ;
cout << "\n this-> is equal to "<<this->x;
cout << "\n (*this).x is equal to "<< (*this).x <<endl;
}
int main (void)
{
Test testobject1(12),testobject2(15);
testobject1.print();
testobject2.print();
return 0;
}
17
Example#2
class Box
{
int main (void)
{
private:
Box smallbox,bigbox;
int l,b,h;
smallbox.setdimension(2,3,4);
public:
smallbox.showdimension();
void setdimension(int l,int b,int h)
bigbox.setdimension(15,20,25);
{
bigbox.showdimension();
this->l=l; this->b = b; this->h=h;
return 0;
}
}
void showdimension()
{
cout<<"lenth="<<l<<endl<<"breadth="<<b<<endl<<"height="<<h<<endl;
//cout<<"lenth="<<this->l<<endl<<"breadth="<<this->b<<endl<<"height="<<this>h<<endl; // equivalent
//cout<<"lenth="<<(*this).l<<endl<<"breadth="<<(*this).b<<endl<<"height="<<(*t
his).h<<endl; //equivalent
}
};
18
Dynamic Allocation and
Polymorphism
19
Introduction
• “the same thing but in different forms”.
• In C++ the meaning of polymorphism is the
ability to access different implementations of a
function using the same name.
• It builds upon Inheritance
• Key topic : Inheritance + Pass by reference
• There is two levels at which polymorphism
operates:
– Compile time polymorphism
– Run time polymorphism
20
Polymorphism
• CTP
– Early binding or static binding or static linking. Also
known as compile time polymorphism, simply means that
an object is bound to its function call at compile time
– Implemented using overloaded functions and operators
• RTP
– In this polymorphism function is linked with a particular
class much later after the compilation and the selection
of appropriate function is done dynamically at run time
– therefore this type of polymorphism is also known as late
binding or dynamic binding.
21
22
Pointers to Objects
• A pointer can point to an object created by a class
– suppose that sd1 is an object of class student as
student sd1;
• Object pointer “ptr” of type student can be created as below
student sd1;
student *ptr;
ptr= &sd1;
• the pointer “ptr” can be initialized with the address of sd1
• We can refer to members either by using arrow and the object pointer
ptr - > display ( ); or
by using ( . ) operator and object pointer
(*ptr) . display ( );
• Since dot operator (.) has higher precedence than the indirection operator( )
parenthesis is needed. We can create the objects of a class using pointer and
new operator as below
• student *ptr = new student; //allocates memory and assigns the
23
address of memory space to pointer “ptr”
Pointer to derived Classes
The C++ pointer rule:
• A pointer declared as pointing to base class can be used to
point to an object of the derived class of that base class
– But a pointer to a derived class can not be used to point an
object of the base class or to any of the derived classes of the
base class.
• By using base class pointer, we can access only those
members which are inherited from the base class
– and not the members that originally belong to derived class.
– In other words, a base pointer can point to any object derived
form that base but the pointer can not be directly used to
access all the members derived by a derived class.
• Pointers to objects of a derived class are type compatible
with pointers to object of base class.
24
Pointer to derived Classes
• Pointers can be used not only to base objects but
also to objects of derived classes
• Pointers to objects of a base are type-compatible
with pointers to objects of a derived class
• Therefore, a single pointer variable can be made to
point to objects belonging to different classes
• But there is a problem in using pointer to access the
public
• members of the derived class
• Only those members that are inherited from base
class can be accessed
• Those members which originally belong to derived
class cannot be accessed.
25
Pointer to derived Classes
• In case a member of derived class has the
same name as one of the members of base
class, then any reference to that member by
pointer will always access the base class
member.
26
Rules in C++ for Pointers
27
Rules in C++ for Pointers [contd…]
28
sample program 1: access from pointer
#include<iostream>
using namespace std;
class Base
{
public:
void show ( )
{
cout<<"show function from base class"<<endl;
}
};
class Derive1 : public Base
{
public:
void show ( )
{
cout<<" show function from Derive1 class"<<endl;
}
};
contd…
29
sample program 1: access from pointer
class Derive2 : public Base
{
public:
void show ( )
{
cout<<" show function form Derive2 class "<<endl;
}
};
int main ( )
{
Derive1 dv1;
Derive2 dv2;
Base *ptr; //pointer to base class
ptr=&dv1; // put adress of dv1 in pointer pr
ptr ->show ( );
ptr= &dv2;
ptr->show ( );
return 0;
}
30
Discussion Sample Program 1
Reason of this output:
• Because the compiler ignore the contents of pointer “ptr” and chooses
the member function that matches the type of the pointers i.e. Base
class type
• If we change void show ( ) function in base class into virtual void show ( )
function then the output of the program will be changed as below:
Output:
show function from Derive1 class
show function form Derive2 class
• The same function call ptr -> show ( ) executes different functions
depending on the contents of pointer.
RULE
• The compiler selects the function based on the content of the pointer,
not the type of the pointer, once we make the same function i.e. void
show ( ) a virtual function in Base class.
• This is due to type compatibility of the pointer.
31
Pointers to base class
// pointers to base class
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
};
class Rectangle: public Polygon {
public:
int area()
{ return width*height; }
};
class Triangle: public Polygon
{
public:
int area()
{ return width*height/2; }
};
int main () {
Rectangle rect;
Triangle trgl;
Polygon * ppoly1 = ▭
Polygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << rect.area() << '\n';
cout << trgl.area() << '\n';
return 0;
}
32
Method overriding, Method hiding and method overloading
• The method overloading feature is very helpful in code
reusability by creating a different version of a method,
meaning method overloading is nothing but a technique to
create two or more methods of the same name but
different signatures.
• Method / Function overloading is multiple methods in a
class with the same name but different signatures.
• Method overriding is a feature by which a derived class can
provide a new implementation for the base class method
having the same name and signature as in a derived class.
• Method hiding : A member function of a derived class with
the same name as a function in the base class hides all
functions in the base class with that name. In such a case
Only the derived class function can be called directly. The
class scope resolution operator :: must be used to call
hidden base functions explicitly.
33
class A
{
public:
void f1(){cout<<"Hello A\n";}
void f2(){cout<"Hello F2 of A\n";}
};
class B: public A
{
private:
int x;
public:
void f1(){cout<<"Hello B\n";}
void f2(int a) //method hiding
{
cout<<"Hello F2 of B"<<endl;
}
void f3() {cout<<"I am overloaded f3 without
argument\n";}
void f3(int k) {cout<<"I am overloaded f3 with
argument\n";}
};
int main()
{
B b;
b.f1(); //method overriding
//b.f2(); //Error
b.f2(1); // method hiding
b.f3(); //method overloading
b.f3(10); //method overloading
}
34
Virtual members
35
Virtual Function
• Polymorphism refers to the property by which objects
belonging to different classes are able to respond to the
same message, but in different forms
• An essential requirement of polymorphism is therefore the
ability to refer to objects without any regard to their
classes.
• This necessitates the use of single pointer variable to refer
to the objects of different classes
• When we use same function name in both base and
derived classes, the function in base class is declared as
virtual.
• When a function is made virtual, C++ determines which
function to use at run time based on the type of object
pointed by the base pointer rather than the type of the
pointer
36
Virtual Function
• We must access virtual function through the use
of pointer declared as a pointer to the base
class.
• Why can’t we use the object name with dot
operator the same way as any other member
function to call the virtual function?
• Yes, we can but run time polymorphism is
achieved only when a virtual function is
accessed through a pointer to the base class.
37
Rules for Virtual Functions
• The virtual function must be member of some class,
cannot be static member
• They are accessed by using object pointer
• A virtual function can be a friend of another class
• The prototypes of base class version of virtual function
and all derived class version must be identical
• We cannot have virtual constructors but can have virtual
destructors
• While a base class pointer can point to any type of derived
object, the reverse is not true
• When a base pointer points to a derived class,
incrementing or decrementing it will not make it point to
the next object of derived class
38
Virtual Function
• Existing in appearance but not in reality.
• Virtual functions are needed to perform a particular
operation using the same function call by objects of
different classes.
– Example: By using a single “draw” function we can draw
different shapes, circle, rectangle, triangle and so on. For this,
object of different classes are used to call the same function.
– For dynamic binding of member functions, C++ uses the
concept of virtual function.
• Virtual functions are the functions which are declared with
the keyword virtual in the base class
virtual void dispdata ( )
{
cout<<”This is C-era”;
}
39
// virtual members
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area ()
{ return 0; }
};
class Rectangle: public Polygon {
public:
int area ()
{ return width * height; }
};
class Triangle: public Polygon {
public:
int area ()
{ return (width * height / 2); }
};
int main () {
Rectangle rect;
Triangle trgl;
Polygon poly;
Polygon * ppoly1 = ▭
Polygon * ppoly2 = &trgl;
Polygon * ppoly3 = &poly;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly3->set_values (4,5);
cout << ppoly1->area() << '\n';
cout << ppoly2->area() << '\n';
cout << ppoly3->area() << '\n';
return 0;
}
40
Virtual Function contd…
• Virtual functions may or may not be implemented in the derived classes.
If it is implemented the declaration must be identical to that of the base
class except for the word “virtual” as below:
void dispdata ( )
{
cout << “I am a C – student”;
}
Notes:
• Once a function is declared as a virtual function then its redefinition in
subsequent derived classes are dynamically binded, and they are also by
default virtual functions.
• All re-definition of functions in derived classes are treated as virtual
provided they match the base class function precisely (exactly) in terms
of the member and types of argument passed. If they do not match
exactly then they will be treated as ordinary overloaded function.
• A virtual function in a base class may or may not be defined. If they are
not defined then they must be declared as “pure”.
41
Example# without VF
#include<iostream>
using namespace std;
class Enemy
{
protected:
int attackPower;
public:
void SetAttackPower(int a)
{
attackPower=a;
}
};
class Ninja:public Enemy
{
public:
void attack()
{
cout<<" I am Ninja and I am chopping you with "<<attackPower<<" power."<<endl;
}
};
42
Example# withoud VF contd..
class Monster: public Enemy
{
public:
void attack()
{
cout<<" I am Monster and I am eating you with "<<attackPower<<" power."<<endl;
}
};
int main()
{
Ninja n;
Monster m;
Enemy *Enemy1=&n; // because ninja is of type enemy this is valid
Enemy *Enemy2=&m; // anything that an enemy can do, monster can do
Enemy1->SetAttackPower(100); // ninja is just a more specific type of enemy
Enemy2->SetAttackPower(50); //every enemy has setattack power
n.attack(); // cannot use enemy1 because its type is enemy
m.attack(); // enemy class does not have attack function
return 0; // virtual member make this even easier
}
43
Use of Virtual function
#include<iostream>
using namespace std;
class Enemy
{
protected:
int attackPower;
public:
void SetAttackPower(int a)
{
attackPower=a;
}
virtual void attack()
{
cout<<" I am enemy attack\n";
}
};
class Ninja:public Enemy
{
public:
void attack()
{
cout<<" I am Ninja and I am chopping you with "<<attackPower<<" power."<<endl;
}
};
44
class Monster: public Enemy
{
public:
void attack()
{
cout<<" I am Monster and I am eating you with "<<attackPower<<" power."<<endl;
}
};
int main()
{
Ninja n;
Monster m;
Enemy *Enemy1=&n;
Enemy *Enemy2=&m;
Enemy1->SetAttackPower(100);
Enemy2->SetAttackPower(50);
Enemy1->attack();
Enemy2->attack();
return 0;
}
45
Pure Virtual Function
• A pure virtual function is one with the expression “= 0” (zero not ohh)
added to the declaration
– in other words a pure virtual function is one which is declared with a
keyword “virtual” and initialize to zero.
– The “= 0” syntax is simply how we tell the compiler that a virtual function
will be pure.
– Pure virtual function are functions without definition [body]
• The “=” sign here, has nothing to do with assignment, the value zero is
not assigned to anything.
• A pure virtual function can be declared as pure by any of the following
ways:
–
–
–
–
•
a) virtual <return type> <function name> (…) = 0;
b) virtual <return type> <function name> (…)
c) { ………. ; }
d) virtual void show () -0; //pure virtual function;
A pure virtual function does not contain any effective code i.e. there is
no implementation of function within the class where the function was
declared. It provides an interface for the class hierarchy.
46
Pure Virtual Function
• A virtual function is usually declared in base class and
redefined in the derived classes.
• The function in base class only serves as place
holders, also are “empty”.
• If we define such functions as:
– virtual void display()=0;
• Such functions are called pure virtual functions.
• The derived classes should either define the function
or re-declare it as pure virtual.
• The class containing pure virtual function cannot be
used to declare any object of its own.
• Such classes are called abstract base classes
47
Example# PVF
#include<iostream>
using namespace std;
class Base
{
public:
virtual void show ( )=0; //pure virtual function
};
class Derive1 : public Base
{
public:
void show ( )
{
cout<<"show function from Derive1 class"<<endl;
}
};
48
Example#1: contd..
class Derive2 : public Base
{
public:
void show ( )
{
cout<<"show function form Derive2 class"<<endl;
}
};
int main ( )
{
Base *arr[2]; //pointer to base class
Derive1 dv1;
Derive2 dv2;
arr[0]=&dv1; // put address of dv1 in pointer
arr[1]= &dv2;
arr[0] ->show ( );
arr[1]->show ( );
return 0;
}
49
Pure Virtual Function
and
Abstract Class
50
Abstract Classes
• An abstract class is a class with at least one pure
virtual function.
– Objects of an abstract class can not be defined, but they
are used to derive child class. A pointer to abstract class
can be derived.
• e.g. the following class AbstractX is an abstract class
class AbstractX
{
public:
void function1 ( );
virtual void vf1 ( ) = 0;
virtual void vf2 ( ) =0;
};
51
Abstract Classes
Notes:
a) An abstract class can be used as base class only for other
classes. No object of an abstract class can be declared.
Abstract class // illegal
AbstractX x; //attempt to create an object of the
abstract class
b) An abstract class can not be specified as an argument
type or as a function return type.
int abs1 (AbstractX x); // X being an abstract class, can
not pass anything to the function
AbstractX abs2 (int i); //Error- nothing can be returned to an
Abstract X’s object i.e. object of an abstract class is not possible to hold any
value.
52
Abstract Classes
c) Member functions in an abstract class may be called from a constructor
of abstract class but calling pure virtual function either directly or in
directly form such a constructor provokes run time error.
AbstractX ( ) // constructor
{
vf2 ( ); //error-direct call of vf2 which is a “pure” virtual function
}
void configuration ( )
{
vf2 ( ); // error- indirect call of vf2 which is a “pure” virtual function
}
d) The actual use of declaring a class as an abstract class is to implement
the dynamic binding in C++. An abstract class is always a base class and
contains member function/s as pure virtual function which resolves the
reference of the function name dynamically in later derived classes.
53
// abstract base class
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area (void) =0;
};
class Rectangle: public Polygon {
public:
int area (void)
{ return (width * height); }
};
class Triangle: public Polygon {
public:
int area (void)
{ return (width * height / 2);
}
};
int main () {
Rectangle rect;
Triangle trgl;
Polygon * ppoly1 = ▭
Polygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << ppoly1->area() << '\n';
cout << ppoly2->area() << '\n';
return 0;
}
54
// pure virtual members can be called
// from the abstract base class
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
virtual int area() =0;
void printarea()
{ cout << this->area() << '\n'; }
};
class Rectangle: public Polygon {
public:
int area (void)
{ return (width * height); }
};
class Triangle: public Polygon {
public:
int area (void)
{ return (width * height / 2); }
};
int main () {
Rectangle rect;
Triangle trgl;
Polygon * ppoly1 = ▭
Polygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
ppoly1->printarea();
ppoly2->printarea();
return 0;
}
55
// dynamic allocation and polymorphism
#include <iostream>
using namespace std;
class Polygon {
protected:
int width, height;
public:
Polygon (int a, int b) : width(a), height(b)
{}
virtual int area (void) =0;
void printarea()
{ cout << this->area() << '\n'; }
};
class Rectangle: public Polygon {
public:
Rectangle(int a,int b) : Polygon(a,b) {}
int area()
{ return width*height; }
};
class Triangle: public Polygon {
public:
Triangle(int a,int b) : Polygon(a,b)
{ }
int area()
{ return width*height/2; }
};
int main () {
Polygon * ppoly1 = new Rectangle
(4,5);
Polygon * ppoly2 = new Triangle
(4,5);
ppoly1->printarea();
ppoly2->printarea();
delete ppoly1;
delete ppoly2;
return 0;
}
56
Download