“Chishiki” is Japanese for “knowledge.” e-chishiki.com aims to bring software developers, information security professionals, IT executives and other IT pros a rich body of knowledge in the form of articles, interviews, tutorials and technical discussions. Our contributors are among the biggest names in the Indian IT industry and include noted authors, educators and practitioners.
Programming Languages – C++
Inheritance in C++
Yashavant Kanetkar and Asang Dani
The three important cornerstones of Object Oriented Programming (OOP) are Encapsulation, Inheritance and Polymorphism. Encapsulation hides the complexity of any operation from a common user by defining the function inside a class. The common user can then use the function without worrying about the details. Polymorphism means one thing existing in several different forms, or one action leading to different results. The first type is called “compile-time polymorphism,” whereas the second type is called “run-time polymorphism.” Function and operator overloading are examples of compile-time polymorphism, whereas, calling virtual functions is an example of run-time polymorphism. That brings us to the third corner-stone, Inheritance. Inheritance is a mechanism which permits the reuse of existing pieces of software. Another type of reuse mechanism is containership. A good example of it could be using an array of string objects in a stringlist class.
Inheritance in C++
The most important advantage of Inheritance is that it permits code reusability. Once a base class is written and debugged, we can keep it safe, but at the same time it can be adapted to work in different situations. Reusing existing code saves time and money and increases a program's reliability. Inheritance can also help in the original conceptualization of a programming problem, and in the overall design of the program. The code reusability is also very useful while distributing class libraries. The creator of class libraries can distribute the library without being required to part with its source code. The users of the library can either use the library either on as is where is basis or can further modify it by driving new classes from the classes present in the library.
Inheritance can be best understood through a real life example:
Inheritance In Real Life
Let us take an example of a Grandfather, Father and a child. Let us assume that Grandfather has some qualities like, he is a simple minded person, a good English orator and is very religious. When he gives a birth to a son, the son may inherit some of the properties of father, change some properties and acquire some new properties. For example the son may be a simple minded person and a good English orator. This means that he has inherited these properties from the Grandfather. However, the son is moderately religious, which means this property that he acquired from the grandfather has undergone a modification. Thirdly, the son has developed good English writing skills, which he has acquired completely newly. When the son gives birth to a son (grandson for the grandfather), he too inherits some properties from his parent and grandparent, changes some of the properties and acquires a few of his own. The following figure captures the essence of these relationships.
The classes given below can implement the above inheritance relationship:
class grandfather
{
} ;
class son : public grandfather
{
} ;
class grandson : public son
{
} ;
As you can see, there are multiple levels of inheritance in this relationship. Here the class grandson is derived from the base class son, which in turn is further derived from the base class grandfather.
When we create an inheritance chain each class in the chain can contain private, protected and public members. In such a case it becomes important to know which element is accessible to which objects. The following figure shows these accesses in detail.
There is another aspect of inheritance, where a class can be derived from more than one base class. This is called Multiple Inheritance. Let us understand this with the help of an example. Refer the following figure.
Here istream is class that can perform input from an input stream, whereas ostream is class that can perform output to an output stream. istream class doesn't know whether it is going to perform input from console, file or network. Likewise, the ostream class also has no knowledge about whether it is going to perform output to console, file or network. fstream class can perform IO for a file. The ifstream class can perform input from a file stream, whereas, the ofstream class can perform output to a file stream.
The following code snippet will give you an idea of the syntax of defining a class that is inherited from multiple base classes:
class ifstream : public istream, fstream
{
public :
ifstream( ) : istream( ), fstream( )
{
}
} ;
class ofstream : public ostream, fstream
{
public :
ofstream( ) : ostream( ), fstream( )
{
}
} ;
The order in which we mention the base classes in the above declaration of ifstream and ofstream classes dictates the order in which the constructors of the base classes would be called when we create either an ifstream object or an ofstream object. So even if we change the order of the constructors in the list following the colon the calling sequence of the constructors won't change. Note that the destructors in case of multiple inheritance are called in exactly the reverse order of the constructors.
A question may occur to you. Why is the order of calling constructors governed by the order in the class declaration? This is because if you change the order of constructor calls while defining the constructor, you may have two different call sequences in two different constructors, but the poor destructor wouldn’t know how to properly reverse the order of calls for destruction.
In multiple inheritance there may occur a case where there is a conflict of functions. Imagine a situation where a class has been derived from two base classes. The two base classes have functions with the same name, say fun( ), while the derived class has no function with this name. Now what would happen if the derived class object tries to call the base class function fun( )? An error would occur since the compiler cannot figure out fun( ) of which base class you wish to call. This problem can be resolved using the scope resolution operator to specify the function from which base class you wish to call. This is shown below:
// base1 and base2 are base classes
// Both base classes contain the function fun( )
// The class derived has been derived from base1 and base2
derived d ;
d.fun( ) ; // Error
d.base1::fun( ) ;
d.base2::fun( ) ;



