1 / 46

Chapter 7 Virtual Functions and Dynamic Polymorphism

Chapter 7 Virtual Functions and Dynamic Polymorphism. Objectives. The need for virtual functions About virtual functions The mechanism of virtual functions Pure virtual functions and abstract base class Virtual destructors and constructors. The Need for Virtual Functions.

Download Presentation

Chapter 7 Virtual Functions and Dynamic Polymorphism

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 7Virtual Functions and Dynamic Polymorphism

  2. Objectives • The need for virtual functions • About virtual functions • The mechanism of virtual functions • Pure virtual functions and abstract base class • Virtual destructors and constructors

  3. The Need for Virtual Functions • Example 1 shows overriding member function of base class in the derived class. Example 1: class A { public: void show() { cout<<“show A\n” } }; class B: public A { public: void show() { cout<<“show B\n” } }; • Example 2 shows calling an overridden function through a pointer of base class type: Example 2: void main() { A *Aptr; A A1; B B1; Aptr=& A1; Aptr->show(); Aptr=&B1; Aptr->show(); }

  4. The Need for Virtual Functions • In the Example 2, the base class function is called irrespective of the type of object pointed at by the pointer. • The compiler decides which function is to be called by considering the type of the pointer; the type of the object pointed at by the pointer is not considered. • Overriding in such cases is ineffective. This can be a serious problem when a client is trying to extend a class hierarchy. • Calling an overridden function through a reference of base class type produces the same effect. (See Example 3). Example 3 void main() { A A1; B B1; A &Aref1= A1; Aref1.show(); A &Aref2 = B1; Aref2.show(); }

  5. The Need for Virtual Functions • Placing the pointer and the object pointed at by the pointer in the same function as local variables does not solve the issue since an object can be as effectively accessed through its name itself. • Instead, the pointer appears as a formal argument in function definitions and the address of the object is passed as a parameter to the function calls. Similar comments hold true for the reference variable also. • Calling an overridden function through a pointer of base class type, where the base class function will get successively refined by the overriding functions of the derived classes, is also ineffective. (See Example 4).

  6. The Need for Virtual Functions Example 4 class X {public: void abc(A *); } void X::abc (A *p) { p->show(); } void main() { X X1; A A1; B B1; X1.abc(&A1); // A::show() will be called X1.abc(&B1); // A::show() will be called } • Thus, it proves impossible to extend an existing class hierarchy. Function overriding does not produce the desired effects. Virtual functions solve this problem.

  7. Virtual Functions • Virtual functions provide one of the most useful and powerful features of C++ called dynamic polymorphism. Consider the following example for understanding this concept . Suppose the library programmer has to write a code for computing sum between the ranges a and b (factorial sum , cube sum, log sum etc.) and the application programmer can select any of the sum function available in the library, just by passing the function name as an argument to the function generic Sum function: Example 5: intfactSum(int a, int b) { inti; long sum; for (sum=0, i=a; i<=b;i++) sum+=fact(i); return sum;}

  8. Virtual Functions Example 6: intCubeSum(inta, int b) { inti; long sum; for (sum=0, i=a; i<=b;i++) sum+=cube(i); return sum;} Example 7: intLogSum(inta, int b) { inti; long sum; for (sum=0, i=a; i<=b;i++) sum+=log(i); return sum;}

  9. Virtual Functions • From the 3 mentioned functions it is clear that the definitions are same except the name of the inner function they all call. • So it is possible to replace the definition of these functions by a single function. The example 8 shows a generic function that will replace all 3 functions . • For this we have to pass a function pointer as an additional formal argument: Example 8: long intGenericSum(int a, int b, long int (*p )(inti) ) { inti; long sum; for (sum=0, i=a; i<=b;i++) sum+=(*p) (i); return sum;} • Now, any of the sum function can be called by passing the function whose returned values have to be summed up as the last parameter to this generic function. • For example: • void main() • { • cout<<GenericSum(10,50,fact); • cout<<GenericSum(10,50,cube); • }

  10. Virtual Functions • The function call: (*p) (i) , exhibits the polymorphic behaviour while compiling it, it is not known which function will actually be executed. • This becomes known only later when the client program that calls the GenericSum() function. • Similar effect must also happen for the class objects in C++. • Depending on the address contained in the common pointer, corresponding member functions of the different classes have to be selected.

  11. Virtual Functions • If the library programmer, who is defining the base class, expects and suspects overriding of a certain member function and wants to make such an override meaningful, he/she should declare the function as virtual. • For declaring a function as virtual, the prototype of the function within the class should be prefixed with the virtual keyword. • The virtual keyword may appear either before or after the keyword specifying the return type of the function. • If the function is defined outside the class, then only the prototype should have the virtual keyword. • The syntax for declaring a virtual function as follows: virtual <return type> <function name>(<formal arguments>);

  12. Virtual Functions Example 9: class A { public: virtual void show() { cout<<“show A\n” } }; class B: public A { public: void show() { cout<<“show B\n” } }; void main() { A *Aptr; A A1; B B1; Aptr=& A1; Aptr->show(); Aptr=&B1; Aptr->show(); }

  13. Virtual Functions • When the base class pointer points at an object of the derived class and a call is dispatched to an overridden virtual function, then it is the overriding function of the derived class, and not the overridden function of the base class, that is called. • The function call exhibits polymorphic behaviour, because while compiling it, it is not known which function will actually be executed. • This is decided only when the client program that calls this function is compiled. We can therefore say that compile time for the client is run time for the library. Therefore, the polymorphic behaviour exhibited by virtual functions is also termed as dynamic polymorphism. • The functions in the base class usually contain only those statements that are relevant to the base class itself.

  14. Virtual Functions • The overriding functions of the derived class first call back the overridden base class functions and then add the extra statements that complete the definitions with respect to the derived class itself. • Having such base class functions as virtual ensures that the client is able to call both the functions in sequence as desired. • Virtual functions of the base classes reappear as virtual in the derived classes also.

  15. Virtual Functions Example 10: class A { public: virtual void show() { cout<<“show A\n” } }; class B: public A { public: void show() { cout<<“show B\n” } }; class C: public B { public: void show() { cout<<“show C\n” } }; void main() { B*Bptr; C C1; Bptr=&C1; Bptr->show(); }

  16. The Mechanism of Virtual Functions • For every base class that has one or more virtual functions, a table of function addresses is created during run time. This table of function addresses is called the virtual table or VTBL in short. • Such a table of addresses of virtual functions will be created for the derived class as well. • The VTBL contains the address of each and every virtual function that has been defined in the corresponding class. Example 11: class A { public: virtual void abc(); virtual void def(); }; • During runtime, the VBTL of class A will be: Address of A::abc() 201 101 Address of A::def()

  17. The Mechanism of Virtual Functions • Addresses of non-virtual functions do not appear in such tables. • A table of addresses of virtual functions will be created for the derived class also. • If the derived class does not redefine a certain base class member, then the table will contain the address of the inherited base class virtual function itself. • However, if a certain base class virtual function is redefined in the derived class, this table will contain the address of the overriding function. • Also, if the derived class defines a new virtual function, then its address will also be contained in the table. (See Example 12 and Figure). Example 12: class B: public A { public: void def(); void virtual ghi(); Address of B::def() }; The VBTL for class B appears as: Address of A::abc() Address of B::ghi() 301 101 401

  18. The Mechanism of Virtual Functions • Every object of a class that has a virtual function contains a pointer to the VTBL of the corresponding class. This pointer is also known as the virtual pointer or VPTR. • Whenever a call is dispatched to a virtual function through an object or a reference to an object, or through a pointer to an object, then first of all the value of the VPTR of the object is read. • Then the address of the called function from the corresponding VTBL is obtained. Finally, the function is called through the address thus obtained. • The virtual table size varies from class to class (for each class there is only one VTBL). • The size of the object does not vary. Only the size of the objects of classes with virtual functions increases uniformly by four bytes due to the presence of the additional pointer (VPTR).

  19. The Mechanism of Virtual Functions Why not declare functions virtual by default? Why does C++ support not support dynamic binding only? • They incur a runtime cost in the form of space that is wasted for creating the VTBL and embedding the VPTR in each and every object of the base/derived class. • Time is also lost in searching the VTBL for the function address. • If none of the member functions of a certain class will be overridden, then making them virtual will unnecessarily incur the above cost.

  20. Virtual Functions • Run time polymorphism is achieved only when a virtual function is accessed through a pointer to the base class. • It cannot be achieved using the object name along with the dot operator to access virtual function. • If the library programmer, who is defining the base class, expects and suspects overriding of a certain member function and wants to make such an override meaningful, he/she should declare the function as virtual. • For declaring a function as virtual, the prototype of the function within the class should be prefixed with the virtual keyword.

  21. Pure Virtual Functions • There are cases where the library programmer would like to enforce an override of the base class virtual functions. • The virtual function is seldom used for performing any task is generally used as a placeholder. • A do-nothing function may be defined as: virtual <return_type> <function_name> (<formal_args>) =0; • Such a function is a pure virtual function. • A pure virtual function is a function declared in a base class that has no definition relative to the base class. • In such cases, the compiler requires it to either define the function or re-declares it as a pure virtual function.

  22. Pure Virtual Functions When should pure virtual functions be used in C++? In C++, a regular, "non-pure" virtual function provides a definition, which means that the class in which that virtual function is defined does not need to be declared abstract. You would want to create a pure virtual function when it doesn’t make sense to provide a definition for a virtual function in the base class itself, within the context of inheritance. An example of when pure virtual functions are necessary For example, let’s say that you have a base class called Figure. The Figure class has a function called draw. And, other classes like Circle and Square derive from the Figure class. In the Figure class, it doesn’t make sense to actually provide a definition for the draw function, because of the simple and obvious fact that a “Figure” has no specific shape. It is simply meant to act as a base class. Of course, in the Circle and Square classes it would be obvious what should happen in the draw function – they should just draw out either a Circle or Square (respectively) on the page. But, in the Figure class it makes no sense to provide a definition for the draw function. And this is exactly when a pure virtual function should be used – the draw function in the Figure class should be a pure virtual function.

  23. Pure Virtual Functions • A virtual function that is initialized to zero (0) is referred to as pure virtual function. It has no body and hence also known as do-nothing or the dummy function. • Example: virtual void show()=0; • A class containing one or more pure virtual functions is called an Abstract Base Class (ABC), which means an instance of such class can't be created (but pointer to that class can be created). • We should use pure virtual function if we do not want to instantiate a class but make it act as a base class for all the classes that derive from it.

  24. Pure Virtual Functions Sample program: class alpha { public:virtual void show()=0; //pure virtual function }; class beta:public alpha { public:void show() //overriding { cout<<"OOP in C++"; } }; void main() { alpha *p; beta b; p=&b; p->show(); } Output: OOP in C++

  25. Pure Virtual Functions An important thing to note about pure virtual functions is that these functions must be overridden in all the derived classes otherwise the compile would flag out an error. Sample program: class A { public: void virtual abc()=0; void virtual def()=0; void virtual ghi()=0; }; void main() { A A1; //error }

  26. Pure Virtual Functions class B: public A { public: void abc() { //deftn of abc} }; void main() { B B1; //error } class C: public B { public: void def() { // deftn of def } void ghi() {//deftn of ghi} }; void main() { C C1; //OK }

  27. Pure Virtual Functions • Pure virtual functions provide a mechanism to the library programmer to enforce the desired override. • If even one member function is declared as a pure virtual function, then the corresponding class becomes an Abstract Base Class (ABC in short). • A function is declared as a pure virtual function by prefixing its prototype with the virtual keyword as before but suffixing it with an ‘equal to’ sign and then by a ‘zero’ (0). • The syntax for declaring a pure virtual function is: virtual <return type> <function name>(<formal arguments>)=0; • An abstract base class cannot be instantiated, that is, objects of an abstract base class cannot be declared. Compile-time errors defeat attempts to do so.

  28. Pure Virtual Functions • The derived class must override all pure virtual functions of the base class or itself get branded as an ABC by the compiler. • The library programmer defines the ABC and also some generic functions that implement the general flow of a related algorithm without considering the exact data type on which they will work. Thus, the utility of an ABC lies in its use as an interface.

  29. Pure Virtual FunctionsAdvantages of ABC • The ABC behaves just like an interface with little or no implementation of its own. • The library programmer is free to define generic functions without bothering about the implementation details. • The library programmer can enforce all necessary overrides. • The application programmer can derive any class from the ABC, provide his/her own implementations for the derived class and then use the same driver functions for any of these derived classes. • Abstract Base Classes are also used to build implementation in stages. We know that if a pure virtual function inherited from the base class is not defined in the derived class, it remains a pure virtual function in the derived class. Thus, the derived class also becomes an abstract class.

  30. Pure Virtual Functions • The ability to provide an implementation to pure virtual methods allows data types to provide core functionality while still requiring derived classes to provide a specialized implementation. • The class remains abstract even if we provide an implementation for its pure virtual function. • A member function can be non-virtual, virtual, or pure virtual.

  31. Pure Virtual Functions Example: Class Shape accepts two values (Data Type: Double). Create two derived classes Triangle and Rectangle ; calculate area of Triangle and rectangle using data members from base class. Use one virtual function to display data.     class Shape    {     protected :     double x0, y0;     public :     void getdata(double x, double y)     {     x0 = x;     y0 = y;     }     virtual void displayArea() = 0;    };

  32. Pure Virtual Functions class Triangle : public Shape    {     public :     void getdata(double x, double y)     {     Shape :: getdata(x,y);      }     void displayArea()     {     double area = (x0 * y0)/2.0;     cout << "\n Area of triangle = " << area;      }    }; class Rectangle : public Shape    {     public :     void getdata(double x, double y)     {     Shape :: getdata(x,y);      }     void displayArea()     {     double area = (x0 * y0);     cout << "\n Area of rectangle = " << area;     }    };

  33. Pure Virtual Functions void main()    {     Triangle *tptr;     Rectangle *rptr;     Shape *sptr[2];     int i;     tptr = new Triangle;     rptr = new Rectangle;     tptr->getdata(20.0,30.0);     rptr->getdata(20.0,20.0);     sptr[0] = tptr;     sptr[1] = rptr;     for(i=0; i<2; i++)     sptr[i]->displayArea();     getch();    } Question: How to derive another class circle from the base class and call displayarea () function?

  34. Virtual Destructors • Destructors can be defined as virtual. • The destructor of a base class must be declared as virtual if the delete operator is to be used on objects of a base class and there is a presence of pointers in the derived classes. • When a pointer of the base class points at a dynamically created object of the derived class and then deletes the memory occupied by the object, the entire block of memory is deleted. This is irrespective of whether the base class destructor is virtual or not.

  35. Virtual Destructors Destructors must be defined virtual. Why? For e.g.. Consider base class A and a derived class B class A { public: ~A() ; }; }; class B: public A { public: ~B() ; }; }; void main() { A* APtr ; //only the base class destructor APtr = new B; //is called with respect to the …… //object before the entire memory delete APtr; //occupied by the object is returned.

  36. Virtual Destructors • This leads to memory leak apart from other problems, since destructor of B is not called. • If destructor of class A is virtual, then first the destructor of class B will be called , then the destructor of class A will be called. Finally, the entire memory block occupied by the object will be returned to OS. • If we expect the use of the delete operator on objects of a derived class in the presence of pointers of the base class, we must declare the destructor of the base class as virtual.

  37. Virtual Constructors • Constructors cannot be virtual. Declaring a constructor as virtual results in a compile-time error. • There are valid reasons that justify the above statement: • To create an object, the constructor of the object class must be of the same type as the class. But, this is not possible with a virtually implemented constructor. • At the time of calling a constructor, the virtual table would not have been created to resolve any virtual function calls. Thus, a virtual constructor would not have been anywhere to look up.

  38. Virtual Constructors • However, the need to construct virtually arises very frequently while programming in C++. • Calling the copy constructor seems to serve the purpose . For this, a clone function will have to be defined. • Derived classes will similarly define and override this clone function. • Whenever a clone of the object is required, the clone function is called. The clone object created is subsequently destroyed. • Since the clone function constructs an object and is also virtual, it is sometimes called a virtual constructor. However, note that there is actually nothing like a virtual constructor.

  39. Virtual constructors • Declaring a constructor virtual results in compile-time error. Why ? • If the constructor of class A is virtual, then in • A* p = new B ; • the constructor of class B alone will be called and that of class A will not be called. A rough pointer will result. • The need to construct virtually arises very frequently while programming in C++: • void abc (A * p ) { // defn of abc() function } • Here an exact copy of the object at which ‘p’ points is required within the abc() function • Calling a copy constructor seems to serve the purpose i.e. A * q = new A (* p) or A A1(*p)

  40. This will work if a correct copy constructor is defined and if ‘p’ points to an object of base class and not to the derived class object. • If ‘p’ points to the derived class object, then the object created will not be of the same type and will be smaller in size with less data members since it creates the object of class A • A clone function is to be defined to solve this • class A • { public : virtual A * clone(){ return new A(* this);} • //defn of class A }; • class B : public A • { public : virtual B * clone(){ return new B(* this);} • //defn of class B };

  41. Whenever a clone object is required, then the clone function is called and object created is subsequently destroyed • void abc( A * p) { …. ; A * q = p -> clone(); • …. ; delete q; } • Since clone function is virtual, its correct version is called. • Since the clone function constructs an object and is virtual, it is called a virtual constructor • There is actually nothing like virtual constructor

  42. Virtual constructor Here is a simple example:   class AbstractBase   {   public:       virtual ~AbstractBase() {}       virtual AbstractBase * Create() = 0;       virtual AbstractBase * Clone() = 0;   // ...   };   class SomeType : public AbstractBase   {   public:       virtual SomeType * Create();       virtual SomeType * Clone();   // ...   };

  43. Virtual constructor    SomeType * SomeType::Create()   {       return new SomeType;   }   SomeType * SomeType::Clone()   {       return new SomeType(*this);   } int main()   {       AbstractBase *p;       Derived d;              p = &d;          }

  44. Questions 1. Create a class called Shipment which consists of data members total_weight (float type) and no_of_packages (int type). Write a parameterized constructor. Also write a member function for overloading the minus sign. This function should subtract total_weight of second object from total_weight of first object and return this value. Write a suitable main() function. 2. Create a class called Distance consisting of data members ifeet (int type) and finches (float type). Write functions for overloading the extraction operator and the insertion operator for objects of this class. Write a complete program using these functions.

  45. Questions 3. Given a program fragment as follows – class Matrix { int mat[10][10]; int row, col; public: Matrix(int m[10][10], int r, int c); //parameterized constructor }; void main( ){ int m1[10][10] = {{1,1,1},{2,2,2},{3,3,3}}; Matrix A(m1,3,3); cout << A; //display contents of matrix – row by row ++A; //increment each element of the matrix by 1 cout << A; } A. Write a member function (including prototype) for overloading the increment operator. This function increments each element of the matrix by 1. (3) B. Write a function (incuding prototype) for overloading the insertion operator (<<). This function should display the contents of the matrix row by row, that is, one row per line. (2) 2A. List and explain any 2 rules for operator overloading. (2) 2B. Explain function template. Illustrate with a complete program for swapping two integers using a function template. (3) 3A. What is the order of invocation of constructors in case of inheritance? (2) 3B. Write a program to create a graphic class hierarchy. Create an abstract base class called Figure and derive two classes Square (side) and Circle (radius). Derive classes SquarePrism (height) from Square and Cylinder (height) from Circle. Include the appropriate constructors and the member function Show() to display the details of the object. Create the objects of the different classes. Demonstrate the dynamic polymorphism through invoking the Show() function for the objects created. (Note – Information given with class names within parentheses are data members) (5) 3C. Why it is necessary to catch exceptions? Explain with an example the limitation of exception handling. (1+2) ***********************

  46. Questions A. Write a member function (including prototype) for overloading the increment operator. This function increments each element of the matrix by 1. B. Write a function (incuding prototype) for overloading the insertion operator (<<). This function should display the contents of the matrix row by row, that is, one row per line. 4. Write a program to create a graphic class hierarchy. Create an abstract base class called Figure and derive two classes Square (side) and Circle (radius). Derive classes SquarePrism (height) from Square and Cylinder (height) from Circle. Include the appropriate constructors and the member function Show() to display the details of the object. Create the objects of the different classes. Demonstrate the dynamic polymorphism through invoking the Show() function for the objects created. (Note – Information given with class names within parentheses are data members).

More Related