Virtual Functions - chapter - 4, Slides of Object Oriented Programming

Virtual Functions Virtual means existing in appearance but not in reality. When virtual functions are used, a program that appears to be calling a function of one class may be called a part of a different course. Why are virtual functions needed?

Typology: Slides

2021/2022

Available from 12/03/2022

razaroghani
razaroghani 🇵🇰

4.5

(4)

151 documents

1 / 65

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41

Partial preview of the text

Download Virtual Functions - chapter - 4 and more Slides Object Oriented Programming in PDF only on Docsity!

1

Virtual Functions

 Virtual means existing in appearance but not in

reality.

When virtual functions are used, a program that

appears to be calling a function of one class may in

reality be calling a function of a different class.

 Why are virtual functions needed?

Suppose you have a number of objects of different

classes but you want to put them all in an array and

perform a particular operation on them using the

same function call.

For example, suppose a graphics program includes

several different shapes: a triangle, a ball, a square,

and so on, as in the MULTSHAP program in the,

“Inheritance.”chapter

Each of these classes has a member function draw()

Virtual Functions

 Now suppose you plan to make a picture by grouping

a number of these elements together, and you want

to draw the picture in a convenient way.

One approach is to create an array that holds pointers

to all the different objects in the picture. The array

might be defined like this: shape* ptrarr[100]; // array

of 100 pointers to shapes

If you insert pointers to all the shapes into this array,

you can then draw an entire picture using a simple

loop:

for(int j=0; j<N; j++) { ptrarr[j]->draw(); } //

(*ptrarr[j] ).draw()

This is an amazing capability: Completely different

functions are executed by the same function call.

Normal Member Functions Accessed with Pointers (1/2) // normal functions accessed from pointer #include using namespace std; class Base { //base class public: void show() { cout << "Base\n"; } }; class Derv1 : public Base { //derived class 1 public: void show() { cout << "Derv1\n"; } }; class Derv2 : public Base { //derived class 2 public: void show() { cout << "Derv2\n"; } };

Normal Member Functions Accessed with Pointers (1/2) int main() { Derv1 dv1; // object of derived class 1 Derv2 dv2; // object of derived class 2 Base* ptr; // pointer to base class ptr = &dv1; // put address of dv1 in pointer // The rule is that pointers to objects of a derived // class are type compatible with pointers to objects of // the base class. ptr->show(); // execute show() OR (*ptr).show(); // the function in the base class is always executed. ptr = &dv2; // put address of dv2 in pointer ptr->show(); // execute show() return 0; } 5

Virtual Member Functions Accessed with Pointers (1/2) // virtual functions accessed from pointer #include using namespace std; class Base{ // base class public: virtual void show() // virtual function { cout << "Base\n"; } }; class Derv1 : public Base { // derived class 1 public: void show() { cout << "Derv1\n"; } }; class Derv2 : public Base { //derived class 2 public: void show() { cout << "Derv2\n"; } };

Virtual Member Functions Accessed with Pointers (2/2) int main() { Derv1 dv1; // object of derived class 1 Derv2 dv2; // object of derived class 2 Base* ptr; // pointer to base class ptr = &dv1; // put address of dv1 in pointer ptr->show(); // execute show() of Derv // The rule is that the compiler selects the function // based on the contents of the pointer ptr, not on the // type of the pointer ptr = &dv2; // put address of dv2 in pointer ptr->show(); // execute show() of Derv return 0; }

Late Binding

 Which version of draw() does the compiler call?

In fact the compiler doesn’t know what to do, so it

arranges for the decision to be deferred until the

program is running.

 At runtime, when it is known what class is pointed to

by ptr, the appropriate version of draw will be called.

This is called late binding or dynamic binding.

 Choosing functions in the normal way, during

compilation, is called early binding or static binding.

Late binding requires some overhead but provides

increased power and flexibility.

 We’ll put these ideas to use in a moment, but first

let’s consider a refinement to the idea of virtual

functions.

11 Abstract Classes and Pure Virtual Functions  (^) Think of the shape class in the multshap program in Chapter 9. We’ll never make an object of the shape class; we’ll only make specific shapes such as circles and triangles.  When we will never want to instantiate objects of a base class, we call it an abstract class_. Such a class exists_ only to act as a parent of derived classes that will be used to instantiate objects.  (^) If we don’t want anyone to instantiate objects of the base class, we’ll write our classes so that such instantiation is impossible.  How can we can do that? By placing at least one pure virtual function in the base class.A pure virtual function is one with the expression = added to the declaration. This is shown in the next

Abstract Classes and Pure Virtual Functions (1/2) int main() { // Base bad; // can’t make object from abstract class Base* arr[2]; // array of pointers to base class Derv1 dv1; // object of derived class 1 Derv2 dv2; // object of derived class 2 arr[0] = &dv1; // put address of dv1 in array arr[1] = &dv2; // put address of dv2 in array arr[0]->show(); // execute show() in both objects arr[1]->show(); return 0; }

Abstract Classes and Pure Virtual Functions  (^) Once you’ve placed a pure virtual function in the base class, you must override it in all the derived classes from which you want to instantiate objects.  If a class doesn’t override the pure virtual function, it becomes an abstract class itself, and you can’t instantiate objects from it (although you might from classes derived from it).  For consistency, you may want to make all the virtual functions in the base class pure.

Virtual Functions and the person Class (2/3) } bool isOutstanding(){ return (gpa > 3.5)? true : false; } }; class professor : public person { // professor class private: int numPubs; // number of papers published public: void getData() { //get professor data from user person::getName(); cout << " Enter number of professor’s publications: "; cin >> numPubs; } bool isOutstanding() { return (numPubs > 100)? true : false; } };

Virtual Functions and the person Class (1/3) int main(){ person* persPtr[100]; // array of pointers to persons int n = 0; char choice; // number of persons on list do { cout << "Enter student or professor (s/p): "; cin >> choice; if(choice=='s') persPtr[n] = new student; else persPtr[n] = new professor; persPtr[n++]->getData(); //get data for person cout << " Enter another (y/n)? "; cin >> choice; } while( choice=='y' ); //cycle until not ‘y’ for(int j=0; j<n; j++){ //print names of all persPtr[j]->putName(); // say if outstanding if( persPtr[j]->isOutstanding() ) cout << " This person is outstanding\n"; } return 0; } //end main()

Virtual Base Classes

 Before leaving the subject of virtual

programming elements, we should

mention virtual base classes as

they relate to multiple inheritance.

Consider the situation shown in Fig.

with a base class, Parent; two

derived classes, Child1 and Child2;

and a fourth class, Grandchild,

derived from both Child1 and Child2.

In this arrangement a problem can arise if a member

function in the Grandchild class wants to access data

or functions in the Parent class.

The NORMBASE program shows what happens.

Virtual Base Classes #include using namespace std; class Base { public: ~Base() // non-virtual destructor // virtual ~Base() // virtual destructor { cout << "Base destroyed\n"; } }; class Derv : public Base { public: ~Derv() { cout << "Derv destroyed\n"; } }; int main(){ Base* pBase = new Derv; delete pBase; return 0; }