PreviousNext

Binding by Object Reference to Use a Different Interface

We defined our overdraft savings account to be derived from two different interfaces (see the following figure). However, the client does not have any knowledge of how a server implements the overdraft account. The client does have a way to create an overdraft account by calling the static function openOverdraft( ), but that is defined in the Savings interface which has no access to the Loan interface. So how does an overdraft object inquire about its loan balance by using the Loan interface's getLoanBalance( )member function, when the object reference is to the Savings interface? We obviously cannot simply create another object reference to the Loan interface and expect the two different object references to both refer to the same overdraft object.


Clients Do Not Know About Server Implementations

The solution is to use an idl-generated member function. When the IDL compiler generates the interface classes, it also generates an additional bind( ) member function that allows the client to easily use other interfaces. The following examples show sample client code that creates and uses a new simple savings account object and an overdraft account object:

#include "savings.h"
#include "loan.h"

Account *a = 0;
Savings *ss = 0;
Savings *od = 0;
Loan *iLoan = 0;

The interface classes are declared in the header files generated by the IDL compiler as follows:

ss = Savings::openSimple(456.12);
od = Savings::openOverdraft(568.19);

In this example, the client creates a new simple savings account object on a server by calling the openSimple( ) function. The function creates an object reference to the Savings interface. The client also creates a new overdraft account object on a server by calling the openOverdraft( ) function. This function also creates an object reference to the Savings interface.

A robust server would likely give clients a way to find accounts again later by making the objects named and persistent; but, to simplify our examples, we use only dynamic objects. Therefore, accounts must be recreated each time a client runs.

balance = ss::getSavingsBalance();
assert(balance == 456.12);
balance = od::getSavingsBalance();
assert(balance == 568.19);

Object references to the Savings interface can call any member functions of the Savings and Account interfaces as follows:

iLoan = Loan::bind(od);

To use a different interface, clients use the built-in bind( ) member function with an object reference parameter. In this example, the function creates an object reference to the Loan interface, iLoan, from the object reference to the Savings interface, od:

balance = iLoan->getLoanBalance();
cout << "Loan Balance: " << balance << endl;

The object can now call any member function of the Loan interface as follows:

ss->deposit(20.01);

An object reference to one interface can access member functions of its inherited interfaces, as expected. In this example, ss is an object reference to a Savings object, but the deposit( ) function is specified in the Account interface:

balance = ss->getAccountBalance();
cout << Balance: " << balance << endl;
a = Account::bind(ss);
balance = a->getAccountBalance();
cout << Balance: " << balance << endl;

As an aid to debugging, it is a good idea to use the interface in which the operation is declared, even if the inherited operation can be resolved. When the object calls getAccountBalance( ) with a Savings object reference, the function is executed in the client stub for the Savings interface. On the other hand, when the same function is called with an Account object reference, the Account client stub function is executed.