Programmer's Corner - Object-Oriented Programming (OOP) Tutorial - Example - Abstract Class

Backup and Security Solutions 10% off all products with promo code: VISI-P1YR
Get the Programmer's Corner FireFox Search Plug-In

Abstract Class Example

You may have noticed that the bank account example we did had some similar code in both the SavingsAccount and CheckingAccount. Since we used interfaces we could not have that code in the BankAccount interface because  interfaces do not allow that. Now we can do it with an abstract class and have the common code in that class. So we can inherit the abstract class and add what we need to make it a specific account. This example we will do just that.

Open Visual Studio .NET and create a new Console Application called BankAccount2. Since this example is going to be quite different we will start from scratch. To begin add a new class called BankAccount. Again to make abstract you use the keyword "MustInherit".

Public MustInherit Class BankAccount

End Class

We will keep the same properties and methods as the interface had only now we can also put code in them. The BankAccount interface had properties, AccountNumber and Balance, and methods, Debit and Credit. Now comes the decisions of what the abstract class will do. Generally it has code that will be the same in all child classes (classes that inherit it) and forces what isn't common to all be overridden.  You could supply suggested code and allow child classes to override it if you wish.

Lets examine SavingsAccount and BankAccount from the previous example to see what is common to both so we can put it in the abstract BankAccount class. AccountNumber, Balance, and Credit are all identical and would likely be the same in any child class. So lets put it in the BankAccount class.

Private mdblBalance As Double
Private mintNumber As Integer

Public Property AccountNumber() As Integer
    Get
        Return mintNumber
    End Get
    Set(ByVal Value As Integer)
        If mintNumber = 0 And Value > 0 Then
            mintNumber = Value
        End If
    End Set
End Property

Public ReadOnly Property Balance() As Double
    Get
        Return mdblBalance
    End Get
End Property

Public Sub Credit(ByVal Amount As Double)
    If Amount > 0 Then
        mdblBalance += Amount
    End If
End Sub

None of the above need the "Implements" any more since we are not implementing an interface.

As before the Debit function is a little different in SavingsAccount and CheckingAccount. This brings us to a bit of a snag. Since mdblBalance is private we do not have access to it and therefore cannot directly change it. Since the Balance property is ReadOnly we cannot use it to change mdblBalance either. So what do we do? Well there are two options that come to mind. One is to supply a default Debit function which would look exactly like the CheckingAccount, overriding it in SavingsAccount to check to see if they have enough money and if they do call the Debit function in BankAccount. The other is to make mdblBalance "Protected" in scope. Protected means anything inside the same class or any derived (child) class can access it directly.

In order to keep mdblBalance Private we need to declare an overridable Debit function that has the same code as the Debit function in CheckingAccount. If you want to go the Protected way then a simple MustOverride Debit function will do.

Public Overridable Function Debit(ByVal Amount As Double) As Boolean
    If Amount > mdblBalance Then
        Return False
    Else
        mdblBalance -= Amount
        Return True
    End If
End Function

' Or

Protected mdblBalance As Double

MustOverride Function Debit(ByVal Amount As Double) As Boolean

Now lets create the new SavingsAccount and CheckingAccount by adding two classes with those names

Public Class SavingsAccount
    Inherits BankAccount

End Class

Public Class CheckingAccount
    Inherits BankAccount

End Class

Lets start with the CheckingAccount class. If you have the overridable Debit function then you are done! Seriously there is no code needed because it is already in the BankAccount class. If you went the Protected way then you must declare the Override Debit function directly manipulating mdblBalance.

Public Overrides Function Debit(ByVal Amount As Double) As Boolean
    If Amount > 0 Then
        mdblBalance -= Amount
        Return True
    Else
        Return False
    End If
End Function

Now for the SavingsAccount either way you will have to have override Debit function. If Debit is overridable then we will override it checking to see if they have enough money before we debit. If they do we will call the Debit function the BankAccount (the base class). If Debit is "MustOverride" (the Protected way) then it will look similar to the CheckingAccount only first making sure there is enough money.

Public Overrides Function Debit(ByVal Amount As Double) As Boolean
    If Amount > 0 Then
        If MyBase.Balance < Amount Then
            Return False ' not enough money in account
        Else
            MyBase.Debit (Amount)
            Return True
        End If
    Else
        Return False ' amount isn't positive
    End If
End Function

' Protected way

Public Overrides Function Debit(ByVal Amount As Double) As Boolean
    If Amount > 0 Then
        If mdblBalance < Amount Then
            Return False ' not enough money in account
        Else
            mdblBalance -= Amount
            Return True
        End If
    Else
        Return False ' amount isn't positive
    End If
End Function

One final thing is the constructors (Public Sub New()). Unlike the interface these can be defined in the abstract class and can have code in them. SavingsAccount and CheckingAccount both have two constructors and one of them had no parameters which set mdblBalance to zero. Since they are both the same it can be moved into the BankAccount abstract class. The constructor that took in the starting balance is going to be different in SavingsAccount and CheckingAccount depending on whether you made mdblBalance protected or not.

' BankAccount constructor with no parameters
Public Sub New()
    mdblBalance = 0
End Sub

' Private mdblBalance As Double
' SavingsAccount
Public Sub New(ByVal StartAmount As Double)
    MyBase.>New()
    If StartAmount > 0 Then
        MyBase.Credit (StartAmount)
    End If
End Sub

' CheckingAccount
Public Sub New(ByVal StartAmount As Double)
    MyBase.New()
    MyBase.Credit (StartAmount)
End Sub

' Protected mdblBalance As Double
' SavingsAccount
Public Sub New(ByVal StartAmount As Double)
    mdblBalance = 0
    If StartAmount > 0 Then
        mdblBalance = StartAmount
    End If
End Sub

' CheckingAccount
Public Sub New(ByVal StartAmount As Double)
    mdblBalance = StartAmount
End Sub

Now time to test. If you copy the code from the module in the Class & Interface Example Executable and run the program it should work exactly the same.

So Abstract class or Interface? It all depends on the situation. The only main difference is an Abstract class can have code. If you want a variable to have at least a certain properties and methods and don't want to supply any code then make an interface. If you see code that is common to all derived classes then make it abstract.

Congratulations you have completed the Abstract Class Example.

Author Information:

Adam Schentag

http://www.programmers-corner.com

adam@programmers-corner.com

Comments:

Add your comments here.

Name

Comment

You can also send feedback to feedback@programmers-corner.com

There are currently no comments available.