chapter 7 virtual functions and dynamic polymorphism

46
Chapter 7 Virtual Functions and Dynamic Polymorphism

Upload: sharyl-jackson

Post on 26-Dec-2015

239 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Chapter 7 Virtual Functions and Dynamic Polymorphism

Chapter 7Virtual Functions and Dynamic

Polymorphism

Page 2: 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

Page 3: Chapter 7 Virtual Functions and Dynamic Polymorphism

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();

}

Page 4: Chapter 7 Virtual Functions and Dynamic Polymorphism

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();

}

Page 5: Chapter 7 Virtual Functions and Dynamic Polymorphism

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).

Page 6: Chapter 7 Virtual Functions and Dynamic Polymorphism

The Need for Virtual FunctionsExample 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 calledX1.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.

Page 7: Chapter 7 Virtual Functions and Dynamic Polymorphism

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:

int factSum(int a, int b){ int i;

long sum;for (sum=0, i=a; i<=b;i++)sum+=fact(i);return sum;}

Page 8: Chapter 7 Virtual Functions and Dynamic Polymorphism

Virtual Functions

Example 6:int CubeSum(int a, int b){ int i;

long sum;for (sum=0, i=a; i<=b;i++)sum+=cube(i);return sum;}

Example 7:int LogSum(int a, int b){ int i;

long sum;for (sum=0, i=a; i<=b;i++)sum+=log(i);return sum;}

Page 9: Chapter 7 Virtual Functions and Dynamic Polymorphism

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 int GenericSum(int a, int b, long int (*p )(int i) ){ int i;

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);}

Page 10: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 11: Chapter 7 Virtual Functions and Dynamic Polymorphism

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>);

Page 12: Chapter 7 Virtual Functions and Dynamic Polymorphism

Virtual FunctionsExample 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();

}

Page 13: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 14: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 15: Chapter 7 Virtual Functions and Dynamic Polymorphism

Virtual FunctionsExample 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();

}

Page 16: Chapter 7 Virtual Functions and Dynamic Polymorphism

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:

101 201

Address of A::def()

Address of A::abc()

Page 17: Chapter 7 Virtual Functions and Dynamic Polymorphism

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()

101 301 401

Page 18: Chapter 7 Virtual Functions and Dynamic Polymorphism

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).

Page 19: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 20: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 21: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 22: Chapter 7 Virtual Functions and Dynamic Polymorphism

Pure Virtual FunctionsWhen 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.

Page 23: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 24: Chapter 7 Virtual Functions and Dynamic Polymorphism

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++

Page 25: Chapter 7 Virtual Functions and Dynamic Polymorphism

Pure Virtual FunctionsAn 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}

Page 26: Chapter 7 Virtual Functions and Dynamic Polymorphism

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}

Page 27: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 28: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 29: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 30: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 31: Chapter 7 Virtual Functions and Dynamic Polymorphism

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; };

Page 32: Chapter 7 Virtual Functions and Dynamic Polymorphism

Pure Virtual Functionsclass 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;     }    };

Page 33: Chapter 7 Virtual Functions and Dynamic Polymorphism

Pure Virtual Functionsvoid 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?

Page 34: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 35: Chapter 7 Virtual Functions and Dynamic Polymorphism

Virtual DestructorsDestructors 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.

Page 36: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 37: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 38: Chapter 7 Virtual Functions and Dynamic Polymorphism

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.

Page 39: Chapter 7 Virtual Functions and Dynamic Polymorphism

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)

Page 40: Chapter 7 Virtual Functions and Dynamic Polymorphism

*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 };

Page 41: Chapter 7 Virtual Functions and Dynamic Polymorphism

*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

Page 42: Chapter 7 Virtual Functions and Dynamic Polymorphism

Virtual constructorHere 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();

// ...

};

Page 43: Chapter 7 Virtual Functions and Dynamic Polymorphism

Virtual constructor SomeType * SomeType::Create() { return new SomeType; }

SomeType * SomeType::Clone() { return new SomeType(*this); }

int main() { AbstractBase *p; Derived d;

p = &d; }

Page 44: Chapter 7 Virtual Functions and Dynamic Polymorphism

Questions1. 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.

Page 45: Chapter 7 Virtual Functions and Dynamic Polymorphism

Questions3. 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 1cout << A;}A. Write a member function (including prototype) for overloading the increment operator. This functionincrements each element of the matrix by 1. (3)B. Write a function (incuding prototype) for overloading the insertion operator (<<). This functionshould 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 afunction 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 andderive two classes Square (side) and Circle (radius). Derive classes SquarePrism (height) from Squareand 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 dynamicpolymorphism through invoking the Show() function for the objects created. (Note – Information givenwith class names within parentheses are data members) (5)3C. Why it is necessary to catch exceptions? Explain with an example the limitation of exceptionhandling. (1+2)***********************

Page 46: Chapter 7 Virtual Functions and Dynamic Polymorphism

QuestionsA. 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 Squareand 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).