Introduction

There is a lot of confusion among beginners about the abstract class. Knowing its syntax is easy, but when and why should we use an abstract class is something which has troubled most start up developers. I will try to explain the concept with an easy to understand example. Hope this proves to be useful!

Background

There are a lot of definitions for an abstract class, more often I find that instead of explaining the concept, articles deal with the actual syntax of the abstract class. For example, an abstract class cannot have a private virtual member, blah blah.

This article will try to explain the What and the When.

Understanding the Abstract Class

An abstract class is a class which cannot be instantiated, which means you cannot create an object of an abstract class, it can only act as a base class and other classes can derive from it. So what is the rationale behind the existence of a class if we cannot create an object of it?

Let’s take an example of a bank to explain this. Later, we will go through the code to implement it.

Suppose you go to a bank for opening an account. Let’s see below what transpires between an applicant and a bank staff.

Bank Staff: Welcome sir.

Applicant: I want to open an account.

Bank Staff: Sure sir, what kind of account do you want to open?

Applicant: I just want to open an account.

Bank Staff: Do you want to open a Savings Account or a Current Account?

Applicant: I do not want to open any specific account, just open an account.

Bank Staff: Sir, this is not possible, we need to create a specific type of account. Unless you tell me the type of the account, I cannot help you.

In the light of the above discussion, we come up with the below inference for our banking application software.

Banks have a facility to open an account

Bank account should be of a specific type (Saving/Current)

Bank cannot open a generic account

To explain this concept, let's create a banking application. This application is just for demonstration purposes and should not be used as a design guide.

Using the Code

We have a BankAccount class which is an abstract class for the reason explained above.

Irrespective of the type of account, there
are certain members/behaviors which are common to all types of accounts and thus should be part of the base class, in our case the BankAccount class.

Bank Account Common Members

Account Owner property will have the name of the account holder

Account Number uniquely identifies a bank account

Minimum Balance will have the minimum threshold for the account

Maximum Deposit Amount will have the maximum amount which can be deposited in one go

Interest Rate is required for all bank accounts

Transaction Summary records all the transactions taking place in an account

Bank Account Common Behavior

You can deposit money in it.

You can withdraw money from it.

There should be facility to calculate interest.

User can generate Report/ Summary to see the transactions.

Deposit and Withdraw: These are two abstract methods. It looks like Deposit/Withdraw functionality should be the same for a
SavingAccount and CurrentAccount but might
not always be as in our case. These methods are abstract because we want that the child class should give its own implementation. (These two methods however can also be created as virtual methods but for the sake of our demonstration, let them be abstract methods.)

The CalculateInterest() method is implemented in the abstract class and the child class will reuse this functionality,
clearly an advantage of an abstract class over an interface regarding code reuse:

Constructor: Though the BankAccount class is an abstract class,
it still has a constructor. What is the use of a constructor if an instance of
the abstract class
cannot be created? The constructor is used when we create an instance of SavingAccount or
CurrentAccount, so variables defined in the abstract class could be initialized using
the abstract class constructor. Remember that whenever a child class is instantiated,
the constructor of its base class is called first and then the derived class constructor is called.

Some of the fields are
protected and some are public, I have kept it like
that for no serious reason. TransactionSummaryis kept
protected so that only a child class should be able to see and change it.

The GenerateAccountReport()method will show the details of
the account including the transaction summary. It is a virtual method. By setting it
as virtual, we are declaring that any subclass can override it to give its own implementation; however,
the default implementation is provided by the base class.

Let's dig inside our child classes. The constructors of the SavingAccount as well as
CurrentAccount are initializing some variable as per their requirements,
however certain common variables are set by the abstract class, which explains the rationale behind the need of a constructor in
the abstract class.

The Withdraw and Deposit methods are pretty simple and need no detailed explanation. Both classes have overridden them to provide their own implementation.

The Deposit method of SavingAccount throws an exception if
the amount deposited is greater than a specified limit.

The Withdraw method of
SavingAccount checks the number
of withdrawals before throwing an exception.

The GenerateAccountReport method of
SavingAccount adds a report header, calls the base class method for the generic implementation,
and then sends the account report email.

To use the above code, here is a our
Main method which creates an instance each of a Saving and Current
account. The variable taken to store
these instance is of type BankAccount, thus allowing us to have polymorphic behavior.

When to Use Abstract Class

Let's go back to the example of our banking application.

Though we cannot open a generic account, all accounts will have
a certain member and behavior as discussed above.
Also, we want that all types of accounts should conform to these attributes and behaviors.

To summarize,
create an abstract class if:

Class expresses an idea which is too generic and whose
independent (alone) existence is not required in your application,
e.g., BankAccount.

There is a family of types forming a hierarchy. An “IS-A” relation exists between a base class and other derived classes. E.g.:

Saving Account IS-A Bank Account

Current Account IS-A Bank Account

If there are certain members/ behaviors which are common
to all classes, these should be placed inside the abstract class, e.g.,
AccountNumber, Deposit(), etc.

If there are behaviors/attributes which should be implemented or
must be present in all classes, declare them as abstract methods in the
abstract class, e.g., CalculateInterest().

Why Not
an Interface in Place of the BankAccount Class?

In our example, you can argue that we can use
a Interface instead of the BankAccount abstract class, something like shown below:

First of all, there is a hierarchy between BankAccount and SavingAccount and a close relation exists. Also, we are able to figure
out certain common features present in all the child classes,
thus an abstract class will help in code reuse. An interface is more of a contract between classes. There are
a lot of syntactical differences between an abstract class and an interface,
a little Googling may be of great help so I haven't touched it in this article.

Conclusion

I have explained what an abstract class is, how to use it, and when to use it with the help of an example.

It is abstract because, As a class I do not know the implementation details of the method but I am certain about its existence. Class may not know the logic of withdraw/deposit but as a bank account It needs to provide this functionality to its customer. how it will be done is left for the child classes. So abstract keyword enforces the child class that this functionality/implementation must exist.

Also timely - found it just when an Abstract class was what I needed to represent two different ways of calculating the same types of results from the same raw data. Had though of using an interface but Abstract allowed all the common methods and properties to be coded in the Abstract base class.

I loved the way you explained Abstract Classes..which is thought a very easy topic..yet people never implement it in a correct way. Hope with this article viewers will understand the correct usage of abstract class.
Great Work!!

In my opinion, your article started great.
The comparison with someone trying to open an account and requiring to choose an account type was the first time that a real world comparison made sense to me.

But then I think the article got a little confusing.
You have the IAccountReportGenerator. Personally, I don't see a reason to put this interface. We are already dealing with account classes. Anything related to the accounts can be there, without requiring an interface.
Also, even the words used seem a problem. It looks like you are adding a secondary responsibility to the account classes. It would be much better to use a ReportGenerator as something independent, that can then be used to generate reports for one account or the other.

But in fact, I don't think that's the main point. It simply seems that you lost focus, trying to show a good design with interfaces + abstract classes when the purpose was to show the abstract classes. So, I can't believe that someone that needs to understand what an abstract class is will understand this and get it right.

Hi Paulo, Your comment certainly makes sense and i also thought earlier to not use the IAccountReportGenerator in this example and now i am more of the opinion that it should have not been there. Should i remove that so that article can make much more sense.

I think that removing any reference to interfaces from the actual text (and of course, revising the text accordingly, not only removing those references) will really help.
I think that at the end you may briefly comment that who are interested may also look for interfaces, but I don't think it is worth trying to compare them here or try to use an interface, as this makes the article lose its focus.

Paulo, I removed the IAccountReportGenerator interface. I added a small comparision to interface in the end so that one can understand in this particular scenario why having interface would not make much sense, There is always a confusion between abstract class and interface. Full comparision however was never a part of the article, though i thought that a small reference to it in light of the exmaple shown above might be helpful.