Skip to main content

Inherticance in C++

What is inheritance?

In object oriented programming, Inheritance is a mechanism by which a new class can be created as an extension of an existing class. Inheritance helps us in code reuse.

The existing class is called base class /super class  and new class is called derived class / sub class  or inherited class.


Derived class is an extension of base class. It inherits all the members of the base class (even the private members). And it can have new members of its own.

Base class members which are public and protected are accessible from derived class object. Private members of base class are not directly accessible in derived class but can be accessed using base class methods.

Syntax

class derived-class:access-specifier base-class
{
/* members*/
};

We write derived class name followed by :, followed by public/private/protected followed by base class name. Then the usual definition of class is written where in we write new members of the class.

The base class must have been declared earlier. Access-specifier tells the mode of inheriting. It can be one of public, private or protected.

public is most commonly used access specifier. If omitted, access defaults to private. The table below shows how the access specifier controls the access of base class members.
Public Inheritance Public members remain public
Protected members remain protected  in derived class
Protected Inheritance Public and protected members become protected in derived class
Private Inheritance Public and protected members become private members in derived class

Public access specifier is the most commonly used mode for inheritance. If public access specifier is used, all public base class members are accessible in derived class and they remain public in derived class too. Which means they can be accessed from outside of derived class too.  And protected members of the base class remain protected in derived class, which means they are not accessible outside the derived class except for derived classes of derived class.

Protected access specifier makes the both public and protected members as protected members in derived class.

Let us look at an example of inheritance.


class A
{
 int n;
public:
 void setn(int m)
 { n = m; }
 int getn()
 { return n;}
protected:
 int n0;
};
class B:public A
{ 
 int n_der;
public:
 void print();
};
void B::print()
{
 cout<<getn()<<n_der;
 //cout<<n;//invalid
 cout<<n0;//valid
}
int main()
{
 B obj;
 obj.setn(10);
 cout<<obj.getn();/*obj can call base class function*/
 obj.print();
}

Here B is a derived class of A. That is to say, B is specialized class of A. B has all the features of A plus extra. So B has all data members of A and all methods of A.

 obj  is an object of derived class B, has the following data members - n and n_der and n0. n and n0 are inherited from base class A and n_der is a new member added in B.

obj has 3 member functions - getn(), setn() and print().

In the print() function of B class, derived class can access n0 because it is a protected member in base class. But it can not access n because n is private in base class.

Note that private member n can  be accessed by B class using getn() and setn() functions.

Which members of base class are inherited by derived class? 

Derived class inherits all the members of base class except for
  1. Constructors and destructors
  2. Overloaded operators
  3. Friend functions
Each object of a derived class IS AN object of base class.   

Protected members of a class

Let us revisit the access specifier "protected" in a class. A class member which is protected is not accessible outside of a class. But it is accessible from methods of derived class.


class A
{
   int n;
protected:
   int m;
};
class B:public A
{
   public:
     void print();
};
void B::print()
{
     cout<<n;//error
     cout<<m;//No error
}
In class A above, m is a protected member. It can not be accessed from outside. It can't be accessed from main() function. But it can be accessed from B class. print() function of B class, trying to display m does not produce any error. But display of n produces a syntax error.

So a protected member is like private member, but it can be accessed from derived class objects.

ISA

Remember that derived class object is a base class object.

A function which has a base class parameter can be sent any base class object as argument or any derived class object as argument.

So whenever a base class object is needed, you can use a derived class object in its place. But the reverse is not true. A base class object is not a derived class object.


class Dog:public Animal
{/*code*/};
void printAge(Animal a)
{
 cout<<"Age of animal is "<<a.getAge();
}
int main()
{
 Dog d1;
 Animal a1;
 a1 = d1;/*valid*/
 // d1 = a1;/*invalid*/
 printAge(a1);
 printAge(d1);
}

Here d1 is an Animal class object too. But a1 is not a Dog.
 
Now the function printAge() can be called with an object of animal class. But the argument to printAge() function can also be an object of derived class of Animal. But it can also be called with Dog object. Because Dog is a derived class and hence Dog is also an animal. 

Base Class
|
|
|
Derived Class

But when an object is upcasted (converted from derived to base class. Called so because of inheritance diagram), it will contain only base class elements and will lose derived class information. This is called object slicing.
 
If in the above example Dog class had extra data member- say Name, this member will not be present in the printAge function.

Object slicing can be avoided by using references or pointers.

Constructors and Destructors of Derived Class

When an object of derived class is created, first, constructor of base class is called implicitly, followed by constructor of derived class. If base class does not have default constructor, a compiler error is generated.


When derived object is being destroyed, first destructor of derived class is called  and then destructor of base class is called.

class A
{
public:
 A(){cout<<"A ctor ";}
 ~A(){cout<<"A dtor ";}
};
class B:public A
{
public:
 B(){cout<<"B ctor ";}
 ~B(){cout<<"B dtor ";}
};
int main()
{
 B obj; 
 cout<<"Hello world ";
}

Output of the above program will be
A ctor B ctor Hello World B dtor A dtor

When obj is created, it first calls base class constructor (A constructor), then it calls derived class constructor (B).

When main function is terminated, object obj is destroyed. During destruction, the program first calls derived class destructor (B) and then calls base class destructor. 

Member Initializer list for Base class constructor

If base class has no default constructor, then derived class can not call base constructor implicitly. This generates a syntax error.

class A
{
public:
 A(int m){/***code***/
};
class B:public A
{
 /*code*/
}
int main()
{
 B obj1;
}

The program above fails to compile because our base class A has no default constructor. B constructor for obj1  tries to call A constructor but fails.

In such situations, derived class must define a constructor, which must call base class constructor explicitly  in its member initializer list.
 

class B:public A
{
public:
 B():A(0){/*B ctor*/}
/*code*/
};

B constructor here calls non-default A constructor as A(0)


As we can see in the above code, we are calling parameterized constructor of base class using A(0) - which calls A constructor with argument 0.  And this must be called in member initialization list of derived class constructor. It can not be in the body of B constructor. 

Name Hiding

Derived class object can call all the public and protected methods of base class. But what if base and derived class methods have same name?

If derived class redefines a base class method with same name but different types or number of parameters, then base class version of function can not be called in the derived class. It gets hidden.

class A
{
public:
 void print();
};
class B:public A
{
public:
 void print(int n);/*this hides 
print function of base class*/
};
/* functions here*/
int main()
{
 A objA;
 B objB;
 objA.print();/*correct*/
 objB.print(10);/*OK*/
// objB.print();/*invalid */
}

In the above example, objB.print() is invalid because print() function is redefined with different signature in derived class. So print() with no parameters can not be called using B class object. Remember print() can be still be called using objects of A class.

If it is necessary to call such a hidden function from derived class,  it can  be called using scope resolution operator and base class name
 as
  objB.A::print()

Function Overriding:


A derived class can provide its own version of base class function. This overriding function in derived class must have exact signature as base class function. 

class A
{
public:
 void print()
 {
 cout<<"Hello world";
 }
};
class B:public A
{
public:
 void print()/*overriding function*/
 {
 cout<<"Goodbye world";
 }
};
int main()
{
 A obj1;
 obj1.print();/*prints hello world*/
 B obj2;
 obj2.print();/*prints Goodbye world*/
}


Now if print() is called from object of B class, it invokes the overriding function of derived class.

Function overriding and  virtual functions is  used for implementing polymorphism in C++. 



You can get these notes and also programs, quiz on C++ by downloading the app Simplified C++ by Hegdeapps 

Comments

Popular posts from this blog

Ten questions in C/C++

Let us see some questions in C and C++ Write printf statement in C to print - I got 98% in Maths Can you execute a function before main() in C? If yes, how is it done? Can you write a program to find if a number is even without using modulo operator? How do you define a data member which is common to all objects of a class in C++? Can we have a single constructor for a class, but still create objects from the class passing zero/one and two parameters? What problems might occur if a class has no default constructor? Is the following statement correct? fprintf(stdout,"Hello world");   Why do we use the following statement in C++ program? using namespace std;  Can you write a single statement to check if the number is a power of 2?  What does the following statement mean in C/C++?4 if(a) b++;    So we have 10 questions. How many of these can you answer?   Do you need more questions in C and C++?    You can find t...

Find the error in C++ program

This C++ program is not compiling. What do you think is the error with the program? #include<iostream> using namespace std; int main() {    int arr[10];    arr={1,2,3,4,5,6,7,8};    cout<<"arr[0]="<<arr[0];    return 0; } Is the error due to Not using printf Initialising the array with only 8 elements instead of 10 Initialising array in the next statement instead of in definition. None of the above  Now if you like this question, there are plenty more questions like this and programs and notes in my app Simplified C++. Download the Simplif ied C++   by Hegdeapps now By the way the correct answer is (3)

Basics of C++

Let us talk about some basics of the language.  Identifiers  All variables and functions and objects need a name - they need identifiers. Identifiers in C++ need to follow some simple rules      They need to start with either a-z/A-Z or _ (underline)      They can contain only alphabets, digits or underline      They need to be unique in their scope      They can not be keywords Examples of some bad identifiers    1var    sum of numbers    int Data types :  C++ has the following basic data types. We will talk about classes and objects later     int     float     char     double     bool int An int data type is used to store integer values. e.g.   int a=10; int b = -100;   float and double  are used to store real numbers. double ...