Tuesday 23 October 2012

Multiple Inheritance, Virtual Functions And Polymorphism


Multiple Inheritance
Unit 8 Multiple Inheritance, Virtual Functions
And Polymorphism
Structure
8.1 Introduction
8.2 Introduction to Multiple Inheritance
8.3 Introduction to Virtual Functions
8.4 Introduction to Polymorphism
8.1 Introduction
This unit has the following objectives
· To understand how to implement multiple inheritance
· To understand the complexities that might arise in multiple inheritance
· To learn the concept of virtual functions and polymorphism
8.2 Introduction to Multiple Inheritance
We have learnt in the last unit the concept of inheritance. We will explore in detail the concept of multiple inheritance and the ambiguities that might arise in multiple inheritance. Multiple Inheritance is the process of inheriting a class from more than one parent class. This would be required in several instances where you would like to have the functionalities of several classes . This is also extensively used in class libraries.
The syntax for implementing multiple inheritance is similar to single inheritance. Let us suppose, there are two classes A and B, you want to derive a class C from A and B. The syntax of class definition will be as follows:
class C : public A, public B
{
};
Let us implement a program where there are two classes namely student and employee. We will derive a class manager from the above two classes and see how member functions and constructors are implemented in multiple inheritance.
//multiple.cpp
# include<iostream.h>
# include<string.h>
# include<conio.h>
class student
{ protected:
char qual[6]; // highest degree earned
int percent; // percentage score in the last degree
public:
student()
{ strcpy(qual, “”); percent=0;}
student(char ch[6], int p)
{ strcpy(qual, ch); percent=p;}
void display()
{ cout<<endl<<”Qualification”<<qual;
cout<<endl<<”Score”<<percent;
}} ;
class employee {
protected:
int empno;
char ename[25];
public:
employee()
{ empno=0;
strcpy(ename,"");
}
employee(int n, char ch[25])
{ empno=n;
strcpy(ename,ch);
}
void display()
{cout<<endl <<"Emp Code:"<<empno;
cout<<endl <<"Name:"<<ename;
}
};
class manager: public employee, public student
{
protected:
float basic;
float hra;
public:
manager():employee(),student()
{ basic=0.0; hra=0.0;}
manager(int n,char ch[25], char ch1[6], int p, float i, float j): employee(n,ch), student(ch1,p)
{ basic=i; hra=j;}
void display()
{ employee::display();
student::display();
cout<<endl <<"Basic"<<basic;
cout<<endl <<"HRA"<<hra;
}
};
void main()
{
clrscr();
manager m1(205, “pawan”, “MBA”, 80, 40000.00, 5000.00);
m1.display();
getch();
}
You can see in the above program, that the derived class constructors calls both the parent class constructors. This is because every object of the derived class has its own copy of parent data members. Therefore it is required to initialize them as well. The parent class member functions are invoked using the scope resolution operator as shown in the display function of the manager class.
The output of the above program will be
Emp Code:205
Name:pawan
Qualification MBA
Score 80
Basic 40000
HRA 5000
Even though implementation of multiple inheritance is simple, there are several type of ambiguities that might arise in its implementation. Let us suppose there are two parent classes A and B. Class C has been derived from A and B. There is a function f1() defined in both the parent classes but f1() has not been defined in the child class. When the child class object (objc) tries to access the function f1() through a statement objc.f1(), there is compiler error. This is because the statement is ambiguous because the compiler will not be able to figure out which parent’s f1() function have to be called. The ambiguity can be resolved by prefixing the parent class name followed by scope resolution operator before the function name. The following statement would resolve the ambiguity
objc.A::f1();
The above statement implies that use the function f1() of class A. Another solution would be to introduce a dummy function f1() in Class C and invoke the parent functions whichever applicable.
Another common ambiguity raised is in the case of diamond inheritance. Diamond inheritance is a situation as shown in the following diagram arises when both the parent classes have been derived from a single parent class.
image
Fig. 8.1: Diamond Inheritance
class A
{protected:
int a;};
class B : public parent
{ }
class C: public parent
{ }
class D : public B, public C
{ public:
int f1()
return a; //à ambiguous
}
Imagine the above situation where there is a parent class A with a protected data member a. Two child classes B and C are derived publicly from A. Class D is derived both from B and C publicly. The compiler complains when the grandchild class D tries to access the member a of the parent class A. This ambiguity arises because when classes B and C are derived from A, each inherits a copy of A called subobject and contains own copy of parent data. The ambiguity arises for the grandchild in resolving which copy of the child class subobject to be accessed.
The solution for this is virtual base class. By making classes B and C as virtual classes, the two classes will share a common subobject and will result in resolving the ambiguity as shown below.
class A
{protected:
int a;};
class B : virtual public A
{}
class C: virtual public A
{}
class D : public B, public C
{ public:
int f1()
return a; //only one copy of the parent
}
Self Assessment questions
1. In case of multiple inheritance, the child class has a copy of data of all the parent classes. True/False
2. The problem of diamond inheritance ambiguity is resolved by declaring the child classes as ____________
3. In multiple inheritance if the both the parent class (A and B) have same function and child class (C) does not have that function, then the which function is called
a. Class A
b. Class B
c. Have to be specified explicitly
d. No function will be called
8.3 Introduction to Virtual Functions
Virtual means existing in effect but not in reality. Virtual functions are primarily used in inheritance. Let us suppose you have a class base as shown in the following program and two classes derv1 and derv2 are publicly derived from class base. You would like to create a pointer that points to any of the derived class objects. If you create a pointer of derv1, then it can point to derv1 object only. Compiler will complain if you assign any other object is assigned to the pointer. The solution is to create a pointer to Base class.
// objectptr.cpp
# include <iostream.h>
class base
{ public:
void show()
{cout<<“base”<<endl;}};
class derv1:public base
{ public:
void show()
{cout<<“derv1”<<endl;}};
class derv2: public base
{ public:
void show()
{cout<<“derv2”<<endl;}};
void main()
{
derv1 dv1;
derv2 dv2;
base *ptr;
ptr=&dv1;
ptr->show();
ptr=&dv2;
ptr->show();
}
The output of the above program will be surprisingly:
base
base
Even though the address of derived classes is assigned to the pointer, the compiler executes the base class function. However, if the base class function is made virtual, we get the desired result. In the following program we have made the base class function show() as virtual function by prefixing with the keyword virtual.
//virtual.cpp
# include <iostream.h>
class base
{ public:
virtual void show() // virtual function
{cout<<“base”<<endl;}};
class derv1:public base
{ public:
void show()
{cout<<“derv1”<<endl;}};
class derv2: public base
{ public:
void show()
{cout<<“derv2”<<endl;}};
void main()
{
derv1 dv1;
derv2 dv2;
base *ptr;
ptr=&dv1;
ptr->show();
ptr=&dv2;
ptr->show();
}
By declaring the base class function as virtual, we now get the output as:
derv1
derv2
In the above program, depending on the contents in the pointer, the compiler decides which class function to call during runtime. This is known as late binding or dynamic binding.
Virtual functions are for just name sake and will not be executed many a times. If the virtual function has no specific role in the base but just declared for enabling the derived class objects access through pointers, the function can be declared as a pure virtual function. A pure virtual function is one which does not have any body. Virtual functions declared by equating it to zero as shown below:
virtual void show()=0;
In inheritance, many a times you would create a class just for grouping data or functionality but the class do not have any instances of its own. Such classes which does not have any objects are known as abstract classes. For example, there is a class known as employee and there are many classes derived from this class such as manager, worker etc. In the program, the employee class brings together the common data and functions to all the subclasses and to avoid coding same functionality in each and every class. Here employee class is the abstract class.
Self Assessment questions
1. Base class functions which does not have any body is known as _______
2. The process of deciding which class function to be called during runtime is known as _______________________
3. The classes which do not have any objects are known as ___________
8.4 Introduction to Polymorphism
Virtual functions in C++ are important to implement the concept of polymorphism. Polymorphism means same content but different forms. In C++, polymorphism enables the same program code calling different functions of different classes. Imagine a situation where you would like to create a class shape and derive classes such as rectangle, circle, triangle etc. Let us suppose each of the classes has a member function draw() that causes the object to be drawn on the screen. You would like to write a common code as following so that you can draw several of these shapes with same code and the shape to be drawn is decided during runtime:
Shape *ptrarr[100]
for (int j=0;j<n;j++)
Ptrarr[j]->draw();
This is an very desirable capability that completely different functions are executed by same function call. If the ptrarr is pointing to a rectangle, a rectangle is drawn. If it is pointint to circle, circle is drawn.
This is exactly what is polymorphism. However to implement this approach several conditions should be met. Firstly, all the classes rectangle, circle, triangle should be derived from a single class (Here it is shape class). Secondly, the draw() function must be declared as virtual in the base class (in the shape class).
Operator overloading is, a type of polymorphism which allows the same operators to behave differently with different datatypes/operands.
Self Assessment questions
1. A pointer to a base class can point to the objects of a derived class. True/False
2. If there is a pointer p, to the objects of a base class and it contains the address of an object of a derived class, and both classes contain a virtual member function, ding(), then the statement p->ding(); will cause the version of ding() in the ________________ class to be executed
3. Polymorphism in C++ is implemented through ________________.
Summary
Inheritance has to be implemented with care especially when it is multiple inheritance. Multiple inheritance creates ambiguity in situation where the derived class does not implement the function implemented in both the parent class and also in case of diamond inheritance. Virtual base class helps in resolving the ambiguity. Virtual functions in base class helps to implement polymorphism in C++. Abstract classes are classes without any objects.
Terminal Questions
1. A virtual base class is useful when
a. Different functions in base an derived classes have the same name
b. There are multiple paths from one derived class to another
c. The identification of a function in a base class is ambiguous
d. It makes sense to use a base class with no body
2. Imagine a publishing company markets books and CD-ROMS. Create a class called publication which stores title and price of a publication. Derive two classes: book which adds a page count and CD-ROM which adds playing time in minutes. Each of the three classes should have a getdata() and putdata() function to get its data from the user and display the data respectively. Write a main program that creates an array of pointers to publication and in a loop, ask the user for data for book or cdrom. When user has finished entering data, display all the data.
3. Virtual functions allow you to
a. Create an array of type pointer-to-base-class that can hold pointers to derived classes
b. Create functions that have no body
c. Group objects of different classes so they can all be accessed by same function code
d. Use same function call to execute member functions of objects from different classes.
Answers to SAQs in 8.2
1. True
2. Virtual Base class
3. Have to be specified explicitly
Answers to SAQs in 8.3
1. Pure virtual functions
2. Late binding or dynamic binding
3. Abstract classes
Answers to SAQs in 8.4
1. True
2. Derived
3. Virtual functions
Answers to TQs
1. The identification of a function in a base class is ambiguous
2. //publish.cpp
# include <iostream.h>
#include<conio.h>
class publication
{ protected:
char title[80];
float price;
public:
virtual void getdata()
{ cout<<endl<<”enter title”; cin>>title;
cout<<endl<<”enter price”;cin>>price;
}
virtual void putdata()
{
cout<< endl<<”Title”<<title;
cout<<endl<<”Price”<<price;
}
};
class book: public publication
{
private:
int pages;
public:
void getdata()
{ publication::getdata();
cout<<endl<<”enter number of pages”; cin>>pages;
}
void putdata()
{
publication::putdata();
cout<< endl<<”Number of pages”<<pages;
}
};
class cdrom: public publication
{
private:
float time;
public:
void getdata()
{ publication::getdata();
cout<<endl<<”enter playing time”; cin>>time;
}
void putdata()
{
publication::putdata();
cout<< endl<<”Playing time”<<time;
}
};
void main()
{
publication * ptr[10];
book* bptr;
cdrom* cptr;
char ch;
int n=0;
do
{
cout<<”Enter data for book or cdrom(b/c)”;
cin>>ch;
if (ch==’b’)
{
bptr= new book;
bptr->getdata();
ptr[n++]=bptr;
}
else
{cptr=new cdrom;
cptr->getdata();
ptr[n++]=cptr;
}
cout<<”enter another (y/n)”;
cin>>ch;
}while (ch==’y’);
for(int j=0;j<n;j++)
ptr[j]->putdata();
getch();
}
3. Use same function call to execute member functions of objects from different classes.
  • 0 likes

1 comment:

  1. By way of business a pаyment. Emplοyerѕ can chooѕe to use in any buyout consiԁeratіons.

    And they гentеd a van. This is what happened to
    the last tωo years, Pаnasonіc ѕtill emрloys
    more than 300, 000 squarе miles, making it possiblе tο
    lower thе ρrice or get bеtter terms.


    Haѵе a look at my homeρage online internet marketing training

    ReplyDelete