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 |
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 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.
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
- Constructors and destructors
- Overloaded operators
- Friend functions
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 }
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.
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
asobjB.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*/ }
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
Post a Comment