0% found this document useful (0 votes)
66 views

Unit 3

hi

Uploaded by

karunakar
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
66 views

Unit 3

hi

Uploaded by

karunakar
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 21

Chapter 3

Inheritance
It is the process by which object of one class acquires the properties of object of another class. The class
from which properties are inherited is called base class and the class to which properties are inherited is
called derived class. Inheritance can be broadly classified into:

Single Inheritance
Multiple Inheritance
Multilevel Inheritance
Hierarchical Inheritance
Hybrid Inheritance

Base-Class Access Control


When a class inherits another, the members of the base class become members of the derived class.
Class inheritance uses this general form:

class derived-class-name : access base-class-name


{
// body of class
};

The access status of the base-class members inside the derived class is determined by access. The base-
class access specifier must be either public, private, or protected. If no access specifier is present, the
access specifier is private by default if the derived class is a class. If the derived class is a struct, then
public is the default in the absence of an explicit access specifier.

When the access specifier for a base class is public, all public members of the base become
public members of the derived class, and all protected members of the base become protected
members of the derived class.

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.

When a base class' access specifier is protected, public and protected members of the base
become protected members of the derived class.

In all cases, the base's private elements remain private to the base and are not accessible by members
of the derived class.
Single Inheritance

In a single inheritance the derived class is derived from a single base class.
A

(Single inheritance)

Program 4.1 Example of single inheritance with base class access control as public.

Solution:
#include <iostream.h>
class A
{
int i, j;
public:
void set(int a, int b)
{
i=a; j=b;
}
void show()
{
cout << i << " " << j << "\n";
}
};
class B : public A
{
int k;
public:
B(int x)
{
k=x;
}
void showk()
{
cout << k << "\n";
}
};
void main()
{
B b(3);
b.set(1, 2);
b.show();
b.showk();
}

Output:
12
3

Note: Here all public and protected members of the base class become private members of the derived
class. So object of derived class cannot directly access the member function and data members of the
base class.
Program 4.2
Example of single inheritance with base class access control as private.
Solution:

#include <iostream.h>
class A
{
int i, j;
public:
void set(int a, int b)
{
i=a; j=b;
}
void show()
{
cout << i << " " << j << "\n";
}
};

class B : private A
{
int k;
public:

B(int x)
{
k=x;
}
void showk()
{
cout << k << "\n";
}
};

void main()
{
B b(3);
b.set(1, 2);
b.show(); //******Error******
}

How to access the private data member of base class in derived class?
Private data members of base class can be accessed by derived class by using public member
function/methods of the base class.

Multiple Inheritance

In multiple inheritance derived class is derived from more than one base class.

A B C

(Multiple Inheritance)

Multilevel Inheritance

In multilevel inheritance class B is derived from a class A and a class C is derived from the class B.

Syntax:
class base-class-name1
{
Data members
Member functions
};

class derived-class-name : visibility mode base-class-name


{

Data members
Member functions
};

class derived-class-name1: visibility mode derived-class-


name {
Data members
Member functions
};

Note: visibility mode can be either private, public or protected

(Multilevel inheritance)

Hierarchical Inheritance

In hierarchical inheritance several classes can be derived from a single base class

Syntax:
class base-class-name
{
Data members
Member functions
};

class derived-class-name1 : visibility mode base-class-


name {

Data members
Member functions

};
class derived-class-name2: visibility mode base-class-name
{
Data members
Member functions
};

Note: visibility mode can be either private, public or protected

B C D

(Hierarchical inheritance)

Hybrid inheritance

It is the mixture of one or more above inheritance.

B
C

Constructor and Destructor Execution in Inheritance


When an object of a derived class is created, if the base class contains a constructor, it will be called
first, followed by the derived class' constructor. When a derived object is destroyed, its destructor is
called first, followed by the base class' destructor, if it exists (i.e. constructor functions are executed in
their order of derivation. Destructor functions are executed in reverse order of derivation).
Program 4.4 Constructor and Destructor execution in single inheritance.

Solution:
#include <iostream.h>
class base
{
public:
base()
{
cout << "Constructing base\n";
}
~base()
{
cout << "Destructing base\n";
}
};
class derived: public base
{
public:
derived()
{
cout << "Constructing derived\n";
}
~derived()
{
cout << "Destructing derived\n";
}
};
void main()
{
derived ob;
}

Output:
Constructing base
Constructing derived
Destructing derived
Destructing base

Note: In the above program, first base's constructor is executed followed by derived's. Next (because ob
is immediately destroyed in this program), derived's destructor is called, followed by base's.
Program 4.5 Constructor and Destructor execution in multilevel linheritance.

Solution:
#include <iostream.h>
class base
{
public:
base()
{
cout << "Constructing base\n";
}
~base()
{
cout << "Destructing base\n";
}
};
class derived1 : public base
{
public:
derived1()
{
cout << "Constructing derived1\n";
}
~derived1()
{
cout << "Destructing derived1\n";
}
};
class derived2: public derived1
{
public:
derived2()
{
cout << "Constructing derived2\n";
}
~derived2()
{
cout << "Destructing derived2\n";
}
};
void main()
{
derived2 ob;
}

Output:
Constructing base
Constructing derived1
Constructing derived2
Destructing derived2
Destructing derived1
Destructing base

Program 4.6 Constructor and Destructor execution in multiple inheritance.

Solution:
#include <iostream.h>
class base1
{
public:
base1()
{
cout << "Constructing base1\n";
}
~base1()
{
cout << "Destructing base1\n";
}
};
class base2
{
public:
base2()
{
cout << "Constructing base2\n";
}
~base2()
{
cout << "Destructing base2\n";
}
};
class derived: public base1, public base2
{
public:
derived()
{
cout << "Constructing derived\n";
}
~derived()
{
cout << "Destructing derived\n";
}
};
void main()
{
derived ob;
}

Output:
Constructing base1
Constructing base2
Constructing derived
Destructing derived
Destructing base2
Destructing base1

Note: In the above program, constructors are called in order of derivation, left to right, as specified in
derived's inheritance list. Destructors are called in reverse order, right to left.

Passing Parameters to Base-Class Constructors


So far, none of the preceding examples have included constructor functions that require arguments. In
cases where only the derived class' constructor requires one or more parameters, we simply use the
standard parameterized constructor syntax. However, how do you pass arguments to a constructor in a
base class? The answer is to use an expanded form of the derived class's constructor declaration that
passes along arguments to one or more base-class constructors. The general form of this expanded
derived-class constructor declaration is shown here:

derived-constructor (arg-list) : base1(arg-list),base2(arg-list), …...,baseN(arg-list)


{
// body of derived constructor
}

Here, base1 through baseN are the names of the base classes inherited by the derived class. Notice that
a colon separates the derived class' constructor declaration from the base-class specifications, and that
the base-class specifications are separated from each other by commas, in the case of multiple base
classes.
Program 4.7 Passing Parameters to Base Class Constructors in Single Inheritance.

Solution:
#include <iostream.h>
class base
{
protected:
int i;
public:
base(int x)
{
i=x; cout << "Constructing base\n";
}
~base()
{
cout << "Destructing base\n";
}
};
class derived: public base
{
int j;
public:
derived(int x, int y): base(y)
{
j=x; cout << "Constructing derived\n";
}
~derived()
{
cout << "Destructing derived\n";
}
void show()
{
cout << i << " " << j << "\n";
}
};
void main()
{
derived ob(3, 4);
ob.show();
}
Virtual Base Classes
An element of ambiguity can be introduced into a C++ program when multiple base classes are
inherited. For example, consider this incorrect program:

What is Multipath Inheritance?


Multipath Inheritance is a hybrid inheritance (also called as Virtual Inheritance). It is combination of
hierarchical inheritance and multiple inheritance.

In Multipath Inheritance there is a one base class GRANDPARENT. Two derived class PARENT1 and
PARENT2 which are inherited from GRANDPARENT. Third Derived class CHILD which is inherited from
both PARENT1 and PARENT2.

Problem in Multipath Inheritance


There is an ambiguity problem. When we run program with such type inheritance, it gives a compile
time error [Ambiguity]. If we see the structure of Multipath Inheritance then we find that there is shape
like Diamond.

GRAND PARENT

int i

PARENT1 PARENT 2

int j int i int k int i


CHILD

int j int k int I int i(Duplicate Copies of int i)

[Ambiguity in Multipath Inheritance]

Why Ambiguity Problem in multipath (Virtual) Inheritance?


Suppose GRANDPARENT has a data member int i. PARENT1 has a data member int j. Another
PARENT2 has a data member int k. CHILD class which is inherited from PARENT1 and PARENT2.
CHILD class have data member:
int j ( one copy of data member PARENT1)
int k ( one copy of data member PARENT2)
int i(two copy of data member GRANDPARENT)
This is ambiguity problem. In CHILD class have two copies of Base class. There are two duplicate copies
of int i of base class. One copy through PARENT1 and another copy from PARENT2. This problem is
also called as DIAMOND Problem.

Program 4.7
Demonstration of ambiguities in multipath inheritance.

Solution:
/ This program contains an error and will not compile.
#include <iostream.h>
class base
{
public:
int i;
};
class derived1 : public base
{
public:
int j;
};
class derived2 : public base
{
public:
int k;
};
class derived3 : public derived1, public derived2
{
public:
int sum;
};
void main()
{
derived3 ob;
ob.i = 10; // this is ambiguous, which i???
ob.j = 20;
ob.k = 30;
ob.sum = ob.i + ob.j + ob.k; // i ambiguous here, too
cout << ob.i << " "; // also ambiguous, which i? cout
<< ob.j << " " << ob.k << " ";
cout << ob.sum;
}
As the comments in the program indicate, both derived1 and derived2 inherit base. However, derived3
inherits both derived1 and derived2. This means that there are two copies of base present in an object
of type derived3. Therefore, in an expression like
ob.i = 10; which i is being referred to, the one in derived1 or the one in derived2? Because there are two
copies of base present in object ob, there are two ob.is! As we can see, the statement is inherently
ambiguous.
There are two ways to remedy the preceding program. The first is to apply the scope resolution
operator to i and manually select one i. The second is to use virtual base class.

Remove Ambiguities using scope resolution operator:


In Program 4.7, the ambiguous statements

ob.i = 10;
ob.sum = ob.i + ob.j + ob.k;
cout << ob.i << " "; will be replaced by

ob.derived1::i = 10;
ob.sum = ob. derived1::i + ob.j + ob.k;
cout << ob. derived1::i << " "; respectively

As we can see, because the :: was applied, the program has manually selected derived1's version of
base. However, this solution raises a deeper issue: What if only one copy of base is actually required? Is
there some way to prevent two copies from being included in derived3? The answer, as you probably
have guessed, is yes. This solution is achieved using virtual base classes.

Remove Ambiguities using virtual base class:


When two or more objects are derived from a common base class, we can prevent multiple copies of
the base class from being present in an object derived from those objects by declaring the base class as
virtual when it is inherited. We accomplish this by preceding the base class' name with the keyword
virtual when it is inherited. For example, here is another version of the example program in which
derived3 contains only one copy of base:

Program 4.8
Remove Ambiguities using virtual base class.

Solution:
#include <iostream.h>
class base
{
public:
int i;
};
class derived1 : virtual public base
{
public:
int j;
};
class derived2 : virtual public base
{
public:
int k;
};
class derived3 : public derived1, public derived2
{
public:
int sum;
};
void main()
{
derived3 ob;
ob.i = 10; // now unambiguous

ob.j = 20;
ob.k = 30;
ob.sum = ob.i + ob.j + ob.k; // unambiguous
cout << ob.i << " "; // unambiguous
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
}

As we can see, the keyword virtual precedes the rest of the inherited class specification. Now that both
derived1 and derived2 have inherited base as virtual, any multiple inheritance involving them will cause
only one copy of base to be present. Therefore, in derived3, there is only one copy of base and ob.i = 10
is perfectly valid and unambiguous.
Virtual destructor
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. Destructors are distinguished by the tilde, the ‘~’ that appears in
front of the destructor name. In order to define a virtual destructor, all you have
to do is simply add the keyword “virtual” before the tilde symbol.
The need for virtual destructors in C++ is best illustrated by some examples.
Let’s start by going through an example that does not use virtual destructors,
and then we will go through an example that does use virtual destructors. Once
you see the difference, you will understand why virtual destructors are needed.
Take a look at the code below to start out:

Program 7.2 Example without a Virtual Destructor:


#include iostream.h
class Base
{
public:
Base(){ cout<<"Constructing Base";}
~Base(){ cout<<"Destroying Base";}
};

class Derive: public Base


{
public:
Derive(){ cout<<"Constructing Derive";}

~Derive(){ cout<<"Destroying Derive";}


};

void main(){
{
Base *basePtr = new Derive();
delete basePtr;
}

Output:
Constructing Base
Constructing Derive
Destroying Base
Note: Based on the output above, we can see that the constructors get called in
the appropriate orderwhen 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’. So, how
can we fix this problem?
Well, 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.
Program 7.3 Example with a Virtual Destructor:
So, the only thing we will need to change is the destructor in the Base class and here’s
what it will look
like – note that we highlighted the part of the code where the virtual keyword has been
added in bold:
class Base
{
public:
Base()
{
cout<<"Constructing Base";
}
virtual ~Base()
{
cout<<"Destroying Base";
}
};
Output:
Constructing Base
Constructing Derive
Destroying Derive
Destroying Base
Note: Here the derived class destructor will be called before the base class. So,
now you’ve seen whywe need virtual destructors and also how they work. One
important design paradigm of class design is that if a class has one or more
virtual functions, then that class should also have a virtual destructor.
Classify the various types of polymorphism. conver
o Polymorphism means "one interface, sion
routin
Polymorphism multiple implementations" es
o Polymorphism is either static or dynamic o If
o In static or compile-time polymorphism, it does
the function code to be executed for a not
Static Dynamic
function call is known in advance, i.e., the result
binding is done early during compilation. in a
o Function overloading and Operator unique
Function Operator Virtual overloading belong to early binding. match
o In dynamic or run-time polymorphism the then
Overload Overload Function ambig
binding of function to a call is deferred
until runtime, i.e., dynamic or late binding. uity
o Runtime polymorphism is achieved error
is
through virtual functions.
report
ed.

Explain function overloading or function polymorphism with an example


o C++ permits designing a family of functions with one
function name but with different argument lists is known as
function overloading or function polymorphism.
o The list should differ on type and count.
o When a call is made, the function to be invoked is
determined by the compiler after finding a unique match of
corresponding prototype.
o In case if there is no exact match for a function call then the
compiler tries to find a match by
o making integral promotions to actual arguments
(char to int, float to double) o using built-in

#include <iostream.h>
const float pi = 3.14;
int volume(int); // cube volume
int volume(int, int, // box volume
int); // cylinder volume
float volume(int, int);
int main()
{
cout <<"Cube volume : "<< volume(5) <<"\n";
cout <<"Box volume : "<< volume(9, 3, 4) <<"\n";
cout <<"Cylinder volume : "<< volume(5, 6) <<"\n";
return 0;
}
int volume(int a)
{
return (a*a*a);
}
int volume(int l, int b, int h)
{
return (l * b * h);
}
float volume(int r, int h)
{
return (pi * r * r * h);
}

You might also like