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...

It is a constant

In good old days, C programmers would use preprocessor directive to define constants. e.g. #define s 10 But we know now that, as compiler never gets to see these, preprocessor statements are error prone. Hence we have const s. A constant - defined with keyword const promises that this entity is never going to change. And if we accidentally modify a const, compiler throws an error. Let us look at an example. #include<iostream> using namespace std; int main () { int a = 10 ; const int b = 12 ; a ++ ; b = 18 ; } When we compile this program, compiler tells us that default.cpp: In function ‘int main()’: default.cpp:8:7: error: assignment of read-only variable ‘b’      b = 18; So it is catching the error that we are trying to modify a const. Whenever a local variable or parameter need not be modified, declare it as a const.  Yes, we can make even parameters as constant. We can make objects constant or even me...

Abstract class

 If we can not create any objects of a class, then it is called an abstract class. A class is made abstract by adding at least one pure virtual function to it. Pure virtual function A function is said to be a pure virtual function , if it has no definition but has only declaration. Pure virtual function is defined with the keyword virtual and followed by return type, function name and "=0". class Shape { public: virtual void printarea() =0 ; }; int main () { Shape obj1; //error } Here printarea() function of Shape class is a pure virtual function as it has no body. To make a function as pure virtual function, you should use =0 at the end of virtual function declaration Abstract class When a class has at least one pure virtual function, it is incomplete and no objects can be created from that class. Such a class is called an abstract class . In the earlier example class Shape is an abstract class, and objects can not be created from t...