Inheritance
What is Inheritance?
Unlike most concepts in OOP, inheritance is pretty straight forward and easy to understand. People tend to think of things in terms of groups and how each group is related. When we look at a car we don't think "steel, rubber, bolts, engine, steering wheel", our brain just tells us we are looking at a car. At the same time our brain automatically creates a relationship between all of the components of an object and puts the object into a category. This relationship between objects is described as an "is a" relationship. A Ford Pinto "is a" car. Don't confuse this with what the car is made up of, that is called a "has a" relationship. A car "has" steel, rubber, bolts, and an engine. Enough with the psychology, right?
OK, So WHAT is Inheritance!?
In assignment 3 you have to create a bank account using inheritance. Let's use this as our example, though I will not implement any of the member methods. First we need to define BankAccount:
|
class BankAccount { public: //constructor BankAccount(int = 0); //takes in a starting account balance, default is 0 //accessor int GetBalance(){ return balance; } //behavior void Deposit(int); private: int balance; }; |
By now you should be quite familiar with this setup. We have a constructor with default parameters, a private member called balance to hold the money, an accessor for the balance, and a behavior to deposit money. This is going to be the "base class", sometimes called the "parent class" or "super class". In a moment we will define the MoneyMarketAccount class which will be the "derived class", or "child class" as it is also known. A base class is simply a class that gets inherited from and the derived class is the class that receives the functionality of the inherited class. Let's see how it works.
|
class MoneyMarketAccount:public BankAccount { public: //constructor MoneyMarketAccount(int = 0, int = 500, float = 2.5); //takes in a starting account balance, minimum balance and interest rate //behavior void AddInterest(); private: int minimum_balance; float interest_rate; }; |
Look's just like a regular class right? The only thing that is different is the first line:
|
class MoneyMarketAccount : public BankAccount |
This simply means MoneyMarketAccount derives or inherits from BankAccount. Don't forget to put public before the class you are inheriting from.
Money Money Money Money
MoneyMarketAccount now has the members AddInterest(), minimum_balance, interest_rate which are defined in its header. It also has access to GetBalance(), and Deposit() from BankAccount. It does NOT have access directly to balance from BankAccount because balance is in the private section (more on this in a moment). Now we should take a look at the constructor for MoneyMarketAccount:
|
MoneyMarketAccount::MoneyMarketAccount(int start_amt,
int min_bal, float rate):BankAccount(start_amt) { minimum_balance = min_bal; interest_rate = rate; } |
Yikes! That first line looks a little intimidating but let's break it down.
We should recognize the following part, it just means we are implementing the constructor for MoneyMarketAccount:
| MoneyMarketAccount::MoneyMarketAccount |
Here are the parameters as defined in the header for MoneyMarketAccount:
| MoneyMarketAccount::MoneyMarketAccount(int start_amt, int min_bal, float rate) |
Now we get to something new:
|
MoneyMarketAccount::MoneyMarketAccount(int start_amt,
int min_bal, float rate):BankAccount(start_amt) { minimum_balance = min_bal; interest_rate = rate; } |
Way back in BankAccount we defined the BankAccount constructor to take in an int. It is the job of the derived class to make sure that value gets to the base classes constructor. That is all that is happening here. Notice that in the implementation of MoneyMarketAccount's constructor (code above) the only two incoming values that are used are min_bal and rate. start_amt is simply passed off to BankAccount to let its constructor handle the variable.
Now let's create an instance of MoneyMarketAccount so we can see what it can do:
|
void main(void) { //create a new MoneyMarketAccount with a $200 starting value and default values for the rest MoneyMarketAccount account(200); //use BankAccount's GetBalance accessor cout << account.GetBalance() << endl; //use MoneyMarketAccount's AddInterest behavior account.AddInterest(); } |
The Evils of Public and Private
Great! We get to use BankAccount's members without having to rewrite a ton of code. Now for the bad news. You know that you will have to implement the AddInterest method in MoneyMarketAccount. In this method you will need direct access to BankAccount's balance member so that you can make sure the account has enough money and also you will need to modify balance to add any interest to it. There is a big problem here, right now balance is contained in the private section of BankAccount and ONLY BankAccount has direct access to. Here is an example of what will NOT work as the code stands now:
|
//incomplete implementation of
AddInterest
void MoneyMarketAccount::AddInterest() |
There are a few solutions to this. The WRONG way would be to move balance to the public section of BankAccount. This is not a good idea because it would break the encapsulation of BankAccount. The RIGHT way would be to learn a new keyword: protected. Protected is similar to private in that it does not expose class members to areas outside of the class, but it still allows "derived" classes the same access to the member as the "base" class. This is exactly what we need! Let's modify our definition of BankAccount to reflect our new understanding of inheritance:
|
class BankAccount { public: //constructor BankAccount(int = 0); //takes in a starting account balance, default is 0 //accessor int GetBalance(); //behavior void Deposit(int); protected: //derived classes can access protected members... int balance; }; |
Much nicer! Hopefully you understand inheritance a little better. Remember, just like all things in OOP it is more important to understand the concepts rather than the syntax. Read over this lab again if you are still confused BEFORE you start trying to code up the project. Also, you may note that I used ints in for some of the members, they should really all be floats so they can hold dollars AND cents. Good luck!