|
Unit-03/Lecture-01
·
Inheritance ·
Polymorphism ·
Operator and Method
overloading ·
Abstract methods
and classes ·
Method lookup ·
Public and
protected properties, Private operations ·
Inherited methods,
Redefined methods Inheritance Inheritance ·
Inheritance is a mechanism of acquiring the features and behaviors of
a class by another class. ·
The class whose members are inherited is called the base class, and
the class that inherits those members is called the derived class. ·
Inheritance implements the IS-A relationship. ·
For example, mammal IS-A animal, dog IS-A mammal; Hence dog IS-A
animal as well. ·
Similarities often exist between different
classes. Very often two or more classes will share the same attributes and/or
the same methods. Because you don't want to have to write the same code
repeatedly, you want a mechanism that takes advantage of these similarities.
Inheritance is that mechanism. Inheritance models “is a” and “is like”
relationships, enabling you to reuse existing data and code easily. When A
inherits from B, we say A is the subclass of B and B
is the superclass of A. Furthermore, we say we have “pure inheritance”
when A inherits all the attributes and methods of B. The UML
modeling notation for inheritance is a line with a closed arrowhead pointing
from the subclass to the superclass.
Fig. 22 Inheritance
hierarchy This structure would be
called the Person inheritance
hierarchy because Person is
its root class. The Person
class is abstract: objects are not created directly from it, and it captures
the similarities between the students and professors. Abstract classes are
modeled with their names in italics, as opposed to concrete classes, classes
from which objects are instantiated, whose names are in normal text. Both
classes had a name, e-mail address, and phone number, so these attributes
were moved into Person. ·
An
important feature of classes is the inheritance. This allows us to create an
object derived from another one, so that it may include some of the other's
members plus its own ones. For example, we are going to suppose that we want
to declare a series of classes that describe polygons like our CRectangle, or like CTriangle. Both have certain common features, like for
example, the one that both can be described by means of only two sides:
height and base. This could be
represented in the world of classes with a class CPolygon from which we would derive the two referred
ones, CRectangle and CTriangle
Fig. 23 The class CPolygon would contain members that are common for
all polygons. In our case: width and height. And CRectangle and CTriangle would be its derived classes. ·
In principle every member of base class is
inherited by derived one but: ·
Constructor and
destructor
Although constructor and destructor of the base
class are not inherited, the default constructor (i.e. constructor with no
parameters) and the destructor of the base class are always called when a new
object of a derived class is created or destroyed. ·
In order to derive a
class from another, we use a colon (:) in the declaration of the derived
class using the following format : class derived_class: memberAccessSpecifier base_class{ ... };
·
Advantages 1.
Reduce code redundancy. 2.
Provides code reusability. 3.
Reduces source code size and
improves code readability. 4.
Code is easy to manage and
divided into parent and child classes. 5.
Supports code extensibility by
overriding the base class functionality within child classes. ·
Disadvantages 1.
In Inheritance base class and
child classes are tightly coupled. Hence If you change the code of parent
class, it will get affects to the all the child classes. 2.
In class hierarchy many data
members remain unused and the memory allocated to them is not utilized. Hence
affect performance of your program if you have not implemented inheritance
correctly.
Types of
Inheritance OOPs supports
the six types of inheritance as given below- (1). Single inheritance
In this
inheritance, a derived class is created from a single base class.
Fig.24 single
inheritance Example: //Base Class class A { public void fooA() { //TO DO: } } //Derived Class class B : A { public void fooB() { //TO DO: } }
(2). Multi-level
inheritance
In this
inheritance, a derived class is created from another derived class.
Fig. 25 Multi-level Inheritance Example://Base Class class A { public void fooA() { //TO DO: } } //Derived Class class B : A { public void fooB() { //TO DO: } } //Derived Class class C : B { public void fooC() { //TO DO: } } (3).
Multiple inheritance
In this inheritance, a derived
class is created from more than one base class. This inheritance is not
supported by .NET Languages like C#, F# etc.
Fig. 26
Multiple Inheritance Example: //Base Class class A { public void fooA() { //TO DO: } } //Base Class class B { public void fooB() { //TO DO: } } //Derived Class class C : A, B { public void fooC() { //TO DO: } }
(4).
Multipath inheritance
In this inheritance, a derived
class is created from another derived classes and the same base class of
another derived classes. This inheritance is not supported by .NET Languages
like C#, F# etc.
Fig. 27 Multipath Inheritance Example: //Base Class class A { public void fooA() { //TO DO: } } //Derived Class class B : A { public void fooB() { //TO DO: } } //Derived Class class C : A { public void fooC() { //TO DO: } } //Derived Class class D : B, A, C { public void fooD() { //TO DO: } } (5). Hierarchical
inheritance
In this inheritance, more than one derived classes are created from a
single base.
Fig.28 Hierarchical inheritance Example: //Base Class class A { public void fooA() { //TO DO: } } //Derived Class class B : A { public void fooB() { //TO DO: } } //Derived Class class C : A { public void fooC() { //TO DO: } } //Derived Class class D : C { public void fooD() { //TO DO: } } //Derived Class class E : C { public void fooE() { //TO DO: } } //Derived Class class F : B { public void fooF() { //TO DO: } } //Derived Class class G :B { public void fooG() { //TO DO: } } (6). Hybrid inheritance
This is
combination of more than one inheritance. Hence, it may be a combination of
Multilevel and Multiple inheritances or Hierarchical and Multilevel
inheritance or Hierarchical and Multipath inheritance or Hierarchical,
Multilevel and Multiple inheritances. Since
.NET Languages like C#, F# etc. does not support multiple and multipath
inheritance. Hence hybrid inheritance with a combination of multiple or
multipath inheritance is not supported by .NET Languages.
Fig. 29 Hybrid
inheritance Example: //Base Class class A { public void fooA() { //TO DO: } } //Base Class class F { public void fooF() { //TO DO: } } //Derived Class class B : A, F { public void fooB() { //TO DO: } } //Derived Class class C : A { public void fooC() { //TO DO: } } //Derived Class class D : C { public void fooD() { //TO DO: } } //Derived Class class E : C { public void fooE() { //TO DO: } }
Unit-03/Lecture-04
Disinheritance ·
Disinheritance is also called Virtual Inheritance which solve the
Diamond Problem in inheritance.
·
Virtual inheritance is a technique
used in object-oriented programming, where a
particular base
class in an inheritance hierarchy is
declared to share its member data instances with any other inclusions of that
same base in further derived classes. ·
For example, if class A is normally (non-virtually) derived
from class X (assumed to contain data members), and class B
likewise, and class C inherits from both classes A and B,
it will contain two sets of the data members associated with class X
(accessible independently, often with suitable disambiguating qualifiers).
But if class A is virtually derived from class X instead, then
objects of class C will contain only one set of the data members from
class X. ·
This feature is most useful for multiple inheritances, as it makes the
virtual base a common sub
object for
the deriving class and all classes that are derived from it. This can be used
to avoid the problem of ambiguous
hierarchy composition (known as the "diamond problem") by clarifying ambiguity over which ancestor
class to use, as from the perspective of the deriving class (C in the
example above) the virtual base (X) acts as though it were the direct
base class of C, not a class derived indirectly through its base (A). ·
It is used when inheritance represents restriction of a set rather
than composition of parts. In C++, a base class intended to be common throughout
the hierarchy is denoted as virtual with the ·
Example: class Animal { public: virtual void eat();}; class Mammal : public Animal { public: virtual void breathe();}; class WingedAnimal : public Animal { public: virtual void flap();}; // A bat is a winged mammal class Bat : public Mammal, public WingedAnimal { }; Bat bat;
·
When deriving a class from a base class, the base class may be
inherited through public, protected
or private 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 public and protected
members of the base class. ·
Protected Inheritance: When deriving from a protected base class, public and protected members 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.
Unit-03/Lecture-05 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Polymorphism ·
Polymorphism
is another important OOP concept. Polymorphism, a Greek term, means the
ability to take more than on form. ·
Polymorphism allows a reference to denote objects of different types
at different times during execution. ·
An
operation may exhibit different behavior is different instances. The behavior
depends upon the types of data used in the operation. ·
For
example, consider the operation of addition. For two numbers, the operation
will generate a sum. If the operands are strings, then the operation would
produce a third string by concatenation. ·
The
process of making an operator to exhibit different behaviors in different
instances is known as operator overloading. ·
Polymorphism
plays an important role in allowing objects having different internal
structures to share the same external interface. This means that a general
class of operations may be accessed in the same manner even though specific
action associated with each operation may differ. ·
Polymorphism
is extensively used in implementing inheritance. ·
A
single function name can be used to handle different number and different
types of argument. This is something similar to a particular word having
several different meanings depending upon the context. Using a single
function name to perform different type of task is known as function
overloading.
Fig. 30
Polymorphism ·
The word polymorphism means having many forms. Typically,
polymorphism occurs when there is a hierarchy of classes and they are related
by inheritance. ·
C++ polymorphism means that a call to a member function will cause a
different function to be executed depending on the type of object that
invokes the function. Consider the following example where a base class
has been derived by other two classes: #include <iostream> using namespace std; class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } int area() { cout << "Parent class area :" <<endl; return 0; } }; class Rectangle: public Shape{ public: Rectangle( int a=0, int b=0):Shape(a, b) { } int area () { cout << "Rectangle class area :" <<endl; return (width * height); } }; class Triangle: public Shape{ public: Triangle( int a=0, int b=0):Shape(a, b) { } int area () { cout << "Triangle class area :" <<endl; return (width * height / 2); } }; // Main function for the program int main( ) { Shape *shape; Rectangle rec(10,7); Triangle tri(10,5); // store the address of Rectangle shape = &rec; // call rectangle area. shape->area(); // store the address of Triangle shape = &tri; // call triangle area. shape->area(); return 0; } When the above code is compiled and executed, it
produces the following result: Parent class area Parent class area
Types of
Polymorphism
Fig.31 Types of Polymorphism compile time polymorphism -
It is also called as Early Binding or Overloading or static binding. Compile time polymorphism means we will declare methods with same name
but different signatures because of this we will perform different tasks with
same method name. This compile time polymorphism also called as early
binding or method overloading. -
Method
Overloading or compile time polymorphism means same method names with
different signatures (different parameters). -
Polymorphism,
in C++, is implemented through overloaded functions and overloaded operators.
Function Overloading is also referred to as functional polymorphism. The same
function can perform a wide variety of tasks. The same function can handle
different data types. When many functions with the same name but different
argument lists are defined, then the function to be invoked corresponding to
a function call is known during compile time. When the source code is
compiled, the functions to be invoked are bound to the compiler during
compile time, as to invoke which function depending upon the type and number
of arguments. Such a phenomenon is referred to early binding, static linking
or compile time polymorphism. For example: #include <iostream.h> //function prototype int multiply(int num1, int num2); void main() int ans1=multiply(4,3); float ans2 = multiply(2.5, 4.5); The compiler checks for the correct function to be
invoked by matching the type of arguments and the number of arguments
including the return type. The errors, if any, are reported at compile time,
hence referred to as compile time polymorphism. Run Time Polymorphism -
Run
time polymorphism also called as late binding or method overriding
or dynamic polymorphism. Run time polymorphism or method overriding
means same method names with same signatures. -
In
this run time polymorphism or method overriding we can override a method in
base class by creating similar function in derived class this can be achieved
by using inheritance principle and using “virtual & override”
keywords. Example:
Output: In Derived -
If base
class and derived class have member functions with same name and arguments.
If you create an object of derived class and write code to access that member
function then, the member function in derived class is only invoked, i.e.,
the member function of derived class overrides the member function of base
class. This feature in C++ programming is known as function overriding.
Static and dynamic polymorphism Static polymorphism ·
In static polymorphism response to a function is
decided at compile time. ·
Static
polymorphism is achieved by method overloading. ·
Static polymorphism uses the concept of compile time binding (or early
binding). ·
To implement static polymorphism inheritance
is not necessary. ·
Generally
when a programmer want to extend existing feature in a software, method
overloading (load + extra load (more lines of code)) is used, and a
programmer uses method overriding when he wants to provide a different
implementation. ·
Method
overloading is an
example of compile time/static polymorphism because method binding b/w method
call and method defination happens at compile time and it's depend on the ref.
of the class (ref. create at compile time and goes to stack). ·
Method Overloading is unrelated to polymorphism. It refers
to defining different forms of a method (usually by receiving different
parameter number or types). It can be seen as static polymorphism. The
decision to call an implementation or another is taken at coding time. Notice
in this case the signature of the method must change. Example: #include <iostream> // volume of a cube int volume(int s) { return s*s*s;} // volume of a cylinder double volume(double r, int h) { return 3.14*r*r*static_cast<double>(h);} // volume of a cuboid long volume(long l, int b, int h) { return l*b*h;} int main() { std::cout << volume(10); std::cout << volume(2.5, 8); std::cout << volume(100, 75, 15);}In the above example, the volume of various components are calculated using the same function call "volume", with arguments differing in their data type or their number.
Dynamic polymorphism ·
In Dynamic polymorphism response to a function is decided at run
time. ·
Run time
polymorphism ( or dynamic polymorphism) is achieved by method overriding. ·
Dynamic polymorphism
is faster than static polymorphism. ·
Dynamic polymorphism
uses the concept of runtime binding (or late binding). ·
To implement dynamic
polymorphism inheritance is necessary. ·
Method overriding is an example of run time/dynamic polymorphism
because method binding b/w method call and method defination happens
at run time and it's depend on the object of the class(object create
at time and goes to heap). ·
Method Overriding is when a method defined in a superclass or interface is
re-defined by one of its subclasses, thus modifying/replacing the behavior
the superclass provides. The decision to call an implementation or another is
dynamically taken at runtime, depending on the object the operation is called
from. Notice the signature of the method remains the same when overriding. Example: #include <iostream> //--------------------------------------------------------------------------- class TRectangle { public: TRectangle(double l, double w) : length(l), width(w) {} virtual void print() const;private: double length; double width;}; //--------------------------------------------------------------------------- void TRectangle::print() const { // print() method of base class. std::cout << "Length = " << this->length << "; Width = " << this->width;} //--------------------------------------------------------------------------- class TBox : public TRectangle { public: TBox(double l, double w, double h) : TRectangle(l, w), height(h) {} // virtual is optional here, but it is a good practice to remind it to the developer. virtual void print() const;private: double height;}; //--------------------------------------------------------------------------- // print() method of derived class. void TBox::print() const { // Invoke parent print() method. TRectangle::print(); std::cout << "; Height = " << this->height;} The method print() in class TBox, by invoking
the parent version of method print(), is also able to output the private variables length and width of the base class. Otherwise,
these variables are inaccessible to TBox.
Operator Overloading ·
C++ allows you to specify more than one definition for an operator
in the same scope, which is called operator overloading. ·
An overloaded declaration is a declaration that had been declared with
the same name as a previously declared declaration in the same scope, except
that both declarations have different arguments and obviously different
definition (implementation). ·
When you call an overloaded operator, the compiler determines
the most appropriate definition to use by comparing the argument types you used
to call the operator with the parameter types specified in the definitions.
The process of selecting the most appropriate overloaded operator is called overload
resolution. ·
You can redefine or overload most of the built-in operators available
in C++. Thus a programmer can use operators with user-defined types as well. ·
Overloaded operators are functions with special names the keyword
operator followed by the symbol for the operator being defined. Like any
other function, an overloaded operator has a return type and a parameter
list. Box operator+(const Box&); declares
the addition operator that can be used to add two Box objects and
returns final Box object. Most overloaded operators may be defined as
ordinary non-member functions or as class member functions. In case we define
above function as non-member function of a class then we would have to pass
two arguments for each operand as follows: Box operator+(const Box&, const Box&); ·
Following is the example to show the concept of operator over loading
using a member function. Here an object is passed as an argument whose
properties will be accessed using this object, the object which will call
this operator can be accessed using this operator as explained below: #include <iostream> using namespace std; class Box { public: double getVolume(void) { return length * breadth * height; } void setLength( double len ) { length = len; } void setBreadth( double bre ) { breadth = bre; } void setHeight( double hei ) { height = hei; } // Overload + operator to add two Box objects. Box operator+(const Box& b) { Box box; box.length = this->length + b.length; box.breadth = this->breadth + b.breadth; box.height = this->height + b.height; return box; } private: double length; // Length of a box double breadth; // Breadth of a box double height; // Height of a box }; // Main function for the program int main( ) { Box Box1; // Declare Box1 of type Box Box Box2; // Declare Box2 of type Box Box Box3; // Declare Box3 of type Box double volume = 0.0; // Store the volume of a box here // box 1 specification Box1.setLength(6.0); Box1.setBreadth(7.0); Box1.setHeight(5.0); // box 2 specification Box2.setLength(12.0); Box2.setBreadth(13.0); Box2.setHeight(10.0); // volume of box 1 volume = Box1.getVolume(); cout << "Volume of Box1 : " << volume <<endl; // volume of box 2 volume = Box2.getVolume(); cout << "Volume of Box2 : " << volume <<endl; // Add two object as follows: Box3 = Box1 + Box2; // volume of box 3 volume = Box3.getVolume(); cout << "Volume of Box3 : " << volume <<endl; return 0; } When the above code is compiled and executed, it
produces the following result: Volume of Box1 : 210 Volume of Box2 : 1560 Volume of Box3 : 5400
·
Abstract methods
and classes -
Classes
which contain one or more abstract methods or abstract properties, such
methods or properties do not provide implementation. A class that
contains any abstract methods must be declared as an abstract class even if
that class contains some concrete (nonabstract) methods. -
These
abstract methods or properties are implemented in the derived classes
(Sub-classes). -
Abstract
classes does not create any instances to that class objects . -
An abstract class normally contains one or more abstract
methods. An abstract method is one with keyword abstract
in its declaration, Example: public abstract void draw(); // abstract method -
Abstract methods do not provide implementations. -
An abstract class has at least one abstract method. -
An abstract method will not have
any code in the base class; the code will be added in its derived classes. -
The abstract method in the derived class should be implemented with
the same access modifier, number and type of argument, and with the same
return type as that of the base class. Objects of abstract class type cannot
be created, because the code to instantiate an object of the abstract class
type will result in a compilation error. -
A class that contains any abstract methods must be declared as an
abstract class even if that class contains some concrete (nonabstract)
methods. -
An abstract class declares
common attributes and behaviors of the various classes in a class hierarchy.
An abstract class typically contains one or more abstract methods that
subclasses must override if the subclasses are to be concrete. The instance
variables and concrete methods of an abstract class are subject to the normal
rules of inheritance. Method lookup -
The
lookup starts in the CLASS of the RECEIVER, If the method is defined in the
method dictionary. -
It
is returned, Otherwise the search continues in the superclasses of the
receiver's class .If no method is found and there is no superclass to explore
(class Object),this is an ERROR. -
Method lookup is the process of determining which method definition a
method signature denotes during runtime, based on the type of the object. Example: Class Base{ Public: Void display(){ Cout,<<”\n Display base”; } Virtual void show(){cout<<”\n Show derived”;} }; Int main() { Base B; Derived D; Base *bptr; Cout<<”\n bptr points to Base\n”; bptr=&B; bptr->display();//calls Base version bptr->show();//calls Base version cout<<”\n\n bptr points to Derived \n”; bptr=&D; bptr->display();//calls Base version bptr->show();// calls Derived version return(); } }
Unit-03/Lecture-10
Public and
protected properties, Private operations When creating
objects (or just reading the code for objects created by others) you will
often see the key words: public, private, and protected. Here is a short
description of what they mean: ·
Public
Any variable (or function) that
is tagged "public" can be used by any "outsider" to look
at or modify the current state of an object.Most data associated with an object
should not be public. Only variables that are
often changed by the outside world (with out affecting the rest of the
object) should be declared public. For example, the speed of a car would most
definitely be private not public, because another program
should not be able to stop a car by tellin the car its speed is 0. The only
way an "outsider" can change the speed of a car is to use the
"break()" function associated with the car. ·
Private
Any variable (or function) that is tagged
"private" can only be used by the internal code of the
object. This prevents the outside user of the code from manipulating the
object except through the well defined interface.Often functions that are
tagged "private" are referred to as "helper" functions,
because they are usually used by other functions in the object to complete
"sub-tasks".
·
Protected
For the most part, you can read
protected as "private".
The exception to this is when we use the Object Oriented technique of Inheritance. Inheritance is
when one class file is a CHILD of another class file, thus
"getting" all the code from the parent class for free. Children
Objects which "extend" Parent objects have full access (public)
to any protected variable (or function) in the parent object. Inherited methods, Redefined methods Inherited methods · The ability to
redefine a method name in a derived class allows us to tailor inherited
methods for use with a derived class object. · Inappropriate
inherited methods may be overridden or extended by the derived class. · Object –orientation
allows us to override any inherited method by defining derived class method
with the same name. · When we override an
inherited method in a subclass, we can increase its access but not decrease
it. Otherwise we would destroy the ability of a subclass object to behave
like its superclass. · By overriding, an
inherited method can be redefined. If an object received a message that
doesn’t have a method for that message in the class definition. · When a Java
inherits a method from its superclass, the bytecode implementing method is
not reproduced in the implementation of the class. Redefined methods ·
All subclasses contain the components of all classes between
themselves and the root node in an inheritance tree. The visibility of a
component cannot be changed. However,
you can use the REDEFINITION addition in the METHODS statement to redefine an inherited
public or protected instance method in a subclass and make its function more
specialized. When you redefine
a method, you cannot change its interface. ·
The method declaration and implementation in the superclass is not
affected when you redefine the method in a subclass. ·
The implementation of the redefinition in the subclass obscures the original
implementation in the superclass. ·
Within a redefine method, you can use the pseudo reference super-> to access the obscured method. This
enables you to use the existing function of the method in the superclass
without having to recode it in the subclass. ·
Inherited methods can be redefined in subclasses. ·
Redefined methods must be re-implemented in subclasses. ·
The signature of redefined methods cannot be changed. |