|
In
this article, we will discuss two important concepts of object-oriented
programming inheritance and polymorphism. Inheritance
permits you to use the existing features of a class as it
is and add a few of your own. Instead of using all the features
of an existing class on an as-is-where-is basis, we can also
override a few of them and provide our own implementation
of them.
For example, a class that can create a window may already
exist, which we can extend to create a button, a list box
or a combo box. While extending a class, the existing class
remains unchanged. The new class is called derived class,
whereas, the existing class is called base class.
The main advantage of inheritance is code reusability. The
code reusability is of great help in the case of distributing
class libraries. A programmer can use a class created by another
person or company, and, without modifying it, derive other
classes from it. C# goes one step further and allows cross
language inheritance too.
Polymorphism and inheritance go hand in hand. Polymorphism
implies the existence of an entity in different forms. Polymorphism
allows classes to provide different implementations of a method
that can be called in the same way. Polymorphism can be of
three typesinheritance polymorphism, interface polymorphism
and polymorphism through abstract classes.
Let us first write a program that shows inheritance at work.
Suppose a bank has a very generic class called account that
allows debit and credit transactions on an account. A bank
has to maintain various accounts like savings bank account,
fixed deposit account, current account, etc. Every account
has a few unique features. For example, a savings account
can be operated only ten times in a month. Similarly, it needs
to have a minimum balance against it. On the other hand, a
current account allows unlimited transactions to be performed.
So we can create more specific classes to maintain different
kinds of accounts from the same account class. These classes
can use the basic functionality of the account class and add
their own account-specific functionality. Following code shows
the base class account and derived classes savingaccount and
currentaccount.
class account
{
protected string name ;
protected float balance ;
public account ( string n, float b )
{
name = n ;
balance = b ;
}
public void deposit ( float amt )
{
balance += amt ;
}
public void withdraw ( float amt )
{
balance -= amt ;
}
public void display( )
{
Console.WriteLine ( Name: {0} Balance: {1}, name, balance ) ;
}
}
class savingaccount : account
{
static int accno = 1000 ;
int trans ;
public savingaccount ( string s, float b ) : base ( s, b )
{
trans = 0 ;
accno++ ;
}
public void withdraw ( float amt )
{
if ( trans >= 10 )
{
Console.WriteLine (Number of transactions exceed 10 ) ;
return ;
}
if ( balance - amt < 500 )
Console.WriteLine ( Below minimum balance ) ;
else
{
base.withdraw ( amt ) ;
trans++ ;
}
}
public void deposit ( float amt )
{
if ( trans >= 10 )
{
Console.WriteLine ( Number of transactions exceed 10 ) ;
return;
}
base.deposit ( amt ) ;
trans++ ;
}
public void display( )
{
Console.WriteLine ( Name: {0} Account no.: {1} Balance: {2} ,
name, accno, balance ) ;
}
}
class currentaccount : account
{
static int accno = 1000 ;
public currentaccount ( string s, float b ) : base ( s, b )
{
accno++ ;
}
public void withdraw ( float amt )
{
if ( balance - amt < 0 )
Console.WriteLine ( No balance in account ) ;
else
balance -= amt ;
}
public void display( )
{
Console.WriteLine ( Name: {0} Account no.: {1} Balance: {2} ,
name, accno, balance ) ;
}
}
The savingaccount class has two data membersaccno that
stores account number, and trans that keeps track of the number
of transactions. We can create an object of savingaccount
class as shown below.
savingaccount s = new savingaccount ( Amar, 5600.00f ) ;
From the constructor of savingaccount class we have called
the two-argument constructor of the account class using the
base keyword and passed the name and balance to this constructor
using which the data members name and balance are initialised.
We can write our own definition of a method that already exists
in a base class. This is called method overriding. We have
overridden the deposit( ) and withdraw( ) methods in the savingaccount
class so that we can make sure that each account maintains
a minimum balance of Rs. 500 and the total number of transactions
do not exceed 10. From these methods we have called the base
classs methods to update the balance using the base
keyword. We have also overridden the display( ) method to
display additional information, i.e. account number.
Working of currentaccount class is more or less similar to
that of savingaccount class.
Using the derived class's object, if we call a method that
is not overridden in the derived class, the base class method
gets executed. Using derived class's object we can call base
class's methods, but the reverse is not allowed.
Unlike C++, C# does not support multiple inheritance. So,
in C# every class has exactly one base class.
Now, suppose we declare reference to the base class and store
in it the address of instance of derived class as shown below.
account a1 = new savingaccount ( Amar, 5600.00f ) ;
account a2 = new currentaccount ( MyCompany Pvt. Ltd., 126000.00f) ;
Such a situation arises when we have to decide at run-time
a method of which class in a class hierarchy should get called.
Using a1 and a2, suppose we call the method display( ), ideally
the method of derived class should get called. But it is the
method of base class that gets called. This is because the
compiler considers the type of reference (account in this
case) and resolves the method call. So, to call the proper
method we must make a small change in our program. We must
use the virtual keyword while defining the methods in base
class as shown below.
public virtual void display( )
{
}
We must declare the methods as virtual if they are going to
be overridden in derived class. To override a virtual method
in derived classes we must use the override keyword as given
below.
public override void display( )
{
}
Now it is ensured that when we call the methods using upcasted
reference, it is the derived class's method that would get
called. Actually, when we declare a virtual method, while
calling it, the compiler considers the contents of the reference
rather than its type.
If we don't want to override base class's virtual method,
we can declare it with new modifier in derived class. The
new modifier indicates that the method is new to this class
and is not an override of a base class method.
Abstract classes and methods
If you analyse the above program carefully, you will notice
that the account class is so general that we would
seldom require calling its methods directly. Rather, we would
always override them in derived class and call the
derived class's methods. So, instead of defining the functionality
in account class we can design the account class in such a
way that it would only specify what functionality the derived
classes should have. So, an abstract class always serves as
the base class for other classes. We can achieve this by declaring
the class as abstract.
abstract class account
{
abstract public void deposit( ) ;
abstract public void withdraw( ) ;
abstract public void display( ) ;
}
An abstract method does not have a definition in base class.
As such, it is similar to a pure virtual function of C++.
We cannot instantiate objects of abstract classes. A class
that inherits an abstract class has to define all the abstract
methods declared in the class.
Interfaces
Polymorphism is also achieved through interfaces. Like abstract
classes, interfaces also describe the methods that a class
needs to implement. The difference between abstract classes
and interfaces is that abstract classes always act as a base
class of the related classes in the class hierarchy. For example,
consider a hierarchy-car and truck classes derived from four-wheeler
class; the classes two-wheeler and four-wheeler derived from
an abstract class vehicle. So, the class 'vehicle' is the
base class in the class hierarchy. On the other hand dissimilar
classes can implement one interface. For example, there is
an interface that compares two objects. This interface can
be implemented by the classes like box, person and string,
which are unrelated to each other.
C# allows multiple interface inheritance. It means that a
class can implement more than one interface.
The methods declared in an interface are implicitly abstract.
If a class implements an interface, it becomes mandatory for
the class to override all the methods declared in the interface,
otherwise the derived class would become abstract.
One last thing. Be careful while designing an interface. Because,
once an interface is published, we cannot change it. We cannot
even add a method because all the classes that implement this
interface will have to implement this method.
 |
Yashavant
Kanetkar, one of the first Express Computer columnists,
is an established software expert, speaker and author
with several best-sellers to his credit, including titles
like “Let Us C” and the “Fundas” series. Contact him at
kanet@nagpur.dot.net.in |
|