Sunday, May 30, 2010

Inheritance

INHERITANCE
Inheritance is the process of creating new classes from the existing class or classes.
Reusability) .
Using inheritance, one can create general class that defines traits common to a set of related items. This class can then be inherited (reused) by the other classes by using the properties of the existing ones with the addition of its own unique properties.

Inheritance can be done in different ways:
1. Single Inheritance - no quite
2. Multiple Inheritance
3. Multi-Level Inheritance
4. Hybrid Inheritance and
5. Hierarchial Inheritance.

The old class is referred to as the base class and the new classes, which are inherited from the base class, are called derived classes.


In above figure, the class B contains the three member i.e. Property1, Property2 and Property3.

The second class named as D contains four members i.e. Property1, Property2, Property3 and Property4.

Out of these, three members (Property1, Property2, Property3) of the class D are same as that of class B, while the one member i.e. Property4 is unique.

In the class D, instead of defining all the three members again, one can reuse them from the class B. This feature is known as inheritance which saves time, space, money and increases the reliability and efficiency.

Forms of Inheritance

1.) Single Inheritance

If a class is derived from a single base class, it is called as single inheritance.

2 .) Multiple Inheritance

If a class is derived from more than one base class, it is known as multiple inheritance

3 ) Multilevel Inheritance

The classes can also be derived from the classes that are already derived. This type of inheritance is called multilevel inheritance.

4 ) Hierarchical Inheritance

If a number of classes are derived from a single base class, it is called as hierarchical inheritance

A derived class can be defined as follows:

class derived_class_name : access_specifier base_class_name
{
data members of the derived class ;
member functions of the derived class ;
}

The colon (:), indicates that the class derived_class_name is derived from the class base_class_name.

The access_specifier may be public, private or protected (will be discussed further).

If no access_specifier is specified, it is private by default.

The access_specifier indicates whether the members of the base class are privately derived or publicly derived.


Public inheritance

When a derived class publicly inherits the base class, all the public members of the base class also become public to the derived class and the objects of the derived class can access the public members of the base class.

The following program will illustrate the use of the single inheritance.

This program has a base class B, from which class D is inherited publicly.

Example:

#include
class Rectangle
{
private:
float length ; // This can't be inherited
public:
float breadth ; // The data and member functions are inheritable
void Enter_lb(void)
{
cout << "\n Enter the length of the rectangle : ";
cin >> length ;
cout << "\n Enter the breadth of the rectangle : ";
cin >> breadth ;
}
float Enter_l(void)
{ return length ; }
}; // End of the class definition

class Rectangle1 : public Rectangle
{
private:
float area ;
public:
void Rec_area(void)
{ area = Enter_l( ) * breadth ; }
// area = length * breadth ; can't be used here

void Display(void)
{
cout << "\n Length = " << Enter_l( ) ; // Object of the derived class can't
// inherit the private member of the base class. Thus the member
// function is used here to get the value of data member 'length'.
cout << "\n Breadth = " << breadth ;
cout << "\n Area = " << area ;
}
}; // End of the derived class definition D
void main(void)
{
Rectangle1 r1 ;
r1.Enter_lb( );
r1.Rec_area( );
r1.Display( );
}




























Private inheritance

When a derived class privately inherits a base class, all the public members of the base class become private for the derived class.

In this case, the public members of the base class can only be accessed by the member functions of the derived class.

The objects of the derived class cannot access the public members of the base class.

Note that whether the derived class is inherited publicly or privately from the base class, the private members of the base class cannot be inherited.


Example:

#include
#include
class Rectangle
{
int length, breadth;
public:
void enter()
{
cout << "\n Enter length: "; cin >> length;
cout << "\n Enter breadth: "; cin >> breadth;
}
int getLength()
{
return length;
}
int getBreadth()
{
return breadth;
}
void display()
{
cout << "\n Length= " << length;
cout << "\n Breadth= " << breadth;
}
};

class RecArea : private Rectangle
{

public:
void area_rec()
{
enter();
cout << "\n Area = " << (getLength() * getBreadth());
}
};
void main()
{
clrscr();
RecArea r ;
r.area_rec();
getch();
}

Example:2

#include
class Rectangle // Base class
{
private:
float length ; // This data member can't be inherited
public:
float breadth ; // This data member is inheritable
void Enter_lb(void)
{
cout << "\n Enter the length of the rectangle: "; cin >> length ;
cout << "\n Enter the breadth of the rectangle: "; cin >> bredth ;
}
float Enter_l(void)
{
return length ;
}
void Display_l(void)
{
cout << "\n Length = " << length ;
}
}; // End of the base class Rectangle.
// Defining the derived class Rectangle1. This class has been derived from the
// base class i.e. Rectangle, privately.
class Rectangle1 : private Rectangle // All the public members of the base class
{ // Rectangle become private for the derived class Rectangle1.
private:
float area ;
public:
void Rec_area(void)
{
Enter_lb( );
area = Enter_l( ) * bredth ; // length can't be used directly
}
void Display(void)
{
Display_l( ); // Displays the value of length.
cout << "\n Bredth = " << bredth ;
cout << "\n Area = " << area << endl ;
}
};
void main(void)
{
Rectangle1 r1 ;
r1.Rec_area( ) ;
// r.Enter_lb( ); will not work as it has become private for the derived class.
r1.Display( ) ;
// r.Display_l( ) will not work as it also has become private for the derived class.
}




The protected access specifier

The third access specifier provided by C++ is protected.

The members declared as protected can be accessed by the member functions within their own class and any other class immediately derived from it.

These members cannot be accessed by the functions outside these two classes.

Therefore, the objects of the derived class cannot access protected members of the base class.

When the protected members (data, functions) are inherited in public mode, they become protected in the derived class. Thus, they can be accessed by the member functions of the derived class.

On other hand, if the protected members are inherited in the private mode, the members also become private in the derived class.

They can also be accessed by the member functions of the derived class, but cannot be inherited further.

Overriding the member functions:

The member functions can also be used in a derived class, with the same name as those in the base class.

One might want to do this so that calls in the program work the same way for objects of both base and derived classes.

The following program will illustrate this concept.

#include
const int len = 20 ;
class Employee
{
private:
char F_name[len];
int I_number ;
int age ;
float salary ;
public:
void Enter_data(void)
{
cout << "\n Enter the first name = " ; cin >> F_name ;
cout << "\n Enter the identity number = " ; cin >> I_number ;
cout << "\n Enter the age = " ; cin >> age ;
cout << "\n Enter the salary = " ; cin >> salary ;
}
void Display_data(void)
{
cout << "\n Name = " << F_name ;
cout << "\n Identity Number = " << I_number ;
cout << "\n Age = " << age ;
cout << "\n Salary = " << salary ;
}
}; // End of the base class
class Engineer : public Employee
{
private:
char design[len] ; // S_Engineer, J_Engineer, Ex_Engineer etc

public:
void Enter_data( )
{
Employee :: Enter_data( ) ; // Overriding of the member function
cout << "\n Enter the designation of the Engineer: " ; cin >> design ;
}


void Display_data(void)
{
cout << "\n *******Displaying the particulars of the Engineer**** \n" ;
Employee :: Display_data( ) ; // Overriding of the member function
cout << "\n Designition = " << design ;
}
}; // End of the derived class

void main(void)
{
Engineer er ;
er.Enter_data( ) ;
er.Display_data( );
}

Hierarchical Inheritance:

When two or more classes are derived from a single base class, then
Inheritance is called the hierarchical inheritance. The representation
of the hierarchical inheritance is shown in the following Fig.









In the above Fig., student is a base class, from which the three classes viz. arts, science and commerce have been derived. Now, let us write a program that illustrates the hierarchical inheritance, based on the above design.

Example

include
const int len = 20 ;
class student // Base class
{
private: char F_name[len] , L_name[len] ;
int age, int roll_no ;
public:
void Enter_data(void)
{
cout << "\n\t Enter the first name: " ; cin >> F_name ;
cout << "\t Enter the second name: "; cin >> L_name ;
cout << "\t Enter the age: " ; cin >> age ;
cout << "\t Enter the roll_no: " ; cin >> roll_no ;
}
void Display_data(void)
{
cout << "\n\t First Name = " << F_name ;
cout << "\n\t Last Name = " << L_name ;
cout << "\n\t Age = " << age ;
cout << "\n\t Roll Number = " << roll_no ;
}
};
class arts : public student
{
private:
char asub1[len] ;
char asub2[len] ;
char asub3[len] ;
public:
void Enter_data(void)
{
student :: Enter_data( );
cout << "\t Enter the subject1 of the arts student: "; cin >> asub1 ;
cout << "\t Enter the subject2 of the arts student: "; cin >> asub2 ;
cout << "\t Enter the subject3 of the arts student: "; cin >> asub3 ;
}
void Display_data(void)
{
student :: Display_data( );
cout << "\n\t Subject1 of the arts student = " << asub1 ;
cout << "\n\t Subject2 of the arts student = " << asub2 ;
cout << "\n\t Subject3 of the arts student = " << asub3 ;
}
};
class commerce : public student
{
private: char csub1[len], csub2[len], csub3[len] ;
public:
void Enter_data(void)
{
student :: Enter_data( );
cout << "\t Enter the subject1 of the commerce student: ";
cin >> csub1;
cout << "\t Enter the subject2 of the commerce student: ";
cin >> csub2 ;
cout << "\t Enter the subject3 of the commerce student: ";
cin >> csub3 ;
}
void Display_data(void)
{
student :: Display_data( );
cout << "\n\t Subject1 of the commerce student = " << csub1 ;
cout << "\n\t Subject2 of the commerce student = " << csub2 ;
cout << "\n\t Subject3 of the commerce student = " << csub3 ;
}
};

void main(void)
{
arts a ;
cout << "\n Entering details of the arts student\n" ;
a.Enter_data( );
cout << "\n Displaying the details of the arts student\n" ;
a.Display_data( );
science s ;
cout << "\n\n Entering details of the science student\n" ;
s.Enter_data( );
cout << "\n Displaying the details of the science student\n" ;
s.Display_data( );
commerce c ;
cout << "\n\n Entering details of the commerce student\n" ;
c.Enter_data( );
cout << "\n Displaying the details of the commerce student\n";
c.Display_data( );
}

Multiple Inheritance

When a class is inherited from more than one base class, it is known as multiple inheritance.
The syntax for defining a subclass, which is inheriting more than one classes is:
class Subclass : access_specifier Baseclass1,
access_specifier Baseclass2, ………
…….. access_specifier Baseclass_n
{
members of the derived class ;
};
The following figure illustrates the use of multiple inheritance. 




















In the above figure, Circle and Rectangle are two base classes from which the class Cylinder is being inherited.

The data members of both the base classes are declared in protected mode. Thus, the class Cylinder can access the data member radius of class Circle and data member length, breadth of the class Rectangle, but the objects of the class Cylinder cannot access these protected data members.

The volume of the cylinder is equal to 22/7*(radius*radius*length). Thus, instead of defining these data again, they can be inherited from the base classes Circle and Rectangle ( radius from class Circle and length from class Rectangle ).

Example:

#include
class Circle // First base class
{
protected:
float radius ;
public:
void Enter_r(void)
{
cout << "\n\t Enter the radius: "; cin >> radius ;
}
void Display_ca(void)
{
cout << "\t The area = " << (22/7 * radius*radius) ;
}
};
class Rectangle // Second base class
{
protected:
float length, breadth ;
public:
void Enter_lb(void)
{
cout << "\t Enter the length : "; cin >> length ;
cout << “\t Enter the breadth : ” ; cin >> breadth ;
}
void Display_ar(void)
{
cout << "\t The area = " << (length * breadth);
}
};
class Cylinder : public Circle, public Rectangle // Derived class, inherited
{ // from classes Circle & Rectangle
public:
void volume_cy(void)
{
cout << "\t The volume of the cylinder is: "
<< (22/7* radius*radius*length) ;
}
};
void main(void)
{
Circle c ;
cout << "\n Getting the radius of the circle\n" ;
c.Enter_r( );
c.Display_ca( );
Rectangle r ;
cout << "\n\n Getting the length and breadth of the rectangle\n\n";
r.Enter_l( );
r.Enter_b( );
r.Display_ar( );
Cylinder cy ; // Object cy of the class cylinder which can access all the
// public members of the class circle as well as of the class rectangle
cout << "\n\n Getting the height and radius of the cylinder\n";
cy.Enter_r( );
cy.Enter_lb( );
cy.volume_cy( );
}

Multilevel Inheritance:

It has been discussed so far that a class can be derived from a class.

C++ also provides the facility of multilevel inheritance, according to which the derived class can also be derived by an another class, which in turn can further be inherited by another and so on.

The following figure will illustrate the meaning of the multilevel inheritance.































In the above figure, class B represents the base class. The class D1 that is called first level of inheritance, inherits the class B. The derived class D1 is further inherited by the class D2, which is called second level of inheritance.

Example: Multilevel Inheritance

#include
class Base
{
protected:
int b;
public:
void EnterData( )
{
cout << "\n Enter the value of b: ";
cin >> b;
}
void DisplayData( )
{
cout << "\n b = " << b;
}
};
class Derive1 : public Base
{
protected:
int d1;
public:
void EnterData( )
{
Base:: EnterData( );
cout << "\n Enter the value of d1: ";
cin >> d1;
}
void DisplayData( )
{
Base::DisplayData();
cout << "\n d1 = " << d1;
}
};
class Derive2 : public Derive1
{
private:
int d2;
public:
void EnterData( )
{
Derive1::EnterData( );
cout << "\n Enter the value of d2: ";
cin >> d2;
}
void DisplayData( )
{
Derive1::DisplayData( );
cout << "\n d2 = " << d2;
}
};
int main( )
{
Derive2 objd2;
objd2.EnterData( );
objd2.DisplayData( );
return 0;
}

*****************************************************************************

Virtual base classes

Suppose you have two derived classes B and C that have a common base class A, and you also have another class D that inherits from B and C. You can declare the base class A as virtual to ensure that B and C share the same subobject of A.
In the following example, an object of class D has two distinct subobjects of class L, one through class B1 and another through class B2. You can use the keyword virtual in front of the base class specifiers in the base lists of classes B1 and B2 to indicate that only one subobject of type L, shared by class B1 and class B2, exists.
  






class L { /* ... */ }; // indirect base class
class B1 : virtual public L { /* ... */ };
class B2 : virtual public L { /* ... */ };
class D : public B1, public B2 { /* ... */ }; // valid
Using the keyword virtual in this example ensures that an object of class D inherits only one subobject of class L.
A derived class can have both virtual and nonvirtual base classes. For example:





class V { /* ... */ };
class B1 : virtual public V { /* ... */ };
class B2 : virtual public V { /* ... */ };
class B3 : public V { /* ... */ };
class X : public B1, public B2, public B3 { /* ... */
};
In the above example, class X has two subobjects of class V, one that is shared by classes B1 and B2 and one through class B3.



Example of  Hybrid or Virtual Base Class

class PoweredDevice
{
public:
    PoweredDevice(int nPower)
    {
               cout << "PoweredDevice: " << nPower << endl;
    }
};
 
class Scanner: virtual public PoweredDevice
{
public:
    Scanner(int nScanner, int nPower)
        : PoweredDevice(nPower)
    {
               cout << "Scanner: " << nScanner << endl;
    }
};
 
class Printer: virtual public PoweredDevice
{
public:
    Printer(int nPrinter, int nPower)
        : PoweredDevice(nPower)
    {
               cout << "Printer: " << nPrinter << endl;
    }
};
 
class Copier: public Scanner, public Printer
{
public:
    Copier(int nScanner, int nPrinter, int nPower)
        : Scanner(nScanner, nPower), Printer(nPrinter, nPower), PoweredDevice(nPower)
    {
    }
};

int main()
{
    Copier cCopier(1, 2, 3);
}
Output :
produces the result:
PoweredDevice: 3
Scanner: 1
Printer: 2
 

Virtual functions

By default, C++ matches a function call with the correct function definition at compile time. This is called static binding. You can specify that the compiler match a function call with the correct function definition at run time; this is called dynamic binding. You declare a function with the keyword virtual if you want the compiler to use dynamic binding for that specific function.
The following examples demonstrate the differences between static and dynamic binding. The first example demonstrates static binding:
#include using namespace std; 
 struct A
{
   void f()
  { 
    cout << "Class A" << endl;
    }
};
 struct B: A 
{ 
  void f()
  {
      cout << "Class B" << endl;
  }
};
 void g(A& arg)
{ 
  arg.f();
}
 int main()
{
   B x;
   g(x);
}
The following is the output of the above example:

Class A
When function g() is called, function A::f() is called, although the argument refers to an object of type B. At compile time, the compiler knows only that the argument of function g() will be a reference to an object derived from A; it cannot determine whether the argument will be a reference to an object of type A or type B. However, this can be determined at run time. The following example is the same as the previous example, except that A::f() is declared with the virtual keyword:
#include using namespace std;
 struct A 
{
   virtual void f()
    {
        cout << "Class A" << endl;
    }
};
 struct B: A 
{
   void f()
    { cout << "Class B" << endl;
    }
};
 void g(A& arg)
{
   arg.f();
}
 int main()
{
   B x; 
  g(x);
}

The following is the output of the above example:
Class B
The virtual keyword indicates to the compiler that it should choose the appropriate definition of f() not by the type of reference, but by the type of object that the reference refers to.

Therefore, a virtual function is a member function you may redefine for other derived classes, and can ensure that the compiler will call the redefined virtual function for an object of the corresponding derived class, even if you call that function with a pointer or reference to a base class of the object.

A class that declares or inherits a virtual function is called a polymorphic class.
You redefine a virtual member function, like any member function, in any derived class. Suppose you declare a virtual function named f in a class A, and you derive directly or indirectly from A a class named B. If you declare a function named f in class B with the same name and same parameter list as A::f, then B::f is also virtual (regardless whether or not you declare B::f with the virtual keyword) and it overrides A::f. However, if the parameter lists of A::f and B::f are different, A::f and B::f are considered different, B::f does not override A::f, and B::f is not virtual (unless you have declared it with the virtual keyword). Instead B::f hides A::f.
The following example demonstrates this:
#include using namespace std;
 struct A 
{
   virtual void f()
  {
    cout << "Class A" << endl;
    }
};
 struct B: A 
{ 
  void f(int)
    {
        cout << "Class B" << endl; 
    }
};
 struct C: B 
{ 
      void f()
        { cout << "Class C" << endl;
        }
};
 int main()
{
   B b;
    C c;
   A* pa1 = &b;
   A* pa2 = &c;//   b.f(); 
   pa1->f();
   pa2->f();
}
The following is the output of the above example:
Class AClass C
The function B::f is not virtual. It hides A::f. Thus the compiler will not allow the function call b.f(). The function C::f is virtual; it overrides A::f even though A::f is not visible in C.
If you declare a base class destructor as virtual, a derived class destructor will override that base class destructor, even though destructors are not inherited.
The return type of an overriding virtual function may differ from the return type of the overridden virtual function. This overriding function would then be called a covariant virtual function. Suppose that B::f overrides the virtual function A::f. The return types of A::f and B::f may differ if all the following conditions are met:
  • The function B::f returns a reference or pointer to a class of type T, and A::f returns a pointer or a reference to an unambiguous direct or indirect base class of T.
  • The const or volatile qualification of the pointer or reference returned by B::f has the same or less const or volatile qualification of the pointer or reference returned by A::f.
  • The return type of B::f must be complete at the point of declaration of B::f, or it can be of type B.
The following example demonstrates this:
#include using namespace std;  
struct A { };
 class B : private A {   friend class D;   friend class F;};
 A global_A;B global_B; 
 struct C 
{
   virtual A* f()
  {      cout << "A* C::f()" << endl;     
           return &global_A;   
}};
 struct D : C 
{   
B* f()
{      cout << "B* D::f()" << endl;
      return &global_B; 
  }};
 struct E; struct F : C 
{ //   Error://   E is incomplete//   E* f();
};
 struct G : C { //   Error://   A is an inaccessible base class of B//   B* f();};
 int main()
{   
D d;
C* cp = &d;
 D* dp = &d;
A* ap = cp->f();
 B* bp = dp->f();};


The following is the output of the above example:
B* D::f()B* D::f()
The statement A* ap = cp->f() calls D::f() and converts the pointer returned to type A*. The statement B* bp = dp->f() calls D::f() as well but does not convert the pointer returned; the type returned is B*. The compiler would not allow the declaration of the virtual function F::f() because E is not a complete class. The compiler would not allow the declaration of the virtual function G::f() because class A is not an accessible base class of B (unlike friend classes D and F, the definition of B does not give access to its members for class G).
A virtual function cannot be global or static because, by definition, a virtual function is a member function of a base class and relies on a specific object to determine which implementation of the function is called. You can declare a virtual function to be a friend of another class.
If a function is declared virtual in its base class, you can still access it directly using the scope resolution (::) operator. In this case, the virtual function call mechanism is suppressed and the function implementation defined in the base class is used. In addition, if you do not override a virtual member function in a derived class, a call to that function uses the function implementation defined in the base class.
A virtual function must be one of the following:
  • Defined
  • Declared pure
  • Defined and declared pure
A base class containing one or more pure virtual member functions is called an abstract class.
 


Abstract classes

An abstract class is a class that is designed to be specifically used as a base class. An abstract class contains at least one pure virtual function. You declare a pure virtual function by using a pure specifier (= 0) in the declaration of a virtual member function in the class declaration.
The following is an example of an abstract class:
class AB 
{
public:
  virtual void f() = 0;
};
Function AB::f is a pure virtual function. A function declaration cannot have both a pure specifier and a definition. For example, the compiler will not allow the following:
struct A {
  virtual void g() { } = 0;
};
You cannot use an abstract class as a parameter type, a function return type, or the type of an explicit conversion, nor can you declare an object of an abstract class. You can, however, declare pointers and references to an abstract class. The following example demonstrates this:
struct A {
  virtual void f() = 0;
};
 
struct B : A {
  virtual void f() { }
};
 
// Error:
// Class A is an abstract class
// A g();
 
// Error:
// Class A is an abstract class
// void h(A);
A& i(A&);
 
int main() {
 
// Error:
// Class A is an abstract class
//   A a;
 
   A* pa;
   B b;
 
// Error:
// Class A is an abstract class
//   static_cast(b);
}
Class A is an abstract class. The compiler would not allow the function declarations A g() or void h(A), declaration of object a, nor the static cast of b to type A.
Virtual member functions are inherited. A class derived from an abstract base class will also be abstract unless you override each pure virtual function in the derived class.
For example:
class AB {
public:
  virtual void f() = 0;
};
 
class D2 : public AB {
  void g();
};
 
int main() {
  D2 d;
}
The compiler will not allow the declaration of object d because D2 is an abstract class; it inherited the pure virtual function f()from AB. The compiler will allow the declaration of object d if you define function D2::g().
Note that you can derive an abstract class from a nonabstract class, and you can override a non-pure virtual function with a pure virtual function.
You can call member functions from a constructor or destructor of an abstract class. However, the results of calling (directly or indirectly) a pure virtual function from its constructor are undefined. The following example demonstrates this:
struct A {
  A() {
    direct();
    indirect();
  }
  virtual void direct() = 0;
  virtual void indirect() { direct(); }
};
The default constructor of A calls the pure virtual function direct() both directly and indirectly (through indirect()).
The compiler issues a warning for the direct call to the pure virtual function, but not for the indirect call.


No comments:

Post a Comment

Followers

HomeraDurani

My photo
Rajkot, Gujarat, India
Lecturer in MCA Department Atmiya Institute of Technology & Science Rajkot