One
of the most important concepts in object-oriented programming is that
of inheritance. Inheritance allows us to define a class in terms of
another class, which makes it easier to create and maintain an
application. This also provides an opportunity to reuse the code
functionality and fast implementation time.
When
creating a class, instead of writing completely new data members and
member functions, the programmer can designate that the new class
should inherit the members of an existing class. This existing class
is called the base class, and the new class is
referred to as the derived class.
The
idea of inheritance implements the is a relationship.
For example, mammal IS-A animal, dog IS-A mammal hence dog IS-A
animal as well and so on.
-> Just
like abstraction is closely related with generalization, the
inheritance is closely related with specialization. It is important
to discuss those two concepts together with generalization to better
understand and to reduce the complexity.
->One
of the most important relationships among objects in the real world
is specialization, which can be described as the “is-a”
relationship. When we say that a dog is a mammal, we mean that the
dog is a specialized kind of mammal. It has all the characteristics
of any mammal (it bears live young, nurses with milk, has hair), but
it specializes these characteristics to the familiar characteristics
of canis
domesticus.
A cat is also a mammal. As such, we expect it to share certain
characteristics with the dog that are generalized in Mammal, but to
differ in those characteristics that are specialized in cats.
->The
specialization and generalization relationships are both reciprocal
and hierarchical. Specialization is just the other side of the
generalization coin: Mammal generalizes what is common between dogs
and cats, and dogs and cats specialize mammals to their own specific
subtypes.Purpose Of Inheritance:
- Code
Re-usability (40 %)
- Method
Overriding (i.e. Run Time Poymorphism) using virtual keyword (60 %).
Base & Derived Classes:
A
class can be derived from more than one classes, which means it can
inherit data and functions from multiple base classes. To define a
derived class, we use a class derivation list to specify the base
class(es). A class derivation list names one or more base classes and
has the form:
class derived-class: access-specifier base-class
Where
access-specifier is one of public, protected, or private,
and base-class is the name of a previously defined class. If the
access-specifier is not used, then it is private by default.
Consider
a base class Shape and its derived
class Rectangle as follows:
#include <iostream>
using namespace std;
// Base class
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// Derived class
class Rectangle: public Shape
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
return 0;
}
When
the above code is compiled and executed, it produces the following
result:
Total area: 35
Access Control and Inheritance:
A
derived class can access all the non-private members of its base
class. Thus base-class members that should not be accessible to the
member functions of derived classes should be declared private in the
base class.
We
can summarize the different access types according to who can access
them in the following way:
Access
|
public
|
protected
|
private
|
---|---|---|---|
Same class
|
yes
|
yes
|
yes
|
Derived
classes
|
yes
|
yes
|
no
|
Outside
classes
|
yes
|
no
|
no
|
A
derived class inherits all base class methods with the following
exceptions:
- Constructors, destructors and copy constructors of the base class.
- Overloaded operators of the base class.
- The friend functions of the base class.
When
deriving a class from a base class, the base class may be inherited
through public, protected orprivate inheritance.
The type of inheritance is specified by the access-specifier as
explained above.
We
hardly use protected or private inheritance,
but public inheritance is commonly used. While using
different type of inheritance, following rules are applied:
- Public Inheritance: When deriving a class from a public base class, public members of the base class become public members of the derived class and protected members of the base class become protected members of the derived class. A base class's private members are never accessible directly from a derived class, but can be accessed through calls to the publicand protected members of the base class.
- Protected Inheritance: When deriving from a protected base class, public and protectedmembers of the base class become protected members of the derived class.
- Private Inheritance: When deriving from a private base class, public and protected members of the base class become private members of the derived class.
What
is inherited?
When
inheritance is done, various links and tables (index, virtual etc)
are created which are used to provide the accessibility of the
members of the base class in derived class and in other class
hierarchy. This means saying “public
members are inherited” is
better to say as “public
members become accessible”.
A
derived class inherits every member of a base class except:
- its constructor and its destructor
- its friends
- its operator=() members
Types of Inheritance
There
are five different inheritances supported in C++:
- (1) Simple / Single
- (2) Multilevel
- (3) Hierarchical
- (4) Multiple
- (5) Hybrid
Multiple Inheritances:
A
C++ class can inherit members from more than one class and here is
the extended syntax:
class derived-class: access baseA, access baseB....
Where
access is one of public, protected, or private and
would be given for every base class and they will be separated by
comma as shown above. Let us try the following example:
#include <iostream>
using namespace std;
// Base class Shape
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
// Base class PaintCost
class PaintCost
{
public:
int getCost(int area)
{
return area * 70;
}
};
// Derived class
class Rectangle: public Shape, public PaintCost
{
public:
int getArea()
{
return (width * height);
}
};
int main(void)
{
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
// Print the total cost of painting
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0;
}
When
the above code is compiled and executed, it produces the following
result:
Total area: 35
Total paint cost: $2450
Execution order of the constructor and destructor in inheritance.
It
is sometimes the case that classes are derived from other classes,
which are themselves derived from other classes. For example:
class
A { public : A() { cout
<< "A"
<<
endl; } }; class
B:
public
A { public : B() { cout
<< "B"
<<
endl; } }; class
C:
public
B { public : C() { cout
<< "C"
<<
endl; } }; class
D:
public
C { public : D() { cout
<< "D"
<<
endl; } };
|
Remember
that C++ always constructs the “first” or “most base” class
first. It then walks through the inheritance tree in order and
constructs each successive derived class.
Here’s
a short program that illustrates the order of creation all along the
inheritance chain.
int
main() { cout
<< "Constructing
A: "
<<
endl; A
cA; cout
<< "Constructing
B: "
<<
endl; B
cB; cout
<< "Constructing
C: "
<<
endl; C
cC; cout
<< "Constructing
D: "
<<
endl; D
cD; } |
This
code prints the following:
Constructing A:
A
Constructing B:
A
B
Constructing C:
A
B
C
Constructing D:
A
B
C
D
Note:
Base class constructors and derived class destructors are called first
Basically, it's a test to see if you know in what order the constructors and destructors will be called when a program deals with inheritance.
class Base
{
public:
Base ( )
{
cout << "Inside Base constructor" << endl;
}
~Base ( )
{
cout << "Inside Base destructor" << endl;
}
};
class Derived : public Base
{
public:
Derived ( )
{
cout << "Inside Derived constructor" << endl;
}
~Derived ( )
{
cout << "Inside Derived destructor" << endl;
}
};
void main( )
{
Derived x;
}
In
the code above, when the object "x" is created, first the
Base class constructor is called, and after that the Derived class
constructor is called. Because the Derived class inherits from the
Base class, both the Base class and Derived class constructors will
be called when a Derived class object is created.
When
the main function is finished running, the object x's destructor will
get called first, and after that the Base class destructor will be
called.
So,
here is what the output of the code above would look like:
Inside Base constructor
Inside Derived constructor
Inside Derived destructor
Inside Base destructor
Note:
Common
Interview Question: Are
private class members inherited to the derived class?
Ans: Yes,
the private members are also inherited in the derived class but we
will not be able to access them. Trying to access a private base
class member in the derived class will report a compile time error.
class A
{
public :
void fun1
()
{
}
private:
void fun2
()
{
}
};
class B:
public A
{
};
void main
()
{
B B1
= new B ();
B1.fun1
();
//Error,
Cannot access private member fun2
//B1.fun2
();
}
}
Method
Hiding and Inheritance We will look at an example of how
to hide a method in C++. The Parent class has a
write () method which is available to the child class. In the child
class I have created a new write () method. So, now if I create an
instance of child class and call the write () method, the child class
write () method will be called. The child class is hiding the base
class write () method. This is called method hiding.
If we want to call the parent class write () method, we would have to type cast the child object to Parent type and then call the write () method as shown in the code snippet below.
If we want to call the parent class write () method, we would have to type cast the child object to Parent type and then call the write () method as shown in the code snippet below.
class Parent
{
public:
void write
()
{
cout<<
"Parent
Class write method";
}
};
class Child:
public Parent
{
public:
void write
()
{
cout<<"Child
Class write method";
}
};
void main
()
{
Child c1
= new Child ();
c1.write
();
//Type
caste c1 to be of type Parent and call write () method
((Parent)
C1).write ();
}
UpCasting:
Upcasting is using the Super class's reference or pointer to refer to a Sub class's object. Or we can say that, the act of converting a Sub class's reference or pointer into its Super class's reference or pointer is called Upcasting.
UpCasting:
Upcasting is using the Super class's reference or pointer to refer to a Sub class's object. Or we can say that, the act of converting a Sub class's reference or pointer into its Super class's reference or pointer is called Upcasting.
class Super { int x; |
|
public: | |
void funBase() { cout << "Super function"; } | |
}; | |
class Sub : public Super | |
{ int y; }; | |
int main() |
|
{ | |
Super* ptr; // Super class pointer | |
Sub obj; | |
ptr = &obj; | |
Super &ref; // Super class's reference |
|
ref=obj; | |
} The opposite of Upcasting is Downcasting, in which we convert Super class's reference or pointer into derived class's reference or pointer. We will study more about Downcasting later Functions that are never Inherited 2. Also, assignment operator = is never inherited. It can be overloaded but can't be inherited by sub class. Inheritance and Static Functions |
2. If you redefine a static member function in derived class, all the other overloaded functions in base class are hidden.
3. Static Member functions can never be virtual. We will study about Virtual in coming topics.
No comments:
Post a Comment