Inheritance is one of the most powerful tools in the Object Oriented Programming Style (OOPS)

It is one (of a number) of techniques for making code reusable

It allows one to extend a piece of existing code by specialising it.

It models a very particular kind of relationship between classes known as polymorphism. This is often known as the "is-a" relationship.

Consider two of the classes we have been working with recently. Account and User

Both are representative of a kind of generic category. Consider the table below.

General Class
Account
User
Specialty Classes
Savings Account
Undergraduate
 
Checking Account
Graduate
 
Line of Credit
Faculty

Savings and checking accounts and lines of credit are all special kinds of accounts. They all share common characteristics, such as a balance and an ability to put money in or take it out.

But they all have special characteristics as well. Lines of credit normally have negative balances and large overdraft limits, while savings accounts pay interest.

Similarly, different kinds of computer accounts have different policies applied to them. For example, in our institition, undergraduates pay for printing while faculty don't. Graduate students fall in between, getting an allocation large enough to do a thesis, but paying if they exceed the allocation.

This kind of organization scheme is quite general.

Remember that, at bottom, classes represent categories.

Human categorization of knowledge is not confined to single categories.

Rather we use sub categories and more sub categories, organizing knowledge into hierarchies.

Thus human beings are hominids which are primates which are mammals

That is humans are a kind of hominid which in turn is a kind of primate which is a kind of mammal.

All mammals have warm blood.

All primates have large brains and opposable thumbs. As mammals they also have warm blood. (In the OOPS world we would say they inherit the characteristic of warm bloodedness.)

All hominids walk on two legs. (They also have opposable thumbs and large brains, because they are primates, and warm blood because primates are mammals.)

Humans have a soft palate. (They also walk on two legs because …but you get the picture)

In OOPS, a sub-category is called a sub-class. And objects of sub-classes inherit all the attributes and methods of their super class(es).

Before turning our attention to Users and Accounts let's look at a very simple minded system.

This system forms a hierarchy with three generations.

You can think of A as the grandparent, B as the parent and C as the child.

We say that bObj is a B (an object of class B). But it is also an A.

Likewise, cObj is a C as well as a B as well as an A.

Thus an object of class C has five attributes (its own z plus y1 and y2 from B and x1 and x2 from A)

And it has three methods (its own cFunc() plus bFunc() from B and aFunc() from A).

We have also introduced a new access modifier, protected.

Protected members of a class are accessable to sub-classes of the class but not to the outside.

Here is the implementation code for the three methods declared in the classes A, B and C.

the code in the implementation for cFunc()

Access Modifiers

Let's look at our simple hierarchial class declarations one more time

Note that the syntax

class B : public A

means that class B is publicly derived from A

It is also possible to derive a class privately from another.

To see what that means consider the following table:

Access in Base Class Access Modifier Access in Derived Class
public public public
private public can't access
protected public protected
   
public private private
private private can't access
protected private private

Notice that the derived class cannot loosen the security defined by its parent. It can only tighten it.

Thus public members stay public if publically derived but become private if privately derived.

Private members of the parent class are inaccessable by children.

Protected mebers of the parent class stay protected if publicly derived but become private if privately derived.

What variables may john(), george() & alice() access?

What access is permitted for the objects of classes A, B & C?

Extending Class Account

Let's apply these ideas to extending class Account to Savings Accounts and Checking Accounts. Here is the Accounts class as we left it.

When you start to think in terms of a hierarchy of classes, it is best to rethink them from scratch.

First, what is common to all accounts? That's what should go into the base class.

The base class is quite stripped down. It just has a balance and four functions.

Moreover, the names of deposit and withdraw have been changed to the more generic credit and debit (which are better terms for charge accounts, like VISA).

These functions are implemented in a very generic way

Now let's look at extending Account to checking accounts.

Checking is publicly derived from class Account. It adds the notion of minimum balance as well as various charges.

It over-rides the debit function because the generic one can't do the job. But not the credit function because the generic one in Account works just fine.

Notice, however, all the charges are static. This means that there is one set of charges for all Checking account objects.

The member functions to set charges are also static. What does this mean?

After all there's only one actual member function for a whole class anyway.

Static functions are called with respect to the whole class not a particular object of the class. That is to invoke setRate for the Checking class I would write

Checking::setRate(.02);

The real benefit of this is that we don't have to create any Checking objects before invoking the function.

With regular member functions, you must have an object before you can call the function.

Here's the extension to savings accounts

It's quite similar but the policies will be different. For example there is no bool odAllowed attribute because no savings accounts are ever allowed to go into overdraft.

Here is the implementation code for Checking objects.

Note that the debit function is much more complex than the one in Account since it has to take both charges and overdrafts into account.

Finally here is some code that utilizes the various kind of accounts.

Pay particular attention to the constructor calling sequences (by stepping into them in the TM)

Extending Class User

Our User class created a very simple model of computer users.

Now let's extend it to deal with different kinds of users—faculty & students—by first grouping what is common about the two in a single User class

Then derive the two new classes from this base class. First we have to change the base class a little

The only change is to use the new access control protected where we had private before. This allows the class to be extended, giving member functions of derived classes direct access to this data.

Specialization to Student

Students have id numbers and they have to pay for printing so two attributes have been added—

mId records their id

mPrintPennies keeps track of how much money they have in their print accounts

a number of operations have been included to handle these extra attributes.

Constructor Chaining

Recall that a Student object is a User object so that constructing a Student object also implies constructing the User part of it. The constructors are chained.

when a Student object is constructed its User part must be constructed first.

That is, declaring a Student object

  1. invokes the Student constructor which in turn
  2. invokes the User constructor which, when it has finished
  3. returns to the Student constructor which then does its initialization

As you can see, the Student constructor takes four arguments. Three of them, however, are needed by the User constructor. How do they get passed along?

One again the answer is to employ an initializer list

Here we show the User constructor, which as was seen previously, uses an initializer list to pass arguments on to the various MyString constructors.

Displayed right after it for comparison is the Student constructor.

It uses the initializer list to pass the three arguments needed by the User constructor

As well as to pass the id string to the MyString constructor to build the mId object

Finally, in the body of the constructor, the allocation and number of print pennies are initialized.

Constructor Chaining for Class User

(The arguments are actually passed as pointers. We show strings pointed at for clarity)

Specialization to Faculty

Faculty members get free printing but a record of total pages is kept. It can be cleared from time to time so the record is actually the number of pages printed since the last clearing date.

This requires the addition of attributes

mPages which tracks pages

mCleared which is a MyString object which records the last time pages were cleared

plus new functions for manipulation.

The constructor issues are similar to those for class Student.

Here is a little bit of driver code to try it out.

Use the Teaching Machine to step through the constructor chains when objects of class Student and Faculty get declared.

Again, watch how automated the process is.

We take care of implementing the code correctly.

The compiler worries about which constructors have to be called when.

Copy Constructor Chaining

Copy constructors for base classes are chained just like regular constructors. For example, suppose that we needed an explicit copy constructor for both User and Student (we don't). Then the implementation of the Student copy constructor would go as follows:

Student::Student(const Student& original) : User(original) {
	// Extra code for student copy construction goes here
}

Again, the idea is to reutilize the copy constructor code for the User object, then just add whatever extra is needed to copy construct a Student object.

If the copy constructor code for Student is to be written from scratch, simply omit the initilizer invocation of User.

 

Examples in Full