PreviousNext

Multiple Interfaces and Interface Inheritance

Objects in useful applications are organized into groups (using classes) and hierarchies in order for people to more easily develop and maintain them. For the same reason, you use more than one IDL interface to logically group the objects and functionality of your applications. In addition, you can organize your interfaces into hierarchies that take advantage of the inheritance capabilities of C++ classes.

This discussion uses a traditional savings account example, as shown in the class hierarchy diagram of the following figure. First there is a high-level Account interface and then a Savings interface derived from the Account interface. The Account interface is specified separately from the Savings interface for the basic operations all accounts might have and to show how interface inheritance works. With this scheme, we can easily specify other kinds of accounts by using additional interfaces. (For example, we could also have a Checking interface.) Our example also has a separate Loan interface to show how to combine interfaces in applications. In the implementation of these interfaces, we derive a simple savings account class (simpleSave) from the savings interface, and we derive an overdraft-protected savings account class (overdraft) from both the savings and the loan interfaces.


Multiple Interfaces and Inheritance

The Account interface contains the most basic operations for accounts, including one to obtain the account's balance, one to make deposits, and one to make withdrawals. This interface definition is as follows:

[
uuid(b3896a1c-8ee2-11ce-badc-08002b2bf322)
] interface Account
{
double getAccountBalance();

double deposit( /* Value returned is the balance. */
[in] double amt
);

double withdraw(/* Value returned is actual amount withdrawn */
[in] double amt
);
}

Use the inheritance operator, :, in an interface definition to specify interface inheritance. In the following example, the Savings interface inherits operations from the Account interface. (Depending on your perspective, you can also say the Savings interface is derived from the Account interface.) When an interface inherits another, it also uses the import statement to be sure the operations and any data types of the inherited interface are available to the derived interface. The Savings interface definition is as follows:

[
uuid(b388ab7c-8ee2-11ce-badc-08002b2bf322)
] interface Savings : Account
{
import "account.idl";

static Savings * openSimple(
[in] double amt
);

static Savings * openOverdraft(
[in] double amt
);

double getSavingsBalance();

void setInterestRate(
[in] double rate
);

void addInterest();
}

The openSimple( ) and openOverdraft( ) static operations are object creator operations used to create new accounts on a server. Notice that the Account interface has no creator operations specified. This means that clients cannot create an Account object directly, but servers of course can. The non-static operations for the Savings interface include one to get the savings account balance (getSavingsBalance( )), one to set the interest rate (setInterestRate( )), and one to add the interest to the balance of the account (addInterest( ))

In this application, we have decided that our server implements the overdraft account with a Loan interface. (Note we could have chosen to implement it in another way, and without an additional interface.) The Loan interface is not derived from another interface and is shown in the following example:

[
uuid(912ef43d-8ee2-11ce-a54e-08002b2bf322)
]
interface Loan
{
static Loan * openLoan(
[in] double amt,
[in] double rate,
[in] long months,
[out] double &payment
);

double getLoanBalance();

void payment(
[in] double amt
);

double recalculateLoan( /* returns payment amount required */
[in] double rate,
[in] long months
);
}

The openLoan( ) operation is a static object creator operation to create a loan object. The getLoanBalance( ) operation gets the current balance of the loan and the payment( ) operation is used to make a payment on the loan. The recalculateLoan( ) operation sets new terms for the loan and returns the new monthly payment required.

There are no special techniques to follow in server initialization code except be sure that whatever is required for an individual interface is done for each interface your application uses. For example, the initialization code must be sure to register the endpoints for all interfaces.

More:

Implementing Multiple Managers

Using Objects that Support Multiple Interfaces