Previous Table of Contents Next


3.8.5 Interface Inheritance


   An interface can be derived from another interface, which is then called a base interface of the derived interface. A derived interface, like all interfaces, may declare new elements (constants, types, attributes, exceptions, and operations). In addition, unless redefined in the derived interface, the elements of a base interface can be referred to as if they were elements of the derived interface. The name resolution operator (“::?) may be used to refer to a base element explicitly; this permits reference to a name that has been redefined in the derived interface.

   A derived interface may redefine any of the type, constant, and exception names that have been inherited; the scope rules for such names are described in Section 3.20, “Names and Scoping,? on page 3-67.

   An interface is called a direct base if it is mentioned in the <interface_inheritance_spec> and an indirect base if it is not a direct base but is a base interface of one of the interfaces mentioned in the <interface_inheritance_spec>.

   An interface may be derived from any number of base interfaces. Such use of more than one direct base interface is often called multiple inheritance. The order of derivation is not significant.

   An abstract interface may only inherit from other abstract interfaces.

   An interface may not be specified as a direct base interface of a derived interface more than once; it may be an indirect base interface more than once. Consider the following example:

   interface A { ... }interface B: A { ... }interface C: A { ... }interface D: B, C { ... }interface E: A, B { ... }; // OK

    The relationships between these interfaces is shown in Figure 3-1. This “diamond? shape is legal, as is the definition of E on the right.


   DD

   Figure 3-1 Legal Multiple Inheritance Example

   References to base interface elements must be unambiguous. A Reference to a base interface element is ambiguous if the name is declared as a constant, type, or exception in more than one base interface. Ambiguities can be resolved by qualifying a name with its interface name (that is, using a <scoped_name>). It is illegal to inherit from two interfaces with the same operation or attribute name, or to redefine an operation or attribute name in the derived interface.

   So for example in:

   interface A {

   typedef long L1;

   short opA(in L1 l_1); };

   interface B {

   typedef short L1;

   L1 opB(in long l); };

   interface C: B, A {

   typedef L1 L2; // Error: L1 ambiguous

   typedef A::L1 L3; // A::L1 is OK

   B::L1 opC(in L3 l_3); // all OK no ambiguities };

   References to constants, types, and exceptions are bound to an interface when it is defined (i.e., replaced with the equivalent global <scoped_name>s). This guarantees that the syntax and semantics of an interface are not changed when the interface is a base interface for a derived interface. Consider the following example:

   const long L = 3;

   interface A { typedef float coord[L]:

   void f (in coord s); // s has three floats };

   interface B {

   const long L = 4; };

   interface C: B, A { }; // what is C::f()’s signature?

   The early binding of constants, types, and exceptions at interface definition guarantees that the signature of operation f in interface C is

   typedef float coord[3]; void f (in coord s);

   which is identical to that in interface A. This rule also prevents redefinition of a constant, type, or exception in the derived interface from affecting the operations and attributes inherited from a base interface.

   Interface inheritance causes all identifiers defined in base interfaces, both direct and indirect, to be visible in the current naming scope. A type name, constant name, enumeration value name, or exception name from an enclosing scope can be redefined in the current scope. An attempt to use an ambiguous name without qualification produces a compilation error. Thus in

   interface A {

   typedef string<128> string_t; };

   interface B { typedef string<256> string_t;

};

interface C: A, B {

};

attribute string_t Title; // Error: string_t ambiguous
attribute A::string_t Name; // OK
attribute B::string_t City; // OK

   Operation and attribute names are used at run-time by both the stub and dynamic interfaces. As a result, all operations attributes that might apply to a particular object must have unique names. This requirement prohibits redefining an operation or attribute name in a derived interface, as well as inheriting two operations or attributes with the same name.

   interface A {

   void make_it_so(); };

   interface B: A {

   short make_it_so(in long times); // Error: redefinition of make_it_so };

   For a complete summary of allowable inheritance and supporting relationships among interfaces and valuetypes see Table 3-10 on page 3-32.