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 = &rect; 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 = &rect; 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 = &rect; 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 = &rect; 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