UNIT-4 INHERITANCE AND RUN TIME POLYMORPHISM Inheritance public, private, and protected derivations multiple inheritance virtual base class abstract class composite objects Runtime polymorphism virtual functions pure virtual functions RTTI typeid dynamic casting RTTI and templates cross casting down casting. 1. Explain different types of inheritance in c++ with example programs. (16) Inheritance is a concept of linking two or more classes with each other in a hierarchical manner so that their properties and functions can be shared. (One class will extend to another class.) This leads to the biggest advantage of re-usability of the members and avoids redundancy. Inheritance leads to various issues such as: What is Inherited types of inheritance accessibility modes (public, private and protected) in inheritance Friend function and inheritance etc. Single Inheritance: #include<conio.h> #include <iostream> using namespace std; class Person private: string name; string sex; int age; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 1
void ReadData() cout<<"name:"; cin>>name; cout<<"sex:"; cin>>sex; cout<<"age:"; cin>>age; void display() cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; cout<<"age:"<<age<<endl; ; class student:public Person private: int rollno; string branch; void ReadData() Person::ReadData(); cout<<"roll No:"; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 2
cin>>rollno; cout<<"branch:"; cin>>branch; void display() Person::display(); cout<<"roll No:"<<rollno<<endl; cout<<"branch:"<<branch<<endl; ; int main() student s1; s1.readdata(); s1.display(); getch(); Output: Name:Mike Sex:Male Age:32 Roll No:1320 Branch:CSE Name:Mike Sex:Male Age:32 L. Maria Michael Visuwasam, A.P, CSE, VIT Page 3
Roll No:1320 Branch:CSE Hierarchical Inheritance: #include <iostream> using namespace std; class Cpolygon protected: int width, height; void input_values (int one, int two) width=one; height=two; ; class Crectangle: public Cpolygon int area () return (width * height); ; class Ctriangle: public Cpolygon L. Maria Michael Visuwasam, A.P, CSE, VIT Page 4
int area () return (width * height / 2); ; int main () Crectangle rectangle; Ctriangle triangle; rectangle.input_values (2,2); triangle.input_values (2,2); cout << rectangle.area() << endl; cout << triangle.area() << endl; return 0; In the example above we have used the protected members of the class Cpolygon in the class Crectangle and in the Ctriangle class. This is only possible through Inheritance. What is inherited? When inheritance is done, various links and tables (index, virtual etc) are created which are used to provide the accessibility of the members of the base class in derived class and in other class hierarchy. This means saying public members are inherited is better to say as public members become accessible. A derived class inherits every member of a base class except: its constructor and its destructor its friends its operator=() members L. Maria Michael Visuwasam, A.P, CSE, VIT Page 5
Types of Inheritance There are five different inheritances supported in C++: (1) Simple / Single (2) Multilevel (3) Hierarchical (4) Multiple (5) Hybrid Types of Inheritance flow chart Multiple Inheritance Multiple inheritance is achieved whenever more than one class acts as base classes for other classes. This makes the members of the base classes accessible in the derived class, resulting in better integration and broader re-usability. Take a look at an example: #include <iostream> using namespace std; class Cpolygon protected: int width, height; void input_values (int one, int two) L. Maria Michael Visuwasam, A.P, CSE, VIT Page 6
width=one; height=two; ; class Cprint void printing (int output); ; void Cprint::printing (int output) cout << output << endl; class Crectangle: public Cpolygon, public Cprint int area () return (width * height); ; class Ctriangle: public Cpolygon, public Cprint int area () L. Maria Michael Visuwasam, A.P, CSE, VIT Page 7
return (width * height / 2); ; int main () Crectangle rectangle; Ctriangle triangle; rectangle.input_values (2,2); triangle.input_values (2,2); rectangle.printing (rectangle.area()); triangle.printing (triangle.area()); return 0; Note:the two public statements in the Crectangle class and Ctriangle class. Accessibility modes and Inheritance We can use the following chart for seeing the accessibility of the members in the Base class (first class) and derived class (second class). Accessibility modes inheritance chart Here X indicates that the members are not inherited, i.e. they are not accessible in the derived class. L. Maria Michael Visuwasam, A.P, CSE, VIT Page 8
2. Write a program to print the internal and external marks. And print the total marks using multiple inheritance. And also find out the grade in each subject and print the class. Use appropriate access specifiers and methods to access the data s. (16) //Multiple Inheritance #include<conio.h> #include <iostream> using namespace std; class InternalExam protected: int sub1marks; int sub2marks; void ReadData() cout<<"marks scored in Subject-1:"; cin>>sub1marks; cout<<"marks scored in Subject-2:"; cin>>sub2marks; void display() cout<<"internal Marks scored in Subject-1:"<<sub1marks<<endl; cout<<"internal Marks scored in Subject-2:"<<sub2marks<<endl; ; class ExternalExam L. Maria Michael Visuwasam, A.P, CSE, VIT Page 9
protected: int sub1marks; int sub2marks; void ReadData() cout<<"marks scored in Subject-1:"; cin>>sub1marks; cout<<"marks scored in subject-2:"; cin>>sub2marks; void display() cout<<"external Marks scored in Subject-1:"<<sub1marks<<endl; cout<<"external Marks scored in Subject-2:"<<sub2marks<<endl; ; class Result:public InternalExam, public ExternalExam private: int sub1total; int sub2total; void ReadData() cout<<"**********enter Internal Exam Marks*********"<<endl; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 10
InternalExam::ReadData(); cout<<"**********enter External Exam Marks*********"<<endl; ExternalExam::ReadData(); void Totalmarks() sub1total=internalexam::sub1marks+externalexam::sub1marks; sub2total=internalexam::sub2marks+externalexam::sub2marks; void display() InternalExam::display(); ExternalExam::display(); cout<<"**********************************"<<endl; double average=((sub1total+sub2total)/2)*100; cout<<"\n subject1 Marks:"<<sub1total<< \t ; if(sub1total>50 && sub1total<60) cout<<"e Grade"<<endl; if(sub1total>61 && sub1total<=70) cout<<"c Grade"<<endl; if(sub1total>71 && sub1total<=80) cout<<"b Grade"<<endl; if(sub1total>81 && sub1total<=90) cout<<"a Grade"<<endl; if(sub1total>91 && sub1total<=100) cout<<"s Grade"<<endl; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 11
cout<<"\n subject2 Marks:"<<sub2total<< \t ; if(sub1total>50 && sub1total<60) cout<<"e Grade"<<endl; if(sub2total>61 && sub2total<=70) cout<<"c Grade"<<endl; if(sub2total>71 && sub2total<=80) cout<<"b Grade"<<endl; if(sub2total>81 && sub2total<=90) cout<<"a Grade"<<endl; if(sub2total>91 && sub2total<=100) cout<<"c Grade"<<endl; cout<<"*********************grade *****************"<<endl; if(average>=85) cout<<"distinction"; ; int main() Result r1; r1.readdata(); r1.totalmarks(); r1.display(); getch(); Output: **********Enter Internal Exam Marks********* Marks scored in Subject-1:18 L. Maria Michael Visuwasam, A.P, CSE, VIT Page 12
Marks scored in Subject-2:19 **********Enter External Exam Marks********* Marks scored in Subject-1:75 Marks scored in subject-2:70 Internal Marks scored in Subject-1:18 Internal Marks scored in Subject-2:19 External Marks scored in Subject-1:75 External Marks scored in Subject-2:70 ********************************** subject1 Marks:93 subject2 Marks:89 S Grade A Grade *********************GRADE ***************** Distinction 3. Explain the use of virtual base class with a simple program. (8) An ambiguity can arise when several paths exist to a class from the same base class. This means that a child class could have duplicate sets of members inherited from a single base class. C++ solves this issue by introducing a virtual base class. When a class is made virtual, is taken so that the duplication is avoided regardless of the number of paths that exist to the child class. When two or more objects are derived from a common base class, we can prevent multiple copies of the base class being present in an object derived from those objects by declaring the base class as virtual when it is being inherited. Such a base class is known as virtual base class. This can be achieved by preceding the base class name with the word virtual. Example: //virtual base class #include <conio.h> #include <iostream> L. Maria Michael Visuwasam, A.P, CSE, VIT Page 13
using namespace std; class Baseclass string p; void display() cout<<p<<"\t"; ; class Derivedclass1:virtual public Baseclass //virtual base class string q; void display() Baseclass::display(); cout<<q<<"\t"; ; class Derivedclass2:virtual public Baseclass // virtual base class L. Maria Michael Visuwasam, A.P, CSE, VIT Page 14
string r; void display() cout<<r; ; class Derivedclass3:public Derivedclass1, public Derivedclass2 string s; void display() Derivedclass1::display(); Derivedclass2::display(); cout<<s; ; int main() Derivedclass3 d3; d3.p="maria"; d3.q="michael"; d3.r="visuwasam"; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 15
d3.s=".l"; d3.display(); getch(); Output maria michael visuwasam.l 4. Explain abstract class with a suitable example. (8) An interface describes the behavior or capabilities of a C++ class without committing to a particular implementation of that class. The C++ interfaces are implemented using abstract classes and these abstract classes should not be confused with data abstraction which is a concept of keeping implementation detail separate from associated data. A class is made abstract by declaring at least one of its functions as pure virtual function. A pure virtual function is specified by placing "= 0" in its declaration as follows: class Box // pure virtaul function virtual double getvolume() = 0; private: double length; double breadth; double height; // Length of a box // Breadth of a box // Height of a box ; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 16
The purpose of an abstract class (often referred to as an ABC) is to provide an appropriate base class from which other classes can inherit. Abstract classes cannot be used to instantiate objects and serves only as an interface. Attempting to instantiate an object of an abstract class causes a compilation error. Thus, if a subclass of an ABC needs to be instantiated, it has to implement each of the virtual functions, which means that it supports the interface declared by the ABC. Failure to override a pure virtual function in a derived class, then attempting to instantiate objects of that class, is a compilation error. Classes that can be used to instantiate objects are called concrete classes. Abstract Class Example: Consider the following example where parent class provides an interface to the base class to implement a function called getarea(): #include <iostream> using namespace std; // Base class class Shape // pure virtual function providing interface framework. virtual int getarea() = 0; void setwidth(int w) width = w; void setheight(int h) height = h; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 17
protected: int width; int height; ; // Derived classes class Rectangle: public Shape int getarea() return (width * height); ; class Triangle: public Shape int getarea() return (width * height)/2; ; int main(void) L. Maria Michael Visuwasam, A.P, CSE, VIT Page 18
Rectangle Rect; Triangle Tri; Rect.setWidth(5); Rect.setHeight(7); // Print the area of the object. cout << "Total Rectangle area: " << Rect.getArea() << endl; Tri.setWidth(5); Tri.setHeight(7); // Print the area of the object. cout << "Total Triangle area: " << Tri.getArea() << endl; return 0; When the above code is compiled and executed, it produces following result: Total Rectangle area: 35 Total Triangle area: 17 You can see how an abstract class defined an interface in terms of getarea() and two other classes implemented same function but with different algorithm to calculate the area specific to the shape. Designing Strategy: An object-oriented system might use an abstract base class to provide a common and standarized interface appropriate for all the external applications. Then, through inheritance from that abstract base class, derived classes are formed that all operate similarly. The capabilities (i.e., the public functions) offered by the external applications are provided as pure virtual functions in the abstract base class. The implementations L. Maria Michael Visuwasam, A.P, CSE, VIT Page 19
of these pure virtual functions are provided in the derived classes that correspond to the specific types of the application. This architecture also allows new applications to be added to a system easily, even after the system has been defined. 5. What is the use of Virtual functions and the rules for virtual function? Give an appropriate example. And also give the syntax for the pure virtual functions. (10) (Or) Explain how run time polymorphism can be achieved using virtual functions. A virtual function is a function in a base class that is declared using the keyword virtual. Defining in a base class a virtual function, with another version in a derived class, signals to the compiler that we don't want static linkage for this function. What we do want is the selection of the function to be called at any given point in the program to be based on the kind of object for which it is called. This sort of operation is referred to as dynamic linkage, or late binding. Rules for virtual functions: The virtual functions must be preceded by virtual keyword in the base class. The function in the derived class must have the same name as of the virtual function defined in the base class and the same prototype. The function in the derived class need not be preceded by virtual keyword. If it is preceded by virtual keyword, it makes no difference. If a function with the same name is not defined in the derived class, the original base class function is invoked. The virtual function must be defined in the base class; however it may have an empty body. To use virtual function, a class hierarchy should be present. The constructor function cannot be virtual. The virtual function cannot be a static member. They are accessed using object pointers. Example: Consider the following example where a base class has been derived by other two classes: #include <iostream> L. Maria Michael Visuwasam, A.P, CSE, VIT Page 20
using namespace std; class Shape protected: int width, height; Shape( int a=0, int b=0) width = a; height = b; int area() cout << "Parent class area :" <<endl; return 0; ; class Rectangle: public Shape Rectangle( int a=0, int b=0) Shape(a, b); int area () L. Maria Michael Visuwasam, A.P, CSE, VIT Page 21
cout << "Rectangle class area :" <<endl; return (width * height); ; class Triangle: public Shape Triangle( int a=0, int b=0) Shape(a, b); int area () cout << "Rectangle class area :" <<endl; return (width * height / 2); ; // Main function for the program int main( ) Shape *shape; Rectangle rec(10,7); Triangle tri(10,5); L. Maria Michael Visuwasam, A.P, CSE, VIT Page 22
// store the address of Rectangle shape = &rec; // call rectangle area. shape->area(); // store the address of Triangle shape = &tri; // call triangle area. shape->area(); return 0; When the above code is compiled and executed, it produces following result: Parent class area Parent class area The reason for the incorrect output is that the call of the function area() is being set once by the compiler as the version defined in the base class. This is called static resolution of the function call, or static linkage - the function call is fixed before the program is executed. This is also sometimes called early binding because the area() function is set during the compilation of the program. But now, let's make a slight modification in our program and precede the declaration of area() in the Shape class with the keyword virtual so that it looks like this: class Shape protected: int width, height; Shape( int a=0, int b=0) L. Maria Michael Visuwasam, A.P, CSE, VIT Page 23
width = a; height = b; virtual int area() cout << "Parent class area :" <<endl; return 0; ; After this slight modification, when the previous example code is compiled and executed, it produces following result: Output: Rectangle class area Triangle class area This time the compiler looks at the contents of the pointer instead of it's type. Hence since addresses of objects of tri and rec classes are stored in *shape the respective area() function is called. As you can see, each of the child classes has a separate implementation for the function area(). This is how polymorphism is generally used. You have different classes with a function of the same name, and even the same parameters, but with different implementations. Pure Virtual Functions: It's possible that you'd want to include a virtual function in a base class so that it may be redefined in a derived class to suit the objects of that class, but that there is no meaningful definition you could give for the function in the base class. We can change the virtual function area() in the base class to the following: class Shape protected: L. Maria Michael Visuwasam, A.P, CSE, VIT Page 24
; int width, height; Shape( int a=0, int b=0) width = a; height = b; // pure virtual function virtual int area() = 0; The = 0 tells the compiler that the function has no body and above virtual function will be called pure virtual function. 6. Explain all types of casting using c++ with example programs. (16) Casting operators used in c++ dynamic_cast The dynamic_cast is a casting operator. The following are salient features of dynamic_cast The casting operator is used only for polymorphic object casting. That means it is possible to cast from one polymorphic object to another polymorphic object. dynamic_cast is also known as safe cast. It succeeds only when properly it is casted. The syntax of dynamic_cast is dynamic_cast<toobject or reference>(from object or reference) Casting from derived class pointer object to base class pointer object always succeeds. But the casting from base class pointer object to derived class pointer object succeeds only if base pointer is actually pointing to an object of derived type. The casting is done with pointers or reference only. It cannot be done with objects. In cases of pointers, it is important to check the return value of the dynamic_cast to know if the cast is successful. In cases of references, the reference cannot be null, so dynamic_cast will throw bad_cast when it fails. Polymorphic objects can be dynamically casted using dynamic_cast. L. Maria Michael Visuwasam, A.P, CSE, VIT Page 25
Example: If a class is polymorphic then dynamic_cast will perform a special check during execution. This check ensures that the expression is a valid and complete object of the requested class. Take a look at the example: // dynamic_cast #include <iostream> #include <exception> using namespace std; class Base_Class virtual void dummy() ; class Derived_Class: public Base_Class int a; ; int main () try return 0; Base_Class * ptr_a = new Derived_Class; Base_Class * ptr_b = new Base_Class; Derived_Class * ptr_c; ptr_c = dynamic_cast< Derived_Class *>(ptr_a); if (ptr_c ==0) cout << "Null pointer on first type-cast" << endl; ptr_c = dynamic_cast< Derived_Class *>(ptr_b); if (ptr_c ==0) cout << "Null pointer on second type-cast" << endl; catch (exception& my_ex) cout << "Exception: " << my_ex.what(); In the example we perform two dynamic_casts from pointer objects of type Base_Class* (namely ptr_a and ptr_b) to a pointer object of type Derived_Class*. If everything goes well then the first one should be successful and the second one will fail. The pointers ptr_a and ptr_b are both of the type Base_Class. The pointer ptr_a points to an object of the type Derived_Class. The pointer ptr_b points to an object of the type Base_Class. So when the dynamic type cast is performed then ptr_a is pointing to a full L. Maria Michael Visuwasam, A.P, CSE, VIT Page 26
object of class Derived_Class, but the pointer ptr_b points to an object of class Base_Class. This object is an incomplete object of class Derived_Class; thus this cast will fail! Because this dynamic_cast fails a null pointer is returned to indicate a failure. When a reference type is converted with dynamic_cast and the conversion fails then there will be an exception thrown out instead of the null pointer. The exception will be of the type bad_cast. With dynamic_cast it is also possible to cast null pointers even between the pointers of unrelated classes. Dynamic_cast can cast pointers of any type to void pointer(void*). const_cast: This type of casting manipulates the constness of an object, either to be set or to be removed. For example, in order to pass a const argument to a function that expects a non-constant parameter. // const_cast #include <iostream> using namespace std; void print (char * str) cout << str << endl; int main () const char * c = "sample text"; print ( const_cast<char *> (c) ); return 0; Output: Sample text static_cast: static_cast can perform conversions between pointers to related classes, not only from the derived class to its base, but also from a base class to its derived. This ensures that at least the classes are compatible if the proper object is converted, but no safety check is performed during runtime to check if the object being converted is in fact a full object of the destination type. Therefore, it is up to the programmer to ensure that the conversion is safe. On the other side, the overhead of the type-safety checks of dynamic_cast is avoided. #include <iostream> #include <typeinfo> using namespace std; void main() L. Maria Michael Visuwasam, A.P, CSE, VIT Page 27
char c= a ; int a=static_cast<int>(c); cout<<a; Output: 97 reinterpret_cast The reinterpret_cast is a casting operator which is used to convert to an irrelevant type like converting an integer value to a pointer. #include <iostream> #include <typeinfo> using namespace std; void main() int normalint=100; int *pointerint=reinterpret_cast<int*>(normalint); cout<<pointerint; CROSS CASTING In multiple inheritance, when a derived class object is pointed by one of its base class pointer object, casting from one base class pointer into another base class pointer is known as cross casting. This is done by using dynamic_cast in multiple inheritances. //CROSS CASTING #include <iostream> #include <typeinfo> #include <conio.h> using namespace std; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 28
class Baseclass1 virtual ~Baseclass1() virtual void show() cout<<"base class 1"<<endl; ; class Baseclass2 int a; virtual void show() cout<<"base class 2"<<endl; ; class Derivedclass:public Baseclass1,public Baseclass2 int x; virtual void show() cout<<"derived class "<<endl; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 29
; int main() Baseclass1 *base1ptr=new Derivedclass; Baseclass2 *base2ptr=dynamic_cast<baseclass2*>(base1ptr); //call from base1ptr to base2ptr //baseptr base1ptr->show(); Baseclass1 *baseptr; Baseclass2 b2; //baseptr=&b2; baseptr->show(); getch(); Output: Derived class Down Casting: Casting from base class pointer to the derived class pointer is known as down casting. //Downcasting #include <conio.h> #include <iostream> #include <typeinfo> using namespace std; class Shape L. Maria Michael Visuwasam, A.P, CSE, VIT Page 30
virtual void show() ; class Circle:public Shape ; cout<<"shape is drawn"<<endl; void show() int main() cout<<"circle is drawn"<<endl; Shape *ptrshape, sh; Circle *ptrcircle, c; c.show(); ptrshape=&c; ptrshape->show(); ptrcircle=dynamic_cast<circle*>(ptrshape); //casting from base class ptr to derived class ptr ptrcircle->show(); getch(); Output: Circle is drawn Circle is drawn Circle is drawn L. Maria Michael Visuwasam, A.P, CSE, VIT Page 31
7. Explain briefly about the role of RTTI and typeid in c++. (8) RTTI: Real time information is a mechanism by which we can find the type of an object at run time. In other words, it allows programs that use pointer or reference to base classes to retrieve the actual derived types of the objects to which these pointers or references refer. When we define virtual functions in the base class, they can solve problems of the entire class hierarchy. When we need to solve problems related to some portions of the hierarchy we cannot directly solve it. It is better to use typeid with RTTI in this case. RTTI is provided through two operators: The typeid operator which returns the actual type of the object referred to by a pointer or a reference. The dynamic_cast operator, which safely converts from a pointer or reference to a base type to a pointer or reference of derived type. typeid typeid allows to check the type of an expression: typeid (expression) This operator returns a reference to a constant object of type type_info that is defined in the standard header file<typeinfo>. This returned value can be compared with another one using operators == and!= or can serve to obtain a null-terminated character sequence representing the data type or class name by using its name() member. // typeid #include <iostream> #include <typeinfo> using namespace std; int main () int * a,b; a=0; b=0; if (typeid(a)!= typeid(b)) cout << "a and b are of different types:\n"; cout << "a is: " << typeid(a).name() << '\n'; cout << "b is: " << typeid(b).name() << '\n'; L. Maria Michael Visuwasam, A.P, CSE, VIT Page 32
return 0; Output: a and b are of different types: a is: int * b is: int When typeid is applied to classes typeid uses the RTTI to keep track of the type of dynamic objects. When typeid is applied to an expression whose type is a polymorphic class, the result is the type of the most derived complete object: // typeid, polymorphic class #include <iostream> #include <typeinfo> #include <exception> using namespace std; class CBase virtual void f() ; class CDerived : public CBase ; int main () try CBase* a = new CBase; CBase* b = new CDerived; cout << "a is: " << typeid(a).name() << '\n'; cout << "b is: " << typeid(b).name() << '\n'; cout << "*a is: " << typeid(*a).name() << '\n'; cout << "*b is: " << typeid(*b).name() << '\n'; catch (exception& e) cout << "Exception: " << e.what() << endl; return 0; Output: a is: class CBase * b is: class CBase * *a is: class CBase *b is: class CDerived L. Maria Michael Visuwasam, A.P, CSE, VIT Page 33