C++ allows the use of multiple inheritance, where one class can have more than
one base class. Remember back to the Transaction
, Lodgement
and Withdrawal
classes that we discussed previously. If we wished to
create a FundsTransfer
class, it would have properties of both a
Lodgement
and a Withdrawal
. So the following structure
could be devised, as in Figure 3.16, “Multiple Inheritance with the FundTransfer
class.”.
This is a valid structure as a Lodgement
IS A Transaction
, a
Withdrawal
IS A Transaction
and at different times
during execution a FundTransfer
IS A Lodgement
and
a Withdrawal
.
Two separate Transaction
objects are being created, and they do not
interfere with each other (they have their own state).
When using these Transaction
objects you must be careful to resolve the ambiguity
that results from having two objects of the same class. Suppose, a method was written in the
FundTransfer
class to calculate the time taken for the physical cash
transfer to take place (the time between the withdrawal and the lodgement), you could use a code segment
like:
class FundTransfer: public Lodgement, public Withdrawal { private: // states.. public: virtual int getTimeTaken() { return ( Lodgement::timeOfTransaction - Withdrawal::timeOfTransaction ); } };
In this segment of code the multiple parents are comma separated and the getTimeTaken()
returns the time taken as an int (could be milliseconds). In this method, the ambiguity
is resolved between the two timeOfTransaction
states that are inherited by the
FundTransfer
class, by specifying the parent that resulted in the inheritance of
that state. So, Lodgement::timeOfTransaction
is the timeOfTransaction
state inherited through the Lodgement
parent.
A common base class may not be inherited twice!
This same notation may be used to resolve ambiguity when referring to the class directly. If the
Transaction
had a display()
method, and it was to be
called directly, we could use:
FundTransfer *fundPtr; fundPtr -> display(); // not allowed - ambiguous fundPtr -> Lodgement::display(); // OK! fundPtr -> Withdrawal::display(); // OK!
This is awkward and does not give us an appropriate level of abstraction. It would be more appropriate to
declare a new display()
method in the FundTransfer
class
to avoid this ambiguity.
In the previous example it made sense to have two individual Transaction
objects, each with its own state, otherwise it would not have been possible to calculate the time
taken. This is not always the case. For example:
If the task was to create a special Current Account that had all the
benefits of a Deposit
account and all the benefits of a Current
account, then a structure as shown in Figure 3.17, “Multiple Inheritance with the CashSave
class.” could be devised. We could
call this class CashSave
(nothing to do with AIB at all! ;-)).
Since Account
contains the balance
state,
and CashSave
is a type of
Account
, we do not want the balance
state to be
duplicated - having two different balance
states! To fix this the
CashSave
class should only have one instance of its common indirect
base class. This can be achieved by declaring the base class to be virtual
.
class Current: public virtual Account { // etc.. }; class Deposit: public virtual Account { // etc.. }; class CashSave: public virtual Current, public virtual Deposit{ // etc.. virtual is not required here! };
In effect, we are declaring that if either the Current
class
or the Deposit
class should be used in a multiple inheritance hierarchy, then
they should share the same instance of
the Account
class with any other class that has virtual inheritance of
Account
.
So, this simple alteration to the parent results in a shared parent object. The only difficulty with this
design is that the alteration must be made when the Current
and Deposit
classes are being designed. The programmer/designer must therefore be aware of child classes that are to be created
in the future. This is not always possible as the marketing department may not have concieved of a "Cashsave" account
until many years after the original design.
Now that we have an example of a virtual base class, remember to use a dynamic_cast
in this
case.
© 2006
Dr. Derek Molloy
(DCU).