Learn D Programming Lesson 10 - Inheritance
What is inheritance?
Inheritance is the ability of a class to inherit the characteristics of another class. A class that inherits from another class will have the same variables and functions that the class it inherited from has. The class that is being inherited from is often called the parent and the class that is inheriting from the parent is called the child. Sometimes the parent is called the super class or the base class and the child is called the sub class or the derived class.
Inheritance is important because it lets you share code instead of having to rewrite it all the time. Let's look at a bank account as an example. There are many types of bank accounts such as credit card accounts and cheque accounts. Both credit card accounts and cheque accounts are a type of bank account so they have certain things in common like a balance. They also each have things that are unique to them. In this example the bank account would be the parent class and the credit card account class would inherit from the bank account class and so would the cheque account class.
Using inheritance
We are now going to create the classes from the example above about the bank accounts. The first thing we need to do is create a parent class called BankAccount. The class should be created in a file called BankAccount.d. Here is the code for the BankAccount class which is just a simple class with a balance and two functions called Deposit and Withdraw.
import std.stdio;
class BankAccount
{
int balance;
void Deposit(int amount)
{
balance = balance + amount;
}
void Withdraw(int amount)
{
balance = balance - amount;
}
}
Next we will create a class called CreditCardAccount which should be saved in a file called CreditCardAccount.d and a file called ChequeAccount which should be saved in a file called ChequeAccount.d. Both of these classes will inherit from the BankAccount class. To inherit from a class you must use a colon(:) after the child class name declaration followed by the name of the class that is being inherited from. Remember that you have to import the BankAccount class to be able to use it. You will see that the two new classes are empty and that is because they inherit the balance variable and Withdraw and Deposit functions from BankAccount. Here is the code for them.
import std.stdio;
import BankAccount;
class CreditCardAccount : BankAccount
{
}
import std.stdio;
import BankAccount;
class ChequeAccount : BankAccount
{
}
The last thing we need is a test program. You can create the test program in a file called test.d. You will need to import both the CreditCardAccount class and the ChequeAccount class. Here is the code for the test program in which the two classes are instantiated and then the Deposit function is called on both of them and the balance is printed out to show you how they have been inherited from the BankAccount class.
import std.stdio;
import CreditCardAccount;
import ChequeAccount;
void main()
{
CreditCardAccount CcAcc = new CreditCardAccount();
ChequeAccount ChqAcc = new ChequeAccount();
CcAcc.Deposit(500);
ChqAcc.Deposit(1000);
writefln(CcAcc.balance);
writefln(ChqAcc.balance);
}
The protected access modifier
In the previous lesson you learnt about the public keyword which makes things accessible from anywhere and the private keyword which hides things from other classes. There is a keyword called protected which is half way between private and public because it hides things from other parts of the program but it doesn't hide them from any class that inherits from the class. For example in the BankAccount class we might not want other classes to be able to access the balance but the CreditCardAccount and ChequeAccount classes definitely do need access to the balance. Here is the code for the BankAccount class again with the balance changed to protected and you will find that the program won't compile anymore because the test program is no longer allowed to access the balance.
import std.stdio;
class BankAccount
{
protected int balance;
void Deposit(int amount)
{
balance = balance + amount;
}
void Withdraw(int amount)
{
balance = balance - amount;
}
}
Polymorphism
Polymorphism is the ability of a class to be used as if it were the same as its parent class or any class in its inheritance hierarchy. When the child is used as its parent class then only the variables and functions of the parent class are available for use. To understand it better we need to look at an example followed by an explanation.
import std.stdio;
import CreditCardAccount;
import ChequeAccount;
import BankAccount;
void main()
{
CreditCardAccount CcAcc = new CreditCardAccount();
CcAcc.Deposit(100);
ChequeAccount CheqAcc = new ChequeAccount();
CheqAcc.Deposit(200);
BankAccount account1 = CcAcc;
BankAccount account2 = CheqAcc;
writefln(account1.balance);
writefln(account2.balance);
}
In this example a CreditCardAccount is created and a ChequeAccount is created and they both have some money deposited in them. A bank account is declared and its value is set to the CreditCardAccount and another BankAccount is declared and it is set to the value of the ChequeAccount. That is where polymorphism has just happened because the 2 child classes have been made to look like BankAccounts and it is possible because they both inherit from BankAccount. It is on the other hand not possible to set the value of a CreditCardAccount to a ChequeAccount because it doesn't inherit from CreditCardAccount. The last part of the program prints out the balances of the accounts while still using them as BankAccounts.
Abstract classes
An abstract class is a class that is created only for inheriting from and is not meant to be instantiated. A good candidate for an abstract class is our BankAccount class because we created it only for the reason of allowing the CreditCardAccount and the ChequeAccount to inherit from it. It is possible to not bother making the BankAccount class abstract and everything will still work fine just like it has been doing for us all along but it is better to make it abstract so that you don't instantiate it by mistake. The only thing you have to do to make a class abstract is to put the abstract keyword in front of the class name. Here is the abstract version of the BankAccount.
import std.stdio;
abstract class BankAccount
{
int balance;
void Deposit(int amount)
{
balance = balance + amount;
}
void Withdraw(int amount)
{
balance = balance - amount;
}
}
After making BankAccount abstract you will get an error message when compiling a program that tries to instantiate it using a line of code like the following.
BankAccount account = new BankAccount();
You can also make a function abstract but in that case it has a different meaning to an abstract class. An abstract function must be implemented in any class that inherits from the class it is in. The BankAccount class has a function called Withdraw which would make a good abstract function because withdrawing money from a credit card account and withdrawing money from a cheque account have different rules and so should be implemented differently. The CreditCardAccount class should check both the balance and the credit limit when money is withdrawn but the ChequeAccount class only needs to check the balance. Since all classes that inherit from the class with the abstract function in it have to implement the function it means that the abstract function doesn't have to contain any code and a semi-colon replaces the curly brackets. Here is the code for the 3 classes using an abstract function.
import std.stdio;
abstract class BankAccount
{
int balance;
void Deposit(int amount)
{
balance = balance + amount;
}
abstract void Withdraw(int amount);
}
import std.stdio;
import BankAccount;
class CreditCardAccount : BankAccount
{
void Withdraw(int amount)
{
int CreditLimit = 5000;
if (amount < balance + CreditLimit)
balance = balance - amount;
else
writefln("You have gone over your credit limit");
}
}
import std.stdio;
import BankAccount;
class ChequeAccount : BankAccount
{
void Withdraw(int amount)
{
if (amount < balance)
balance = balance - amount;
else
writefln("There is not enough money in the account");
}
}
Interfaces
An interface is something that forces any classes that inherit from it to have to implement certain functions or variables. Functions must not be implemented in an interface because they are always implemented in the classes that inherit from the interface. An interface is created using the interface keyword instead of the class keyword even though the two are similar in a lot of ways. When you want to inherit from an interface and the class already inherits from another class then you need to separate the name of the class and the name of the interface with a comma.
We are going to create an interface called AccountTypeInterface in a file called AccountTypeInterface.d and it will contain a function called GetAccountType. The CreditCardAccount class and the ChequeAccount class will both inherit from AccountTypeInterface and they will both implement the GetAccountType function. In the test program we will declare an interface and set its value to each of the accounts one at a time and call GetAccountType. Here is the code for the interface and the classes.
interface AccountTypeInterface
{
string GetAccountType();
}
import std.stdio;
import BankAccount;
import AccountTypeInterface;
class CreditCardAccount : BankAccount, AccountTypeInterface
{
void Withdraw(int amount)
{
int CreditLimit = 5000;
if (amount < balance + CreditLimit)
balance = balance - amount;
else
writefln("You have gone over your credit limit");
}
string GetAccountType()
{
return "Credit Card Account";
}
}
import std.stdio;
import BankAccount;
import AccountTypeInterface;
class ChequeAccount : BankAccount, AccountTypeInterface
{
void Withdraw(int amount)
{
if (amount < balance)
balance = balance - amount;
else
writefln("There is not enough money in the account");
}
string GetAccountType()
{
return "Cheque Account";
}
}
import std.stdio;
import CreditCardAccount;
import ChequeAccount;
import BankAccount;
import AccountTypeInterface;
void main()
{
CreditCardAccount CcAcc = new CreditCardAccount();
ChequeAccount CheqAcc = new ChequeAccount();
AccountTypeInterface ATInt = CcAcc;
writefln(ATInt.GetAccountType());
ATInt = CheqAcc;
writefln(ATInt.GetAccountType());
}
Have a look at the code in the test program. It uses the AccountTypeInterface twice but it only declares it once. There is a type of polymorphism going on here and it is what makes interfaces so powerful. You may not fully understand it now but interfaces are very important and you will see how powerful they are when you learn about things like design patterns but for now you only need to be aware of their existence and how to use them.
Practice
Use the banking system classes from this lesson and change the main program to be more like an ATM. Your program should have a nice menu that asks you if you want to deposit money, withdraw money or get your current balance. You can use your imagination if you like and add a whole lot of other features and bank account types.
- Learn D Programming Lesson 1 - Getting started
- Learn D Programming Lesson 2 - First program
- Learn D Programming Lesson 3 - Variables
- Learn D Programming Lesson 4 - More on strings
- Learn D Programming Lesson 5 - Decisions
- Learn D Programming Lesson 6 - Loops
- Learn D Programming Lesson 7 - Arrays
- Learn D Programming Lesson 8 - Functions
- Learn D Programming Lesson 9 - Classes
- Learn D Programming Lesson 10 - Inheritance