1 of 152

OBJECT ORIENTED PROGRAMMING IN C++ �[UNIT-III]

U4.1

2 of 152

Learning Objectives

  • Extending classes
  • Types of Inheritance
  • Defining a derived class
  • Inheriting private members
  • Virtual, Direct & Indirect base class
  • Defining derived class constructors
  • Overriding inheritance method
  • Nesting of Classes

U4.2

3 of 152

Inheritance

  • Inheritance is the property of one class to inherit the properties of another class.
  • Major reason behind inheritance is reusability.
  • The mechanism of deriving a new class from an old or existing class is called inheritance (derivation).
  • The old class is referred to as the base class and new class is called derived class or sub class. The derived class inherits some or all of the traits from the base class.
  • A class can also inherit properties from more than one class, for more than one level.

U4.3

4 of 152

Inheritance Examples

U4.4

5 of 152

Derived class declaration

  • Specifies its relationship with the base class in addition to its own features

Class DerivedClass:[ VisibilityMode] BaseClass

{

//member of derived class

//can access member of base class

}

U4.5

6 of 152

visibility mode

  • Three types of visibility mode
    • public
    • protected
    • private
  • Default visibility mode is private

U4.6

7 of 152

Forms of Inheritance

  • Single Inheritance
  • Multiple Inheritance
  • Hierarchical Inheritance
  • Multilevel Inheritance
  • Hybrid Inheritance

U4.7

8 of 152

Types of

Inheritance

U4.8

9 of 152

Deriving a Class

  • The private derivation means that the derived class can access the public and the protected members of the base class privately.
  • With privately derived class, the public and the protected members of the base class become private members of the derived class.

U4.9

10 of 152

Base class visibility

Derived class visibility

 

Public

Private

Protected

Private

Not inherited

Not inherited

Not inherited

Protected

Protected

Private

Protected

Public

Public

Private

Protected

Visibility of Inherited Members

U4.10

11 of 152

class A // base class { .......... };

class B : acess_specifier A // derived class { ........... } ;

U4.11

12 of 152

#include <iostream>

using namespace std;

class base //single base class

{ public: int x;

void getdata()

{ cout << "Enter the value of x = "; cin >> x; } };

class derive : public base //single derived class

{ private: int y; public:

void readdata()

{ cout << "Enter the value of y = "; cin >> y; }

void product() { cout << "Product = " << x * y; } };

int main()

{ derive a; //object of derived class

a.getdata();

a.readdata();

a.product(); return 0; } //end of program

U4.12

13 of 152

Program of Single Inheritance

 #include<iostream.h> #include<conio.h>

class person //Base class or Super class

{ char name[20]; int age; public: void read_data(); void display_data();};

 class student : public person // Derived class or Sub class

{ int roll; int marks; char grade;

 public : void get_data(); char compute_grade(); void show_data(); };

void person :: read_data()

{ cout<<”\n Enter name:”; cin>>name; cout<<”\n Enter age: “; cin>>age;}

 void person :: display_data()

{cout<<”\n Name: “<< name; cout<< “\n Age: “ << age; }

 

U4.13

14 of 152

Program of Single Inheritance

 void student :: get_data()

{read_data(); cout<< “\n Enter Roll :”; cin>>roll;

cout<< “\n Enter Marks: “; cin>> marks; grade = compute_grade();}

char student :: compute_grade()

{char gd; if (marks<80) gd = ’B’ else gd = ‘A’; return (gd);}

void student :: show_data()

{cout << “\n Roll: “ << roll;cout << “\n Marks: “ << marks;

cout<< “\n Grade: “ <<grade;}

 main(){student s1; // Create an object of student type

s1.getdata();// Read data of a student

cout<<”\n The student data is…:; cout<<”\n”;

obj.dispaly_data(); obj.show_data(); return(0); }

 

U4.14

15 of 152

Multilevel Inheritance

 #include<iostream.h> #include<conio.h>

class A1{protected: char name[15]; int age; };

class A2:public A1 // First level derivation

{ protected: float height; float weight; };

class A3:public A2 // Second level derivation

protected: char sex; public: void get() // Reads data

{ cout<<”Name: “; cin>> name; cout<<”Age: “; cin>> age;

cout<<”Sex: “; cin>> sex; cout<<”Height: “; cin>> height;

cout<<”Weight: “; cin>> weight; } void show() // Displays data

cout<<”\n Name: “ << name; cout<<”\n Age: “ << age<< “Years”;

cout<<”\n Sex: “ << sex; cout<<”Height: “ << height << ”Feets”;

cout<<”Weight: “ << weight << “kg”;}};

U4.15

16 of 152

Multilevel Inheritance

void main()

{

A3 X; // Object declaration

X.get(); // Reads data

X.show(); // Displays data

}

 

 

 

U4.16

17 of 152

Multiple Inheritance

 

#include<iostream.h>

class A {protected: int a;};// class A declaration

class B {protected: int b;};// class B declaration

class C {protected: int c;};// class C declaration

class D {protected: int d;};// class D declaration

class E: public A, B, C, D // Multiple Derivation

{int e;

public:

void getdata()

{cout<<”\n Enter values of a, b, c, d & e: ”;

cin>>a>>b>>c>>d>>e;}

 

U4.17

18 of 152

Multiple Inheritance

void showdata()

{cout<<”\n a= “ <<a <<”b= “ <<b<< “c = “ << c << “d = ” <<d << “e= “ <<e;}};

 void main()

{E x; // Object declaration

x.getdata(); // Reads data

x.showdata(); //Displays data

OUTPUT:

 

Enter values of a, b, c, d & e: 1 2 4 8 16

a=1 b=2 c=4 d=8 z=16

 

U4.18

19 of 152

Example of Hierarchial Inheritance

 Instead of starting from the scratch, we can simply derive a new class employee from the base class person.

 #include<iostream.h> #include<conio.h>

class person //Base class or Super class

{char name[20]; int age;

public: void read_data();void display_data();};

class student : public person // Derived class or Sub class

{int roll; int marks; char grade; public : void get_data();

char compute_grade(); void show_data();};

 class employee : public person

{float bp; float hr; float sal;

 public:void input_emp(); float compute_salary(); void disp_emp();};

 

U4.19

20 of 152

Example of Hierarchical Inheritance

void employee :: input_emp()

{read_data(); // Read name & age from the base class

cout<< “\n Enter Basic Pay:”; cin >> bp;

cout<<”\n Enter HRA :”; cin>>hr;

sal = compute_salary();}

 float employee :: compute_salary()

{float total; total=bp+hr+2.5*bp; return(total);}

void employee :: disp_emp()

{cout<< “\n B.P. : “ << bp; cout<< “\n H.R. : “ << hr;

cout<< “\n Salary : “ << sal; }

 

 

U4.20

21 of 152

Example of Hierarchial Inheritance

void person :: read_data()

{cout<<”\n Enter name:”; cin>>name;

cout<<”\n Enter age: “; cin>>age;}

 void person :: display_data()

{cout<<”\n Name: “<< name;

cout<< “\n Age: “ << age;}

 void student :: get_data()

{read_data(); //read name & age from base class

cout<< “\n Enter Roll :”; cin>>roll;

cout<< “\n Enter Marks: “; cin>> marks;

grade = compute_grade();}

 

U4.21

22 of 152

Example of Hierarchial Inheritance

char student :: compute_grade()

{char gd;

if (marks<80)

gd = ’B’

else gd = ‘A’;

return (gd);}

void student :: show_data()

{

cout << “\n Roll: “ << roll;

cout << “\n Marks: “ << marks;

cout<< “\n Grade: “ <<grade;

}

 

U4.22

23 of 152

Example of Hierarchial Inheritance

main()

{student s1; // Create an object of student type

employee e1; // Create an object of employee tppe

s1.getdata();// Read data of a student

cout<<”\n The student data is…:;

obj.dispaly_data();//inherit function from class person

obj.show_data();

e1.input_emp(); // Read Employee data

cout<<”\n The Employee data is…:;

e1.dispay_data ();// Inherit function from class person to display

e1. disp_emp (); // Display Employee details

return(0);}

U4.23

24 of 152

U4.24

25 of 152

Constructors/Destructors order of Inheritance

  • Destructors, constructors, and assignment operators are not inherited: they may be called automatically were necessary
  • Constructors are called from the “bottom up”
  • Destructors are called from the “top down”
  • C++ matches a function call with the correct function definition at compile time: known as static binding
  • the compiler can match a function call with the correct function definition at run time: known as dynamic binding.
    • declare a function with the keyword virtual if you want the compiler to use dynamic binding for that specific function.
  • The virtual keyword indicates to the compiler that
    • it should choose the appropriate definition of a function not by the type of reference, but by the type of object that the reference refers to.

U4.25

26 of 152

Abstract Classes

  • Abstract classes act as expressions of general concepts from which more specific classes can be derived. You cannot create an object of an abstract class type; however, you can use pointers and references to abstract class types.
  • A class that contains at least one pure virtual function is considered an abstract class. Classes derived from the abstract class must implement the pure virtual function or they, too, are abstract classes.
  • A virtual function is declared as "pure" by using the pure-specifier syntax

class Account { public: Account( double d ); // Constructor.

virtual double GetBalance(); // Obtain balance.

virtual void PrintBalance() = 0; // Pure virtual function.

private: double _balance; };

U4.26

27 of 152

Abstract Classes

class Animal {�public: virtual void speak() = 0;};

class Bird : public Animal {�public: virtual void speak() { printf("twitter"); }};

class Mammal : public Animal {�public: virtual void speak() { printf("can't speak"); }� void bark() { printf("can't bark"); }};

class Cat : public Mammal {�public: void speak() { printf("meow"); }� virtual void purr() { printf("purrrrr"); }};

class Dog : public Mammal {�public: virtual void speak() { printf("wouf"); }� void bark() { printf("wouf"); }

};

U4.27

28 of 152

Overriding in C++

  • Overriding: a method in a parent class is replaced in a child class by a method having exact same type signature.
  • In C++, overriding uses the keyword virtual.
  • When a class contains a virtual method, an internal table called the virtual method table is created.
  • This table is used in the implementation of the dynamic binding of message to method required by the virtual method.
  • Each instance of a class must contain an additional hidden pointer value, which references the virtual method table.
  • A pure virtual method must be overridden in subclasses.

U4.28

29 of 152

Restrictions on using Abstract Classes

  • Abstract classes cannot be used for:
  • Variables or member data
  • Argument types
  • Function return types
  • Types of explicit conversions
  • Another restriction is that if the constructor for an abstract class calls a pure virtual function, either directly or indirectly, the result is undefined. However, constructors and destructors for abstract classes can call other member functions.
  • Pure virtual functions can be defined for abstract classes, but they can be called directly only by using the syntax:
  • abstract-class-name :: function-name( )
  • This helps when designing class hierarchies whose base class(es) include pure virtual destructors, because base class destructors are always called in the process of destroying an object.

U4.29

30 of 152

Example

class base { public: base() {}

virtual ~base()=0; };

// Provide a definition for destructor.

base::~base() {}

class derived: public base { public: derived() {}

~derived(){} };

int main() {

derived *pDerived = new derived;

delete pDerived; }

U4.30

31 of 152

Inner Working of Virtual Functions

  • Don’t need to know how to use it!
    • Principle of information hiding
  • Virtual function table
    • Compiler creates it
    • Has pointers for each virtual member function
    • Points to location of correct code for that function
  • Objects of such classes also have pointer
    • Points to virtual function table

U4.31

32 of 152

The virtual table

  • To implement virtual functions, C++ uses a special form of late binding known as the virtual table. The virtual table is a lookup table of functions used to resolve function calls in a dynamic/late binding manner. The virtual table sometimes goes by other names, such as “vtable”, “virtual function table”, “virtual method table”, or “dispatch table”.

  • First, every class that uses virtual functions (or is derived from a class that uses virtual functions) is given it’s own virtual table. This table is simply a static array that the compiler sets up at compile time. A virtual table contains one entry for each virtual function that can be called by objects of the class.

U4.32

33 of 152

  • Each entry in this table is simply a function pointer that points to the most-derived function accessible by that class.
  • Second, the compiler also adds a hidden pointer to the base class, which we will call *__vptr. *__vptr is set (automatically) when a class instance is created so that it points to the virtual table for that class.

U4.33

34 of 152

class Base

{

public:

    virtual void function1() {};

    virtual void function2() {};

};

 class D1: public Base

{

public:

    virtual void function1() {};

};

 class D2: public Base

{

public:

    virtual void function2() {};

};

Because there are 3 classes here, the compiler will set up 3 virtual tables: one for Base, one for D1, and one for D2.

The compiler also adds a hidden pointer to the most base class that uses virtual functions. Although the compiler does this automatically,

U4.34

35 of 152

we’ll put it in the next example just to show where it’s added:

class Base

{

public:

    FunctionPointer *__vptr;

    virtual void function1() {};

    virtual void function2() {};

};

 class D1: public Base

{

public:

    virtual void function1() {};

};

 class D2: public Base

{

public:

    virtual void function2() {};

};

U4.35

36 of 152

  • When a class object is created, *__vptr is set to point to the virtual table for that class. For example, when a object of type Base is created, *__vptr is set to point to the virtual table for Base. When objects of type D1 or D2 are constructed, *__vptr is set to point to the virtual table for D1 or D2 respectively.

  • Now, let’s talk about how these virtual tables are filled out. Because there are only two virtual functions here, each virtual table will have two entries (one for function1(), and one for function2()). Remember that when these virtual tables are filled out, each entry is filled out with the most-derived function an object of that class type can call.

U4.36

37 of 152

  • Base’s virtual table is simple. An object of type Base can only access the members of Base. Base has no access to D1 or D2 functions. Consequently, the entry for function1 points to Base::function1(), and the entry for function2 points to Base::function2().

  • D1′s virtual table is slightly more complex. An object of type D1 can access members of both D1 and Base. However, D1 has overridden function1(), making D1::function1() more derived than Base::function1(). Consequently, the entry for function1 points to D1::function1(). D1 hasn’t overridden function2(), so the entry for function2 will point to Base::function2().
  • D2′s virtual table is similar to D1, except the entry for function1 points to Base::function1(), and the entry for function2 points to D2::function2().

U4.37

38 of 152

Here’s a picture

of this

graphically:

U4.38

39 of 152

Virtual Base Classes

  • A situation may arise where all the three kinds of inheritance, namely, multilevel, multiple and hierarchical inheritance are involved.
  • This is illustrated in the figure where the child has two direct base classes 'parent1' and 'parent2' which themselves have a common base class 'grandparent'.
  • The 'child' inherits the behaviors of grandparent class via two separate paths.
  • It can also inherit directly, as shown by the dotted lines.
  • The grandparent class is sometimes referred to as indirect base class.

U4.39

40 of 152

Virtual Base Classes

  • Such inheritance by the child class may create some problems.
  • All the public and protected members of the grandparent class are inherited into the child class twice; first via parent1 class and then again via parent2 class.
  • This means that the child class would have duplicate set of members inherited from grandparent, which introduces ambiguity and should be avoided.
  • The duplication of inherited members due to these multiple paths can be avoided by making the common base class as virtual base class, while declaring the direct or intermediate base classes.

U4.40

41 of 152

Virtual Base Classes

  • When a class is made virtual base class, C++ takes necessary care to see that only one copy of that class is inherited, regardless of how many inheritance paths exist between the virtual base class and a derived class.
  • Example: Student Result Processing System.

U4.41

42 of 152

Example -objects of type derived can directly access the public members of base:

#include <iostream>

using namespace std;

class base {

int i, j;

public:

void set(int a, int b)

{ i=a; j=b;

}

void show() {

cout << i << " " << j << "\n"; }

};

class derived : public base

{int k;

public:

derived(int x)

{ k=x; }

void showk() { cout << k << "\n"; }};

int main()

{derived ob(3);

ob.set(1, 2); // access member of base

ob.show(); // access member of base

ob.showk(); // member of derived class

return 0;

}

U4.42

43 of 152

When the base class is inherited by using the private access specifier, all public and protected members of the base class become private members of the derived class. For example, the following program will not even compile because both set( ) and show( ) are now private elements of derived:

// This program won't compile.

#include <iostream>

using namespace std;

class base {

int i, j;

public:

void set(int a, int b) { i=a; j=b; }

void show() { cout << i << " " << j << "\n";}

};

U4.43

44 of 152

// Public elements of base are private in derived.

class derived : private base

{

int k;

public:

derived(int x) { k=x; }

void showk() { cout << k << "\n"; }

};

int main()

{

derived ob(3);

ob.set(1, 2); // error, can't access set()

ob.show(); // error, can't access show()

return 0;

}

U4.44

45 of 152

Protected members behave differently. If the base class is inherited as public, then the base class' protected members become protected members of the derived class and are, therefore, accessible by the derived class. By using protected, you can create class members that are private to their class but that can still be inherited and accessed by a derived class.

#include <iostream>

using namespace std;

class base {

protected:

int i, j; // private to base, but accessible by derived

public:

void set(int a, int b) { i=a; j=b; }

void show() { cout << i << " " << j << "\n"; }

};

U4.45

46 of 152

class derived : public base {

int k;

public:

// derived may access base's i and j

void setk() { k=i*j; }

void showk() { cout << k << "\n"; }

};

int main()

{

derived ob;

ob.set(2, 3); // OK, known to derived

ob.show(); // OK, known to derived

ob.setk();

ob.showk();

return 0;

}

U4.46

47 of 152

In this example, because base is inherited by derived as public and because i and j are declared as protected, derived's function setk( ) may access them. If i and j had been declared as private by base, then derived would not have access to them, and the program would not compile.

U4.47

48 of 152

It is possible to inherit a base class as protected. When this is done, all public and protected members of the base class become protected members of the derived class.

For example,

#include <iostream>

using namespace std;

class base {

protected:

int i, j; // private to base, but accessible by derived

public:

void setij(int a, int b) { i=a; j=b; }

void showij() { cout << i << " " << j << "\n"; }

};

U4.48

49 of 152

// Inherit base as protected.

class derived : protected base

{

int k;

public:

// derived may access base's i and j and setij().

void setk()

{

setij(10, 12);

k = i*j;

}

// may access showij() here

void showall()

{

cout << k << " ";

showij();

}

};

U4.49

50 of 152

int main()

{

derived ob;

// ob.setij(2, 3); // illegal, setij() is protected member of derived

ob.setk(); // OK, public member of derived

ob.showall(); // OK, public member of derived

// ob.showij(); // illegal, showij() is protected member of derived

return 0;

}

As you can see by reading the comments, even though setij( ) and showij( ) are public members of base, they become protected members of derived when it is inherited using the protected access specifier. This means that they will not be accessible inside main( ).

U4.50

51 of 152

It is possible for a derived class to inherit two or more base classes. For example, in this short example, derived inherits both base1 and base2.

An example of multiple base classes.

#include <iostream>

using namespace std;

class base1 {

protected:

int x;

public:

void showx() { cout << x << "\n"; }

};

class base2 {

protected:

int y;

public:

U4.51

52 of 152

void showy() {cout << y << "\n";}

};

// Inherit multiple base classes.

class derived: public base1, public base2 {

public:

void set(int i, int j) { x=i; y=j; }

};

int main()

{

derived ob;

ob.set(10, 20); // provided by derived

ob.showx(); // from base1

ob.showy(); // from base2

return 0;

}

U4.52

53 of 152

how an access declaration works,Ex-

class base {

public:

int j; // public in base

};

// Inherit base as private.

class derived: private base {

public:

// here is access declaration

base::j; // make j public again

.

.

.

};

Because base is inherited as private by derived, the public member j is made a private

member of derived. However, by including

base::j;

U4.53

54 of 152

Aggregation or containership or object Composition in C++

A special form of association that models a whole-part relationship between an aggregate (the whole) and its parts.

Aggregation is also called whole-part or HasA.

For example, an Aircraft contains an Engine or in other words, an Aircraft has an Engine.

U4.54

55 of 152

Aggregation

• Represents a “has-a” (whole-part) relationship

• An object of the whole has objects of the part

U4.55

56 of 152

For example, among other things, a car consists of tires and an engine. Note that the opposite of aggregation is decomposition.

U4.56

57 of 152

Aggregation

  • Models "part of" hierarchy
  • Useful for modeling the breakdown of a product into its component parts .
  • UML notation: Like an association but with a small diamond indicating the assembly end of the relationship.

U4.57

58 of 152

A form of aggregation with strong ownership and coincident lifetime as part of the whole. Parts with non-fixed multiplicity may be created after the composite itself, but once created they live and die with it (i.e., they share lifetimes). Such parts can also be explicitly removed before the death of the composite.

U4.58

59 of 152

  • Containment or containership: This relationship is applied when the part contained with in the whole part, dies when the whole part dies.

It is represented as darked diamond at the whole part.

example:

class A{

//some code

};

class B

{

A aa; // an object of class A;

// some code for class B;

};

In the above example we see that an object of class A is instantiated with in the class B. so the object class A dies when the object class B dies.we can represnt it in diagram like this.

class A

class B

U4.59

60 of 152

Object Composition

  • Use of objects in a class as data members is referred to as object composition
  • Object can be a collection of many other objects
  • The relationship is called a has-a relationship or containership
  • When it comes to the real world programming problem, an object of class TextBox can be contained in the class Form and can so be said as a Form contains a TextBox (or in another way, a Form is composed of a TextBox).
  • Inheritance represents ‘is -a ‘ relationship in OOP, while Containership represents a’ has -a’ relationship.

U4.60

61 of 152

Containership

 class address {

int hno;

char colony[20];

char dist[20];

char state[20];

int pincode;

  public:

void get_data();

void show_data();

};

 class person {

char name[20];

address resadd;

};

U4.61

62 of 152

Containership

  •  Here, Containership (resadd is a new variable / object of class address). The above declaration establishes the relationship i.e. A person “has an” address. Now an object of a class person will always contain an object of class address.
  • To invoke the function of contained object, resadd.getdata(), resadd.showdata() will be mentioned in the program.
  • Inheritance and Containership two important concepts found in OOP (Object Orientated Programming: Example- C++).

U4.62

63 of 152

class Department�{�protected:

int id;�char name[50];

public:

void setDepartment()�{�cout<>id;�cout<>name;�}�void displayDepartment()�{�cout<<"\n Department ID is:"<<id<<"\n";�cout<<"\n Department Name is:"<<name<<"\n";�}};

class Employee�{�protected:

int eid;�char ename[50];�Department dobj;

public:

void setEmployee()�{�cout<>eid;�cout<>ename;�dobj.setDepartment();�}�void displayEmployee()�{�cout<<"\n Employee ID is:"<<eid<<"\n";�cout<<"\n Employee Name is:"<<ename<<"\n";�dobj.displayDepartment();�}�};

U4.63

64 of 152

Destructors in Derived Classes

  • Invoked in reverse order of the constructor invocation

#include <iostream.h>

class B1{

public :

B1(){cout<< “no argument constructor in B1”;}

~B1(){cout<< “destructor in B1”;}

};

class B2{

public :

B2(){cout<< “no argument constructor in B2”;}

~B2(){cout<< “destructor in B2”;}

};

U4.64

65 of 152

class D: public B1, public B2

{

public :

D(){cout<< “no argument constructor in D”;}

~D(){cout<< “destructor in D”;}

};

void main(){ D objd;}

Run

no argument constructor in B1

no argument constructor in B2

no argument constructor in D

destructor in D

destructor in B2

destructor in B1

U4.65

66 of 152

Over loaded Member Functions

  • The members of the derived class can have the same name as those defined in the base class
  • If the same member exist in both the base class and the derived class, the member in the derived class will be executed
  • The member of the base class can be access using scope resolution with overriding functions
  • The general form is

Classname :: Membername ( ) ;

U4.66

67 of 152

class a{

public :

void fn(){ cout<<"base\n";}};

class b: public a{

public :

void fn(){ cout<<"derived\n";}};

void main(){

b obj;

obj.fn();

obj.a::fn(); }

U4.67

68 of 152

Abstract Classes

  • An abstract class is one that has no instances and is not designed to create objects
  • Only designed to be inherited
  • Provides a frame work, upon which other classes can be built
  • Normally exist at the root of the hierarchy

U4.68

69 of 152

Conclusion

  • Inheritance provides the concept of reusability. The derived class inherits some or all of the properties of the base class.
  • A private member of a class cannot be inherited either in public mode or in private mode.
  • The member functions of a derived class can directly access only the in the protected and public data.
  • Multipath inheritance may lead to duplication of inherited members from a “grandparent” base class. This may be avoided making the common base class a virtual base class.
  • In multiple inheritance, the base classes are constructed in the order in which they in the declaration of the derived class.
  • In multilevel inheritance, the constructors are executed in the order of inheritance.
  • A class can contain object of other classes. This is known as containership or nesting.

U4.69

70 of 152

POLYMORPHISM / OVERLOADING

  • A Greek term suggest the ability to take more than one form.
  • It is a property by which the same message can be sent to the objects of different class.

Example: Draw a shape (Box, Triangle, Circle etc.), Move ( Chess, Traffic, Army).

  • Allows to create multiple definition for operators & functions.

Example: ‘+’ is used for adding numbers / to concatenate two string / Sets of Union and so on.

  • There are two types of polymorphism, compile time polymorphism and run time polymorphism. It is also known as early or static binding and run time binding.

U4.70

71 of 152

POLYMORPHISM (Contd.)

  • Function and operator overloading is the example of compile time polymorphism and virtual function is the example of run time polymorphism.
  • A Virtual function, equated to zero is called pure virtual function.
  • Dynamic Binding/ Late Binding. Run-time dependent. Execution depends on the base of a particular definition.
  • Extensively used in implementing inheritance.

U4.71

72 of 152

Function Overloading

U4.72

73 of 152

What is the need for function overloading?

U4.73

74 of 152

How to implement function overloading?

U4.74

75 of 152

Contd…

U4.75

76 of 152

Contd…

U4.76

77 of 152

Unary Operator Overloading

// Program1.cpp: Index class with operator overloading for increment operator

 #include < iostream.h>

class Index

{ private: int value; // Index Value

public:

Index ( ) // No argument constructor

{ value = 0; }

int GetIndex( ) // Index Access

{ return value; }

void operator + +( ) // prefix or postfix increment operator

{

value = value + 1; // value+ + ; }} ;

 

U4.77

78 of 152

Unary Operator Overloading

void main( )

{ Index idx1, idx2; // idex1 and idx2 are objects of Index class

 // display index values

cout << “ \nIndex1 = “ << idx1 . GetIndex ( ) ;

cout << “ \nIndex2 = “ << idx2 . GetIndex ( ) ;

 

// Advance Index objects with + + operators

+ + idx1; // equivalent to idx1. operator + + ( ) ;

idx2 + + ;

idx2 + + ;

cout << “ \ nIndex1 = “ << idx1. GetIndex ( ) ;

cout << “ \ nIndex2 = “ << idx2. GetIndex ( ) ;

}

 

 

U4.78

79 of 152

Operator Returns Values

 The operator function in the previous program Program1.cpp has a subtle defect. An attempt to use an expression such as;

idx1= idx2++;

will lead to a compilation error like Improper Assignment because the return type of operator++ is defined as void type. Such an assignment operation can be permitted after modifying the return type of the operator ++() member function of the index class.

 //Program2.cpp: Index class with overloaded operator returning an object

#include < iostream.h>

class Index{ private: int value; // Index Value

public: Index ( ) // No argument constructor

{ value = 0; }

int GetIndex( ) // Index Access

{ return value; }

U4.79

80 of 152

Operator Returns Values

Index operator + +( ) // Returns nameless object of class Index

{ Index temp; // temp object

value = value + 1; // update index value

temp.value = value; // Initialise temp object

return temp; // Returns temp object

}} ;

 void main( )

{Index idx1, idx2; // idex1 and idx2 are objects of Index class

cout << “ \nIndex1 = “ << idx1 . GetIndex ( ) ;

cout << “ \nIndex2 = “ << idx2 . GetIndex ( ) ;

// Returned object of idx2+ + is assigned to object idx1

idx1 = idx2++; // invokes the overloaded function

idx2 + + ; // Returned object of idx2++ is unused

  cout << “ \ nIndex1 = “ << idx1. GetIndex ( ) ;

cout << “ \ nIndex2 = “ << idx2. GetIndex ( ) ;}

 

 

 

U4.80

81 of 152

Binary Operator Overloading

Complex numbers consists of two parts: real part and imaginary part. It is represented as ( x+iy), where x is the real part and y is the imaginary part. The process of performing the addition operation is illustrated below. Let c1, c2and c3 be three complex numbers represented as follows:c1 = x1 + i y1; c2 = x2 + i y2;

 The operation c3 = c1 + c2 is given by

  c3 = ( c1 .x1 + c2 .x2 ) + i ( c1. y1 + c2. y2 ) ;

// Complex1.cpp: Complex numbers operations with binary operator overloading

# include < iostream.h> class complex{ private : float real ; float imag ;

complex number

public : complex ( ) // no argument constructor

{ real = imag = 0 . 0 ;}

U4.81

82 of 152

Binary Operator Overloading

void getdata ( ) // read complex number

{ cout << “Real Part ? “ ; cin >> real ;

cout << “Imag Part ? “ ; cin >> imag ; }

complex operator + ( complex c2 ) ; // complex addition

void outdata ( char *msg ) // display complex number

{ cout << endl << msg ; cout << “ ( “ << real ;

cout << “ , “ << imag<<“ ) “ ; }} ;

 // add default and c2 complex objects

complex complex : : operator + ( complex c2 )

{ complex temp ; // object temp of complex class

temp . real = real + c2 . real ; //add real parts

temp . imag = imag = c2 . imag ; //add imaginary parts

return ( temp ) ; // return complex object

}

 

U4.82

83 of 152

Binary Operator Overloading

void main ( )

{

complex c1, c2 , c3 ; // c1 , c2 , c3 are object of complex class

cout << “ Enter Complex Number c1 . . “ << endl ;

cl . getdata ( ) ;

cout << “ Enter Complex Number c2 . . “ << endl ;

c2 . getdata ( ) ;

c3 = c1 + c2 ; // add c1 and c2 and assign the result to c3 i.e; c3 = c1 . operator+ ( c2 ) ;

c3 . outdata ( “ c3 = c1 + c2 : “ ) ; // display result

}

 

U4.83

84 of 152

  C++ virtual function is,

  • A member function of a class
  • Declared with virtual keyword
  • Usually has a different functionality in the derived class
  • A function call is resolved at run-time

  • The difference between a non-virtual c++ member function and a virtual member function is, the non-virtual member functions are resolved at compile time. This mechanism is called static binding.

  • Where as the c++ virtual member functions are resolved during run-time. This mechanism is known as dynamic binding.

Pointer object of base class can point to any object of derived class but reverse is not true.

Virtual function

U4.84

85 of 152

Need For Virtual Functions

When objects of different class in a class hierarchy, react to the same message in their own unique ways, they are said to exhibit polymorphic behavior. This program has the base class Father and the derived class Son and has a member function show() with the same name and prototype. In C++, a pointer to the base class can be used to point to its derived class objects.

#include<iostream.h>#include<string.h> //Parent1.cpp: Invoking DC members through BC pointer

 class Father // Father’s name

{ char name[20];

public: Father(char *fname)

{strcpy(name, fname); //fname contains Father’s name

} void show() {cout<<”Father’s name:” << name << endl;}};

class son: public Father{ char name[20]; // Son’s name

public: // 2 Argument constructor; invokes 1 argument constructor of Father

Son( char *sname, char *fname) : Father(fname)

{ strcpy(name, sname); // sname contains Son’s name }

 void show() //show in derived class

{ cout<<”Son’s name:” << name << endl; }};

 void main()

{ Father *fp; // pointer to Father’s class object

Father f1 ( “ RAVI”); fp = &f1; // fp points to Father class object

fp->show(); // Display Father show() function

Son s1 ( “ AMAN”, “RAVI”);

fp = &s1; // valid assignment

fp->show(); // guess what is output? Father or Son!

}

U4.85

86 of 152

Need For Virtual Functions

  • It is interesting to note that after valid assignment to the address of object s1 of the class Son to fp, it still invokes the member function show() defined in the class Father.
  • Hence we need Runtime polymorphism (i.e. Virtual Function) that allows to postpone the decision of selecting the suitable member functions until runtime.
  • In this case, a member function to be invoked depend on the class’s object to which the pointer is pointing.

U4.86

87 of 152

Pure virtual (abstract) functions and abstract base classes

C++ allows you to create a special kind of virtual function called a pure virtual function (or abstract function) that has no body at all! A pure virtual function simply acts as a placeholder that is meant to be redefined by derived classes.

A pure virtual function is a function that has the notation "= 0" in the declaration of that function.

class SomeClass

{

public:

virtual void pure_virtual() = 0; // a pure virtual function // note that there is no function body

};

U4.87

88 of 152

A pure virtual function can have an implementation in C++ – which is something that even many expert C++ developers do not know.

class SomeClass

{

public:

virtual void pure_virtual() = 0; // a pure virtual function // note that there is no function body };

/*This is an implementation of the pure_virtual function which is declared as a pure virtual function. This is perfectly legal: */

void SomeClass::pure_virtual()

{

cout<<"This is a test"<<endl;

}

U4.88

89 of 152

  • It is rare to see a pure virtual function with an implementation in real-world code, but having that implementation may be desirable when you think that classes which derive from the base class may need some sort of default behavior for the pure virtual function.
  • So, for example, if we have a class that derives from our SomeClass class above, we can write some code like this – where the derived class actually makes a call to the pure virtual function implementation that is inherited:

U4.89

90 of 152

class base�{public:�virtual void show()=0; //pure virtual function�};�class derived1 : public base�{public:�void show(){�cout<<"\n Derived 1";}};�class derived2 : public base�{�public:�void show()�{cout<<"\n Derived 2";}};��

void main()�{�base *b; derived1 d1; derived2 d2;�b = &d1;�b->show();�b = &d2;�b->show();�}

U4.90

91 of 152

  • Calling a virtual function is slower than calling a non-virtual function for a couple of reasons:
  • First, we have to use the *__vptr to get to the appropriate virtual table.
  • Second, we have to index the virtual table to find the correct function to call. Only then can we call the function.
  • As a result, we have to do 3 operations to find the function to call, as opposed to 2 operations for a normal indirect function call, or one operation for a direct function call.
  • However, with modern computers, this added time is usually fairly insignificant/unimportant.

Drawback of Virtual Function

U4.91

92 of 152

the *__vptr in each class points to the virtual table for that class. The entries in the virtual table point to the most-derived version of the function objects of that class are allowed to call.

So consider what happens when we create an object of type D1:

int main()

{

    D1 cClass;

}

Because cClass is a D1 object, cClass has it’s *__vptr set to the D1 virtual table.

U4.92

93 of 152

Now, let’s set a base pointer to D1:

int main()

{

    D1 cClass;

    Base *pClass = &cClass;

}

So what happens when we try to call pClass->function1()?

int main()

{

    D1 cClass;

    Base *pClass = &cClass;

    pClass->function1();

}

U4.93

94 of 152

  • First, the program recognizes that function1() is a virtual function. Second, uses pClass->__vptr to get to D1′s virtual table. Third, it looks up which version of function1() to call in D1′s virtual table. This has been set to D1::function1(). Therefore, pClass->function1() resolves to D1::function1()!

  • Now, you might be saying, “But what if Base really pointed to a Base object instead of a D1 object. Would it still call D1::function1()?”. The answer is no.

int main()

{

    Base cClass;

    Base *pClass = &cClass;

    pClass->function1();

}

U4.94

95 of 152

In this case, when cClass is created, __vptr points to Base’s virtual table, not D1′s virtual table. Consequently, pClass->__vptr will also be pointing to Base’s virtual table. Base’s virtual table entry for function1() points to Base::function1(). Thus, pClass->function1() resolves to Base::function1(), which is the most-derived version of function1() that a Base object should be able to call.

U4.95

96 of 152

How VPTR and Virtual table works(Memory Layout)

class Test

{

public:

int data1;

int data2;

int fun1();

};

int main()

{

Test obj;

cout << "obj's Size = " << sizeof(obj) << endl;

cout << "obj 's Address = " << &obj << endl;

return 0;

OUTPUT:

Sobj's Size = 4 Bytes�obj 's Address = 0012FF7C

Note: Any Plane member function does not take any memory.

U4.96

97 of 152

Example 2: Memory Layout of Derived class

class Test

{

public:

int a;

int b;

};

class dTest : public Test

{

public:

int c;

};

int main()

{

Test obj1;

cout << "obj1's Size = " << sizeof(obj1) << endl;

cout << "obj1's Address = " << &obj1 << endl;

dTest obj2;

cout << "obj2's Size = "<< sizeof(obj2) << endl;

cout << "obj2's Address = "<< &obj2 << endl;

return 0;

}

OUTPUT:�obj1's Size = 4�obj1's Address = 0012FF78�obj2's Size = 6�obj2's Address = 0012FF6C

U4.97

98 of 152

Example 3: Memory layout If we have one virtual function.

class Test

{

public:

int data;

virtual void fun1()

{

cout << "Test::fun1" << endl;

}

};

int main()

{

Test obj;

cout << "obj's Size = " << sizeof(obj) << endl;

cout << "obj's Address = " << &obj << endl;

return 0;

}

OUTPUT:

obj's Size = 4�obj's Address = 0012FF7C

Note: Adding one virtual function in a class takes 2 Byte extra.

U4.98

99 of 152

Example 4: More than one Virtual function

class Test

{

public:

int data;

virtual void fun1() { cout << "Test::fun1" << endl; }

virtual void fun2() { cout << "Test::fun2" << endl; }

virtual void fun3() { cout << "Test::fun3" << endl; }

virtual void fun4() { cout << "Test::fun4" << endl; }

};

int main()

{

Test obj;

cout << "obj's Size = " << sizeof(obj) << endl;

cout << "obj's Address = " << &obj << endl;

return 0;

}

U4.99

100 of 152

OUTPUT:

obj's Size = 4�obj's Address = 0012FF7C

Note: Adding more virtual functions in a class, no extra size taking i.e. Only one machine size taking(i.e. 2 byte)

U4.100

101 of 152

Multiple Inheritance

class Base1

{

public:

virtual void fun();

};

class Base2

{

public:

virtual void fun();

};

class Base3

{

public:

virtual void fun();

};

class Derive : public Base1, public Base2, public Base3

{

};

int main()

{

Derive obj;

cout << "Derive's Size = " << sizeof(obj) << endl;

return 0;

}

OUTPUT:

Derive's Size = 6

U4.101

102 of 152

in C++ a destructor is generally used to deallocate memory and do some other cleanup for a class object and it’s class members whenever an object is destroyed.

Example without a Virtual Destructor:

#include iostream.h

class Base

{

public:

Base()

{

cout<<"Constructing Base";

}

// this is a destructor:

~Base()

{

cout<<"Destroying Base";

}

};

U4.102

103 of 152

class Derive: public Base

{

public:

Derive()

{

cout<<"Constructing Derive";

}

~Derive(){

cout<<"Destroying Derive";

}

};

void main()

{

Base *basePtr = new Derive();

delete basePtr;

}

o/p-

Constructing Base

Constructing Derive

Destroying Base

we can see that the constructors get called in the appropriate order when we create the Derive class object pointer in the main function.

But there is a major problem with the code above: the destructor for the "Derive" class does not get called at all when we delete ‘basePtr’.

U4.103

104 of 152

what we can do is make the base class destructor virtual, and that will ensure that the destructor for any class that derives from Base (in our case, its the "Derive" class) will be called.

class Base

{

public:

Base()

{

cout<<"Constructing Base";

}

// this is a destructor:

virtual ~Base()

{

cout<<"Destroying Base";

}

};

o/p-

Constructing Base

Constructing Derive

Destroying Derive

Destroying Base

U4.104

105 of 152

Conclusion

  • Polymorphism simple means one name having multiple forms.
  • There are two types of polymorphism, compile time polymorphism and run time polymorphism. It is also known as early or static binding and run time binding.
  • Function and operator overloading is the example of compile time polymorphism and virtual function is the example of run time polymorphism.
  • A Virtual function, equated to zero is called pure virtual function.

U4.105

106 of 152

Working with Files

U4.106

107 of 152

Learning Objectives

  • Console User Interaction
  • Input Output Stream
  • File Stream Classes
  • Opening a file with open()
  • Opening a file with constructors
  • End-of- file detection
  • File modes
  • File pointers

U4.107

108 of 152

Learning Objectives

  • Sequential File Operation
  • Random Access Files
  • Error Handling
  • Command-line Arguments

U4.108

109 of 152

Input/Output with Files

C++ has support both for input and output

with files through the following classes:

• ofstream: File class for writing operations

(derived from ostream).

• ifstream: File class for reading operations

(derived from istream).

• fstream: File class for both reading and

writing operations (derived from iostream).

U4.109

110 of 152

Open a file

First operation generally done on an object of one of these classes is to associate it to a real file.

• In order to open a file with a stream object, we use its member function open():

void open (const char * filename, openmode mode);

• where filename is a string of characters

representing the name of the file to be opened.

U4.110

111 of 152

Open a file Cont..

  • Mode is a combination of the following flags:

ios::in Open file for reading

ios::out Open file for writing

ios::ate Initial position: end of file

ios::app Every output is appended at the end of file.

ios::trunc If the file already existed it is erased.

ios::binary Binary mode

  • Flags can be combined using bitwise operator OR: | .

ofstreamfile;

file.open ("example.bin", ios::out | ios::app | ios::binary);

U4.111

112 of 152

Open a file (Cont..)

Member functions open of classes

ofstream, ifstream and fstream include a

default mode.

Class Default Mode to Parameter

Ofstream ios::out | ios::trunc

Ifstream ios::in

Fstream ios::in | ios::out

U4.112

113 of 152

Open a file (Cont..)

  • Include a constructor that directly calls the open member functions and has the same parameters as
  • ofstream file(“example.bin”, ios::out| ios::app| ios::binary

  • Check if a file has been correctly opened by calling the member function is_open() :
  • bool is_open();
  • Indicating true in case that indeed the object has been correctly associated with an open file or false otherwise.

U4.113

114 of 152

Closing a File

  • Call the member function close().
  • Has the function of flushing the buffers and closing the file. Its form is quite simple:

void close();

  • Once this member function is called, the stream object can be used to open another file and the file is available again to be opened by other processes.
  • In case that an object is destructed while still associated with an open file, the destructor automatically calls the member function close.

U4.114

115 of 152

Text Mode Files

Use the same members of these classes that we used in communication with the console.

// writing on a text file

#include <fstream.h>

int main () {

ofstream examplefile ("example.txt");

if (examplefile.is_open())

{examplefile << "This is a line.\n";

examplefile << "This is another line.\n";

examplefile.close();

}

return 0;}

U4.115

116 of 152

eof() Inherits from Class ios

// Reading a text file

#include <iostream.h>

#include <fstream.h>

#include <stdlib .h>

int main () {

char buffer[256];

ifstream examplefile ("example.txt");

if (! examplefile.is_open())

{ cout << "Error opening file";

exit (1); }

while (! examplefile.eof () )

{ examplefile.getline (buffer,100);

cout << buffer << endl; }

return 0;

}

U4.116

117 of 152

get and put Stream Pointers

All i/o streams objects have, at least, one stream

pointer:

ifstream, has a pointer known as get pointer that points to the next element to be read.

ofstream, has a pointer put pointer that points tot he location where the next element has to be written.

• Finally fstream, inherits both: get and put.

• These stream pointers that point to the reading or writing locations within a stream can be read and/or manipulated using the following member

functions:

U4.117

118 of 152

Functions for get & put pointers

tellg() and tellp()

These two member functions admit no parameters and

return the current position of get stream pointer (in case

of tellg) or put stream pointer (in case of tellp).

• seekg() andseekp()

1. To change the position of stream pointers get and put. Both functions are overloaded with two different

prototypes:

seekg ( pos_type position );

seekp ( pos_type position );

The stream pointer is changed to an absolute position

from the beginning of the file.

U4.118

119 of 152

Functions for get & put pointers Cont..

seekg ( off_type offset, seekdir direction );

seekp( off_type offset, seekdir direction );

• Using this prototype, an offset from a concrete

point determined by parameter direction can be

specified. It can be:

ios::beg offset specified from the beginning of the stream.

ios::cur offset specified from the current position of the stream pointer.

ios::end offset specified from the end of the stream.

U4.119

120 of 152

Obtaining File Size

#include <iostream.h>

#include <fstream.h>

const char * filename = "example.txt";

int main () {

long l,m;

ifstream file (filename, ios::in | ios::binary);

l = file.tellg();

file.seekg (0, ios::end);

m = file.tellg();

file.close();

cout << "size of " << filename;

cout << " is " << (m-l) << " bytes.\n";

return 0; }

U4.120

121 of 152

Binary Files

  • Use read & write functions of istream and ostream class respectively for input output.
  • Object of class fstream have both. Their prototypes are:

write (char *buffer, streamsize size);

read (char *buffer, streamsize size);

  • Buffer is the address of a memory block where the read data are stored or from where the data to be written are taken. The size parameter is an integer value that specifies the number of characters to be read/written from/to the buffer.

U4.121

122 of 152

Reading Writing Binary File

const char *filename=“example.txt”;

int main() {

char *buffer;

long size;

ifstream file (filename, ios::in | ios::binary | ios::ate);

size = file.tellg();

file.seekg(0, ios::beg);

buffer = new char [size];

U4.122

123 of 152

Reading Writing Binary File

file.read (buffer, size);

file.close();

cout<<“the complete file is in buffer”;

ofstream file1 (“test1.txt”, ios::out | ios :: binary);

file1.write (buffer, size);

delete[] buffer;

return 0; }

U4.123

124 of 152

get() and put()

To read and write data

istream& get(char &ch)

ostream& put(char& ch)

while (in.get(ch))

cout<<ch;

for(i=0; i<256;i++)

out.put((char)i);

U4.124

125 of 152

Conclusion

  • The C++ I/O system contain classes such as ifstream, ofstream and fstream to deal with file handling.
  • These classes are derived from fstreambase class and are declared in a header file iostream.
  • The fstream class does not provide a mode by default and therefore we must provide the mode explicitly.
  • The class ios supports many member functions for managing many errors during file operations.

U4.125

126 of 152

Exceptional Handling

U4.126

127 of 152

Learning Objectives

  • Errors and Exceptions
  • Throwing mechanisms
  • Multiple Catching
  • Rethrowing exceptions
  • Exception handling mechanism
  • Catching all exceptions
  • Restricting exceptions thrown

U4.127

128 of 152

Exception Handling

  • Exceptions are of two kinds, namely, synchronous exceptions and asynchronous exceptions.
  • Errors such as "out-of-range index" and "over-flow" belong to the synchronous type exceptions.
  • The errors that are caused by events beyond the control of the program (such as keyboard interrupts) are called asynchronous exceptions.
  • The proposed exception handling mechanism in C++ is designed to handle only synchronous exceptions.

U4.128

129 of 152

Exception Handling

  • The purpose of the exception handling mechanism is to provide means to detect and report an exceptional circumstance or condition, so that appropriate action can be taken against it. The mechanism suggests a separate error handling code that performs the following tasks:
  • Find the problem (Hit on the exception).
  • Inform that an error has occurred (Throw the exception).
  • Receive the error information (Catch the exception).
  • Take corrective actions (Handle the exception).
  • The error handling code basically consists of two segments; one to detect errors and to throw exceptions, and the other to catch the exceptions and to take appropriate action.

U4.129

130 of 152

Exception Handling Mechanisms

  • C++ exception handling mechanism is basically built upon three keywords, namely, try , throw, and catch .
  • The keyword try is used to preface a block of statements (surrounded by braces) which may generate exceptions. This block of statements is known as try block.
  • When an exception is detected, it is thrown using a throw statement in the try block.
  • Catch blocks defined by the keyword catch, 'catches' the exception 'thrown' by the throw statement in the try block, and handles it appropriately.

U4.130

131 of 152

The catch block that catches an exception must immediately follow the try block that throws the exception.

Exception Handling Mechanisms

U4.131

132 of 152

The general form of these two blocks is as follows:

  1. When a try block throws an exception, the program control leaves the try block and enters the catch statement of the catch block. Note that exceptions are objects used to transmit information about a problem.
  2. If the type of object thrown matches the argument- type in the catch statement, then catch block is executed for handling the exception.
  3. If it does not match, the program is aborted with the help of the abort() function which is invoked by default.
  4. When no exception is detected and thrown, the control goes to the statement immediately after the catch block, i.e., the catch block is skipped.

U4.132

133 of 152

Throw Mechanism

  • When an exception, which is desired to be handled, is detected, it is thrown using the throw statement. It can be used in any one of the following form:
  • throw(exception) ;
  • throw exception ;
  • throw ; // used for re-throwing an exception

U4.133

134 of 152

Throw Mechanism

  • The object passed to the throw statement may be of any type, including constants.
  • It is also possible to throw objects not intended for error handling. When an exception is thrown, it will be caught by the catch statement associated with the try block, i.e., the control exits the current try block, and is transferred to the catch block.
  • The throw point can be in a deeply nested scope within a try block or in a deeply nested function call. In any case, control is transferred to the catch statement.

U4.134

135 of 152

Catch Mechanism

  • The code for handling exceptions is included in a catch block. A catch block looks like a function definition and is of the following form:

  • The type indicates the type of exception that a catch block handles. The parameter argument is the parameter’s name. Note that, the exception-handling code is placed between the two braces.
  • The catch statement catches an exception whose type matches with the type of catch argument. When it is caught, the code in the catch block is executed.

U4.135

136 of 152

Catch Mechanism

  1. When it is caught, the code in the catch block is executed.
  2. If the parameter in the catch definition is given a name, then the parameter can be used in the exception handling code. After executing the handler, the control goes to the statement immediately following the catch block.
  3. Due to a mismatch, if an exception is not caught, an abnormal program termination may occur. It is important to note that the catch block is simply skipped if the catch statement does not catch the exception.

U4.136

137 of 152

Multiple Catch Statements

  • Sometimes, it happens that a program segment has more than one condition to throw an exception.
  • In such a situation, we can associate more than one catch statement with a try, as shown here :

U4.137

138 of 152

Multiple Catch Statements

  • When an exception is thrown, the exception handlers are searched in order for an appropriate match.
  • The first handler that yields a match is executed.
  • After executing the handler, the control goes to the first statement after the last catch block for that try (i.e., all other handlers are bypassed).
  • When no match is found, the program is terminated.

U4.138

139 of 152

Example : Program to illustrate multiple catch statements execution

U4.139

140 of 152

Multiple Catch Execution

  • The program when executed first, invokes the function test() with x = 1 and therefore throws x as an int exception. This matches the type of the parameter m in catch2 and therefore catch2 handler is executed.
  • Immediately after the execution, the function test() is again invoked with x = 0. This time, the function throws 'x', a character type exception and therefore the first handler is executed.
  • Finally, the handler catch3 is executed when a double type exception is thrown. Note that every time only the handler which catches the exception is executed and all other handlers are bypassed.
  • When the try block does not throw any exception and when it completes normal execution, the control passes to the first statement after the last catch handler associated with that try bock.

U4.140

141 of 152

Re-throwing an Exception

  • A handler may decide to re-throw an exception caught without processing it. In such situations, we may simply invoke throw without any arguments as shown below:

throw;

  • This causes the current exception to be thrown to the next enclosing try/catch sequence and is caught by a catch statement listed after that enclosing try block. The following program demonstrates how an exception is re-thrown and caught.

U4.141

142 of 152

Program to illustrate re-throwing of exception

U4.142

143 of 152

Re-throwing an Exception

  • When an exception is re-thrown, it will not be caught by the same catch statement or any other catch in that group. Rather, it will be caught by an appropriate catch in the outer try/ catch sequence only.
  • A catch handler itself may detect and throw an exception. Here again, the exception thrown will not be caught by any catch statements in that group. It will be passed on to the next outer try/catch sequence for processing.

U4.143

144 of 152

Exception Specification

  • It is possible to restrict a function to throw only certain specified exceptions. This is achieved by adding a throw list clause to the function definition. The general form of using an exception specification is:

U4.144

145 of 152

Exception Specification

  • The type-list specifies the type of exceptions that may be thrown by the function.
  • Throwing any other type of exception will cause abnormal program termination.
  • If we wish to prevent a function from throwing any exception, we may do so by making the type-list empty. That is, we must use,

U4.145

146 of 152

Conclusion

  • Exceptions are of two types: synchronous and asynchronous. C++ provides mechanism for handling synchronous exceptions.
  • An exception is typically caused by a faulty statement in a try block. The statement discovers the error and throws it which is caught by a catch statement.
  • When an exception is not caught, the program is aborted.
  • It is also possible to make a catch statement to catch all types of exceptions using ellipses as its arguments.

U4.146

147 of 152

Review Questions [Objective Types]

  1. Assume a class D is privately derived from class B type of members can an object of class D locate in main() access?
  2. When does an ambiguity occur in multiple inheritance?
  3. If a base class and a derived class each include a member function with the same name, the member function of the derived class will be called by an object of the derived class. State true or false.
  4. Is it illegal to make objects of one class as members of another class?
  5. How abstract class is related to pure virtual function?
  6. Is it legal to create a pointer of an abstract base class?

U4.147

148 of 152

Review Questions [Short Answer Types]

  1. When should one derive a class publicly or privately?
  2. How does inheritance influence the working of constructors and destructors?
  3. Class Y has been derived from class X. The class Y does not contain any data member of its own. Does the class Y require constructor? If yes, why?
  4. What is containership? How does it different from inheritance?
  5. Is constructor overloading different from ordinary function overloading? How? Can you overload a destructor?

U4.148

149 of 152

Review Questions [Short Answer Types]

  1. What does the term disambiguation suggest?
  2. What are virtual base class? When should they be used?
  3. What is object slicing? Give example from a C++ program
  4. Is it necessary that the virtual function overridden in the derived class must have the same signature?
  5. A function template have multiple argument types.. Discuss with example.

U4.149

150 of 152

Review Questions [Long Answer Types]

  1. What is visibility mode? What are the different visibility mode supported by C++?
  2. What are the different form of inheritance? Explain with an example.
  3. List the operators that can not be overloaded and justify why they can not be overloaded?
  4. Write a program to overload unary operator, say ++ for incrementing distance in FPS system. Describe the working model of an overloaded operator with the same program.

U4.150

151 of 152

Review Questions [Long Answer Types]

  1. Explain the syntax of binary operator overloading. How many arguments are required in the definition of an overloaded binary operator?
  2. Suggest and implement a program to trace memory leakage.
  3. What is runtime dispatching? Explain with examples how C++ handle run time dispatching?
  4. What are the virtual destructors? How do they differ from normal destructors? Can constructors be declared as virtual constructors? Give reasons.

U4.151

152 of 152

Review Questions [Long Answer Types]

  1. A function template can be overloaded. Write a program in C++ to support the view.
  2. Can we distribute function template and class templates in object libraries?

U4.152