Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
61 views

Inheritance

The document discusses inheritance in C++. It defines inheritance as creating new classes from existing classes, known as base classes. The derived class inherits all properties and methods from the base class but can add its own properties. There are different types of inheritance including single, multiple, multilevel, and hybrid inheritance. Access specifiers like public and private determine which members are accessible from derived classes. Constructors can be used to pass arguments to base class constructors from derived class constructors.

Uploaded by

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

Inheritance

The document discusses inheritance in C++. It defines inheritance as creating new classes from existing classes, known as base classes. The derived class inherits all properties and methods from the base class but can add its own properties. There are different types of inheritance including single, multiple, multilevel, and hybrid inheritance. Access specifiers like public and private determine which members are accessible from derived classes. Constructors can be used to pass arguments to base class constructors from derived class constructors.

Uploaded by

Dhanraj Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 77

Inheritance

Module II
Inheritance
• Inheritance is the process of creating new classes from existing
classes.
• Base class
• The existing class from which new classes derived.
• Derived class
• Class that inherits data members and member functions from a previously
defined base class
• The derived class inherits all the capabilities of the base class but can
add properties of its own.
• The base class is unchanged by this process.
Inheritance

• The derived class inherit the


feature of base class (A,B,C)
and add its own feature D.
• The arrow from derived class
to base class represents that
the derived class access
features of base class and not
vice versa.
Access specifier without inheritance
Access specifier with inheritance
Access specifier with inheritance
Syntax for derived class
Visibility mode of derivation
Forms of Inheritance
Single Inheritance
• Derivation of a derived class
from a single base class is called
single inheritance.

class A{…..};
class B:public A
{….
……};
Multiple Inheritance
• Derivation of a class from
several classes(two or more)
known as multiple inheritance

class A{…..};
class B{…..};
class c:public A, private B
{….
……};
Hierarchical Inheritance
Derivation of several classes from a
single class

class A{…..};
class B:public A
{…..};
class c:public A
{….
……};
class D:public A
{….
……};
Multilevel inheritance
• Derivation of a class from
another derived class is known
as multilevel inheritance

class A{…..};
class B:public A
{….
……};
class c:public B
{….
……};
Hybrid Inheritance
• Derivation of a class involving
multiple forms of inheritance is
known as hybrid inheritance
class A{…..};
class B:public A
{….};
class C{……};

class D:public B, public C


{….};
Multipath Inheritance
• Derivation of a class from other
derived classes ,which are
derived from the same base class.
• An ambiguity can arise in this type
of inheritance
class A{…..};
class B:public A
{….};
class C:public A
{……};
class D:public B, public C
{….};
Single Inheritance //publicly-derived class
#include <iostream> class B : public A //publicly-derived class
using namespace std; {
class A //base class public:
{ int x;
private: void funct()
int privdataA; {
protected: int a;
int protdataA; a = privdataA; //error: not accessible
public: a = protdataA; //OK
int pubdataA; a = pubdataA; //OK
}; }
};
Single Inheritance
int main()
{
int a;
B objB;
A objA;
objA.x=20;
objB.x=25;
a = objA.privdataA; //error not accessible
a = objA.protdataA; //error: not accessible
a = objB.pubdataA; //OK (A public to B)
return 0;
}
Single Inheritance//privately-derived class
class C : private A //privately-derived class
{
public:
void funct()
{
int a;
a = privdataA; //error: not accessible
a = protdataA; //OK
a = pubdataA; //OK
}
};
Single Inheritance//privately-derived class
int main()
{
int a;
C objC;
a = objC.privdataA; //error: not accessible not inherited
a = objC.protdataA; //error: not accessible /private in derive
a = objC.pubdataA; //error: not accessible (A private to C)
return 0;
}
Single inheritance class Derived:public Base
class Base {
{ int total;
int x; public:
protected: void displaytotal()
int y; {
public: total=(getx()+y+z);
int z; cout<<"total: "<<total<<endl;
void getXYZ(int a, int b, int c) }
{ };
x=a; y=b; z=c;
}
int getx(){return x;}
void display()
{
cout<<"x: "<<x<<" y: "<<y<<" z:" <<z<<endl;
}
};
Single inheritance
int main() output
{ x: 10 y: 20 z:30
Derived objd1; d2; total: 60
objd1.getXYZ(10,20,30); x: 100 y: 200 z:300
objd1.display();
objd1.displaytotal();
Base objb1;
objb1.getXYZ(100,200,300);
objb1.display();
objb1.displaytotal(); // error
return 0;
}
Single inheritance with constructor and destructor
class base { Output
public: Constructing base
base() { cout << "Constructing base\n"; } Constructing derived
~base() { cout << "Destructing base\n"; } Destructing derived
}; Destructing base
class derived: public base {
public:
derived() { cout << "Constructing derived\n"; }
~derived() { cout << "Destructing derived\n"; }
};
int main()
{
derived ob;
// do nothing but construct and destruct ob
return 0;
}
Multilevel inheritance
#include <iostream>
using namespace std;
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"; }
};
output
class derived2: public derived1 {
public: Constructing base
derived2() { cout << "Constructing derived2\n"; } Constructing derived1
~derived2() { cout << "Destructing derived2\n"; } Constructing derived2
}; Destructing derived2
int main() Destructing derived1
{ Destructing base
derived2 ob;
// construct and destruct ob
return 0;
}
Multiple inheritance
#include <iostream> class derived: public base1, public base2 {
using namespace std; public:
class base1 { derived() { cout << "Constructing
public: derived\n"; }
base1() { cout << "Constructing base1\n"; } ~derived() { cout << "Destructing
derived\n"; }
~base1() { cout << "Destructing base1\n"; } };
}; int main()
class base2 { {
public: derived ob;
base2() { cout << "Constructing base2\n"; } // construct and destruct ob
~base2() { cout << "Destructing base2\n"; } return 0;
}; }
OUTPUT
Constructing base1
Constructing base2
Constructing derived
Destructing derived
Destructing base2
Destructing base1
Passing Parameters to Base-Class Constructors

• How to pass arguments to a derived-constructor(arg-list) :


constructor in a base class? base1(arg-list),
• The answer is to use an base2(arg-list),
expanded form of the derived // ...
class's constructor declaration
baseN(arg-list)
• that passes along arguments to
one or more base-class {
constructors. // body of derived constructor
}
Constructor Derived class constructor
class Base class Derived:public Base
{ {
int x; int total;
protected: public:
int y; Derived():Base() {
public: total=0;
int z; cout<<"default constructor of derived class
called"<<endl; }
Base() {
Derived(int x1,int y1, int z1):Base(x1,y1,z1)
cout<<"Base default constructor "<<endl; }
{
Base(int a, int b, int c)
total=x1+y1+z1;
{
cout<<"constructing Derived"<<endl;
x=a; y=b; z=c;
}
cout<<"constructing Base"<<endl;
void displaytotal()
}
{
};
cout<<"total: "<<total<<endl;
}
};
Single inheritance
int main() Output
{ Base default constructor
Derived objd1; default constructor of derived class
called
Derived d1(10,20,30);
constructing Base
d1.displaytotal();
constructing Derived
return 0;
total: 60
}
Constructor in Base and derived class without Default Constructor
class Base class Derived:public Base
{ {
protected: int total;
int x; public:
public: Derived(int x1,int y1)
int y; {
/* Base() { total=x1+y1;
x=0;y=0; cout<<"constructing Derived"<<endl;
cout<<"Base default constructor "<<endl; }
}*/
void displaytotal()
Base(int a, int b)
{
{
cout<<"total: "<<total<<endl;
x=a; y=b;
}
cout<<"constructing Base"<<endl;
};
}
};
The program gives Compilation Error
int main()
{
Derived objd1;//Error default constructor not available in Derived
Derived d1(10,20); //Error default constructor not available in Base

if default constructor is defined in the base


then compilation error won’t be there, but
total will be initialized to 0 as default value of Base.
d1.displaytotal();
return 0;
}
Output comes after un commenting following line
/* Base() {
x=0;y=0;
cout<<"Base default constructor "<<endl; }*/
Output:
Base default constructor
constructing Derived
total:0
Multilevel inheritance
class Base
{
int x;
protected:
int y;
public:
int z;
Base()
{
x=y=z=0;
cout<<"Base default constructor "<<endl;
}
Base(int a, int b, int c)
{
x=a; y=b; z=c;
cout<<"constructing Base"<<endl;
}
};
Multilevel inheritance
class Derived1:public Base
{
int m;
public:
int n;
Derived1():Base()
{
m=0; n=0;
cout<<"default constructor of derived1 class called"<<endl;
}
Derived1(int x1,int y1, int z1,int m1,int n1):Base(x1,y1,z1)
{
m=m1; n=n1;
cout<<"constructing Derived1"<<endl;
}
};
Multilevel inheritance
class Derived2:public Derived1{
int total;
public:
Derived2():Derived1() {
total=0;
cout<<"default constructor of derived2 class called"<<endl;
}
Derived2(int x1,int y1, int z1,int m1,int n1):Derived1(x1,y1,z1,m1,n1) {
total=x1+y1+z1+m1+n1;
cout<<"constructing Derived2"<<endl;
}
void displaytotal()
{
cout<<"total: "<<total<<endl;
}
};
Multilevel inheritance
int main() Output
{ Base default constructor
Derived2 objd1; default constructor of derived1
Derived2 d1(10,20,30,40,50); class called
d1.displaytotal(); default constructor of derived2
class called
return 0;
constructing Base
}
constructing Derived1
constructing Derived2
total: 150
Multiple Inheritance
class Base1 Base1(int a, int b, int c)
{ {
int x; x=a;
protected: y=b;
int y; z=c;
public: cout<<"constructing Base1"<<endl;
int z; }
Base1() };
{
x=y=z=0;
cout<<"Base1 default constructor
"<<endl;
}
Multiple Inheritance
class Base2 Base2(int m1,int n1)
{ {
int m; m=m1;
public: n=n1;
int n; cout<<"constructing
Base2() Base2"<<endl;
{ }
m=0;
n=0; };
cout<<“Base2 default constructor"<<endl;
}
Multiple Inheritance
class Derived: public Base1,public Base2{
int total;
public:
Derived():Base1(),Base2() {
total=0;
cout<<"default constructor of derived class called"<<endl;
}
Derived(int x1,int y1, int z1,int m1,int n1): Base1(x1,y1,z1),Base2(m1,n1) {
total=x1+y1+z1+m1+n1;
cout<<"constructing Derived2"<<endl;
}
void displaytotal() {
cout<<"total: "<<total<<endl;
}
};
Multiple Inheritance
int main() Base1 default constructor
{ default constructor of Base2 class
Derived objd1; called
Derived d1(10,20,30,40,50); default constructor of derived
class called
d1.displaytotal();
constructing Base1
return 0;
constructing Base2
}
constructing Derived2
total: 150
Granting Access
• When a base class is inherited • An access declaration takes this
as private, all public and general form:
protected members of that base-class::member;
class become private members
of the derived class. • The access declaration is put
under the appropriate access
• However, in certain heading in the derived class'
circumstances, you may want to
restore one or more inherited • declaration.
members to their original • Notice that no type declaration
access specification. is required (or, indeed, allowed)
in an access declaration.
Granting Access
class base {
int a;
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
base::a;//error
..
};
Virtual Base Classes
// This program contains an error and will not
compile.
#include <iostream>
using namespace std;
class A {
public:
int i;
};
class B : public A {
public: class D: public B, public C {
int j;
public:
};
class C : public A { int sum;
public: };
int k;
};
• Both B and C inherit A.
Multipath Inheritance • However, D inherits both B and C.
D ob; • This means that there are two copies
of A present in an object of type D.
ob.i = 10; // this is ambiguous, which i???• Therefore, in an expression like
ob.j = 20; ob.i = 10;
ob.k = 30; • which i is being referred to, the one
// i ambiguous here, too in B or the one in C? Because there
ob.sum = ob.i + ob.j + ob.k; are two copies of A present in object
ob, there are two ob.is! As you can
// also ambiguous, which i? see, the statement is inherently
cout << ob.i << " "; ambiguous.
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
• There are two ways to remedy the preceding int main()
program. {
• The first is to apply the scope resolution
operator to i and manually select one i. D ob;
ob.B::i = 10; // scope resolved, use B's i
ob.j = 20;
ob.k = 30;
// scope resolved
ob.sum = ob.B::i + ob.j + ob.k;
// also resolved here
cout << ob.B::i << " ";
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
Virtual Base Classes
• When two or more objects are derived from a common base class,
you 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.
• You 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 D contains only one copy of base A:
class D: public B, public C {
Virtual Base public:
int sum;
#include <iostream> };
using namespace std; int main()
class A { {
public: D ob;
int i; ob.i = 10; // now unambiguous
}; ob.j = 20;
class B : virtual public A { ob.k = 30;
public: // unambiguous
int j; ob.sum = ob.i + ob.j + ob.k;
}; // unambiguous
class C : virtual public A { cout << ob.i << " ";
public: cout << ob.j << " " << ob.k << " ";
int k; cout << ob.sum;
}; return 0;
}
Virtual Base
#include <iostream> class C : virtual public A {
using namespace std; public:
class A { int k,i=300;
public: C() { cout << "Constructing c\n"; }
int i=100; ~C() { cout << "Destructing c\n"; }
A() { cout << "Constructing A\n"; }
~A() { cout << "Destructing A\n"; } };

}; class D: public B, public C {


class B : virtual public A { public:
public: int sum;
int j,i=200; D() { cout << "Constructing D\n"; }
B() { cout << "Constructing B\n"; } ~D() { cout << "Destructing D\n"; }
~B() { cout << "Destructing B\n"; }
};
};
Virtual Base
int main() Constructing A
{ Constructing B
D ob; Constructing c
ob.A::i = 10; // unambiguous Constructing D
ob.j = 20; 10 20 30 60
ob.k = 30; Destructing D
// unambiguous Destructing c
ob.sum = ob.C::i + ob.j + ob.k; Destructing B
// unambiguous Destructing A
cout << ob.i << " ";
cout << ob.j << " " << ob.k << " ";
cout << ob.sum;
return 0;
}
Virtual base constructor executes first
class D: public B, virtual public C Constructing A
{ Constructing c
public: Constructing B
int sum; Constructing D
D() { cout << "Constructing 10 20 30 60
D\n"; }
Destructing D
~D() { cout << "Destructing
D\n"; Destructing B
}; Destructing c
Destructing A
Virtual Functions
Runtime Polymorphism
Polymorphism
• Polymorphism is one of the important feature of OOP
• Means one name , multiple forms.
• It allows the object to behave differently in different conditions.
• In C++ we have two types of polymorphism:
1) Compile time Polymorphism – This is also known as static (or
early) binding.
2) Runtime Polymorphism – This is also known as dynamic (or late)
binding.
Types of Polymorphism
Compile time Polymorphism
• Implemented using function overloading and operator overloading
• During overloaded member function , the information regarding
matching arguments and number of arguments is known to the
compiler at the compile time
• The compiler is able to select the appropriate function for a
particular call at the compile time itself
• This is called early binding, or static binding or static linking and
mainly known as Compile time Polymorphism
• Object is bound to its function call at compile time
Runtime Polymorphism
• Function overriding is an example of Runtime polymorphism.
• Function Overriding:
• When child class declares a method, which is already present in the parent
class then this is called function overriding, here child class overrides the
parent class.
• In case of function overriding we have two definitions of the same
function, one is parent class and one in child class.
• The call to the function is determined at runtime to decide which
definition of the function is to be called, that is the reason it is called
runtime polymorphism.
Normal member functions access with pointers
#include <iostream>
using namespace std; int main()
class Base { //base class {
public: Derv1 dv1; //object of derived class 1
void show() //normal function Derv2 dv2; //object of derived class 2
{ cout << “Base\n”; } Base* ptr; //pointer to base class
}; ptr = &dv1; //put address of dv1 in pointer
class Derv1 : public Base { //derived class 1 ptr->show(); //execute show()
public: ptr->f1();;//error
void show() ptr = &dv2; //put address of dv2 in pointer
{ cout << “Derv1\n”; } ptr->show(); //execute show()
void f1(){cout<<“f1”;} return 0;
}; }
class Derv2 : public Base { //derived class 2 Note: base class pointer is type compatible with
derived class pointer
public:
void show()
{ cout << “Derv2\n”; }
};
Normal member functions access with pointers
ptr->show();
Which of the show()functions is
called here? The output from the
program answers these
questions:
Base
Base
• the function in the base class is
always executed.
• The compiler ignores the contents
of the pointer ptr and chooses the
member function that matches
the type of the pointer, as shown
in Figure
Base and Derived class pointer
Typecasting of Pointer
Base* ptr,b1; //pointer to base class
ptr = &dv1; //put address of dv1 in pointer
upcast—implicit type cast allowed
ptr->show(); //execute show() of Base class
((Derv1*)ptr)-> show() //execute show() of Derv1 class
Derv1 *p=&b1; // Error Derived class pointer can’t point to Base class object
Derv1 *p= (Derv1 *)&b1 // downcast—explicit type cast required not safe
void display()
{ cout << “Derv1 own function\n”; }
ptr->display(); //error not derived from base so base class pointer can not access.
((Derv1*)ptr)-> display()// will work
Derv1 *p1=new Derv1();
((Base *)p1)->show();
Pointer
virtual function
• Virtual means existing in appearance but not in reality.
• When virtual functions are used, a program that appears to be calling
a function of one class may in reality be calling a function of a
different class.
• 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.
Virtual Function
virtual function access with pointers
#include <iostream>
using namespace std; int main()
class Base { //base class {
public: Derv1 dv1; //object of derived class 1
virtual void show() //virtual function Derv2 dv2; //object of derived class 2
{ cout << “Base\n”; } Base* ptr=new Base(); //pointer to base class
}; Base b1;
class Derv1 : public Base { //derived class 1 Ptr=&b1;
public: ptr->show();//Base
void show() ptr = &dv1; //put address of dv1 in pointer
{ cout << “Derv1\n”; } ptr->show(); //execute show()
}; ptr = &dv2; //put address of dv2 in pointer
class Derv2 : public Base { //derived class 2 ptr->show(); //execute show()
public: return 0;
void show() }
{ cout << “Derv2\n”; } Shape *ptr[10];
}; ptr[i]->draw();//for loop
virtual function
• The output of this program is
Derv1
Derv2
• the member functions of the derived
classes, not the base class, are executed.
• When the contents of ptr changed from
the address of Derv1to that of Derv2,
and the particular instance of show()that
is executed also changes.
• So the same function call
ptr->show();
• executes different functions, depending
on the contents of ptr.
• The rule is that the compiler selects the
function based on the contents of the
pointer ptr, not on the type of the
pointer, as in previous prg.
Late Binding
• How the compiler knows what function to compile.
• In case of normal member function the compiler has no problem with the
expression ptr->show();
• It always compiles a call to the show()function in the base class.
• But in case of virtual function the compiler doesn’t know what class the
contents of ptr may contain.
• It could be the address of an object of the Derv1class or of the Derv2class.
• Which version of show()does the compiler call?
• In fact the compiler doesn’t know what to do, so it arranges for the decision
to be deferred until the program is running.
• At runtime, when it is known what class is pointed to by ptr, the appropriate
version of will show is called. This is called late binding or dynamic binding.
• (Choosing functions in the normal way, during compilation, is called early
binding or static binding.)
• Late binding requires some overhead but provides increased power and
flexibility.
How Virtual Functions Work
• The usual way compilers handle virtual functions is to add a hidden member to each object.
• The hidden member holds a pointer to an array of function addresses. Such an array is usually termed a virtual function
table (vtbl).
• The vtbl holds the addresses of the virtual functions declared for objects of that class.
• For example, an object of a base class contains a pointer to a table of addresses of all the virtual functions for that class.
• An object of a derived class contains a pointer to a separate table of addresses.
• If the derived class provides a new definition of a virtual function, the vtbl holds the address of the new function.
• If the derived class doesn’t redefine the virtual function, the vtbl holds the address of the original version of the function.
• If the derived class defines a new function and makes it virtual, its address is added to the vtbl .
• Note that whether you define 1 or 10 virtual functions for a class, you add just one address member to an object; it’s the
table size that varies.
• When you call a virtual function, the program looks at the vtbl address stored in an object and goes to the corresponding
table of function addresses.
• If you use the first virtual function defined in the class declaration, the program uses the first function address in the array
and executes the function that has that address.
• If you use the third virtual function in the class declaration, the program uses the function whose address is in the third
element of the array.
How Virtual Functions Work

class Scientist {…
char name[40];
public:
virtual void show_name();
virtual void show_all();
…};
class Physicist : public Scientist{ ...
char field[40];
public:
void show_all(); // redefined
virtual void show_field(); // new
...
};
How Virtual Functions Work
Abstract Classes and Pure Virtual Functions
• It is possible that you 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.
• A pure virtual function is a virtual function that has no definition
within the base class.
• To declare a pure virtual function, use this general form:
virtual type func-name(parameter-list) = 0;

• When a virtual function is made pure, any derived class must provide its
own definition.
• If the derived class fails to override the pure virtual function, a compile-
time error will result.
Abstract class
Properties of Pure virtual function
Pure virtual function int main()
#include <iostream>
using namespace std; {
class Base { //base class // Base bad; //can’t make object from abstract
class
public: Base* arr[2]; //array of pointers to base class
virtual void show() =0; // pure virtual function Derv1 dv1; //object of derived class 1
}; Derv2 dv2; //object of derived class 2
class Derv1 : public Base { //derived class 1 arr[0] = &dv1; //put address of dv1 in array
public: arr[1] = &dv2; //put address of dv2 in array
void show() arr[0]->show(); //execute show() in both objects
{ cout << “Derv1\n”; } arr[1]->show();
}; return 0;
class Derv2 : public Base { //derived class 2
public:
void show() }
{ cout << “Derv2\n”; }
};
Virtual Destructors
• Deleting a derived class object using a pointer to a base class
that has a non-virtual destructor results in undefined behavior.
• To correct this situation, the base class should be defined with
a virtual destructor.
Example
#include <iostream>
using namespace std; Constructing A
class A { Constructing B
public: Destructing A
A() { cout << "Constructing A\n"; }
~A() { cout << "Destructing A\n"; }
};
class B : public A {
public:
B() { cout << "Constructing B\n"; }
~B() { cout << "Destructing B\n"; }
};
int main(){
A *ptr=new B();
delete ptr;
// B obj1;
return 0;}
Virtual destructor
#include <iostream>
Constructing A
using namespace std;
Constructing B
class A {
Destructing B
public:
Destructing A
A() { cout << "Constructing A\n"; }
virtual ~A() { cout << "Destructing A\n"; }
Process returned 0 (0x0) execution time :
}; 5.203 s
class B : public A { Press any key to continue.
public:
B() { cout << "Constructing B\n"; }
~B() { cout << "Destructing B\n"; }
};
int main(){
A *ptr=new B;
delete ptr;
return 0;}
Rules for Virtual function
Rules for Virtual function

You might also like