| 
                   | 
               
                  
                   | 
            |
Multiple inheritance is a powerful aspect of C++. Experience of multiple inheritance indicates that its benefits are best realised by carefully controlling the ways in which it is used within a system to a few easily understood paradigms. Use of multiple inheritance without such control has usually led to designs that are difficult to understand.
Multiple inheritance is used for a single purpose in Symbian OS: namely, interface protocol definitions. These are used in the following kinds of situation: there is a protocol provider class, and a protocol user. It is desirable that the protocol user be independent of all aspects of the protocol provider, except its ability to provide the specified protocol. Examples of such situations include:
an application control is a protocol provider; its menu tree uses the protocol for menu observing. When a menu item has been selected, the menu observing protocol is invoked, so that the application control may handle the menu command. Apart from this, the menu control knows nothing about the application control.
an application, such as a spreadsheet, may have an engine which provides protocols for updating and getting its model contents, and a user interface, which uses these protocols to drive the engine. The engine is written with no knowledge of the user interface, and the user interface is written with minimal knowledge of the engine. They interact using a protocol provided by the engine.
To understand why interfaces are used, this page examines in turn:
the traditional method which uses single inheritance
a technique of overcoming the disadvantages of single inheritance, using protocol intermediary classes
a better technique, which uses multiple inheritance with interface classes
the restrictions on C++ multiple inheritance in Symbian OS
A classical use of single inheritance is to define an abstract protocol from which derived classes may inherit. A base class defines a protocol:
class CProtocol : public CBase
    {
public:
    virtual void HandleEvent(TInt aEventCode)=0;
    };
The protocol includes just one function,
            HandleEvent(), where the event is defined by an integer event
            code.
         
A concrete protocol provider class is then derived from this base class. It provides a concrete implementation of the pure virtual function in the base class:
class CProtocolProvider : public CProtocol
    {
public:
    // construct/destruct
    static CProtocolProvider* NewLC();
    void Destruct();
    // implement the protocol
    void HandleEvent(TInt aEventCode); // handle protocol
protected:
    void ConstructL();
    };
In addition, there is a protocol user class which knows nothing
            about the derived CProtocolProvider class, but it does know about
            the CProtocol class and the functions that specify its protocol.
            It has a function which uses HandleEvent():
         
void CProtocolUser::DoSomething(CProtocol* aProtocol)
    {
    _LIT(KOutput1,"External system doing something\n");
    _LIT(KOutput2,"invoking protocol - event 3\n");
    testConsole.Printf(KOutput1);
    testConsole.Printf(KOutput2);
    aProtocol->HandleEvent(3); // handle an event
    }
The virtual function defined by CProtocol is provided
            by CProtocolProvider. This is the virtual function that is
            actually executed:
         
void CProtocolProvider::HandleEvent(TInt aEventCode)
    { // handle an event in the protocol user
    _LIT(KOutput1,"CProtocolProvider handling event %d\n");
    testConsole.Printf(KOutput1,aEventCode);
    }
Thus, although the protocol user knows nothing about the derived
            CProtocolProvider class, it can invoke its member functions
            through a pointer to its derived class, using the C++ virtual function
            mechanism.
         
This code may be used in the following way:
void doExampleL()
    {
    // show use of interface with simple class
    CProtocolProvider* provider=CProtocolProvider::NewLC();
    CProtocolUser* user=CProtocolUser::NewLC();
    user->DoSomething(provider);
    CleanupStack::PopAndDestroy(); // user
    CleanupStack::PopAndDestroy(); // provider
    }
In the function call, the provider pointer is cast to
            its CProtocol* base class, as required by
            CProtocolUser::DoSomething().
         
The advantages of this method are
it achieves independence of the protocol user from the specific protocol provider
This was the goal we set out to achieve. However, this method has a serious disadvantage:
it forces the protocol provider to be derived from a protocol base class
however, if more than one protocol must be provided by the provider class, the only solution is to include all the protocols into a single umbrella protocol, and to derive the provider class from that. This is bad encapsulation. Firstly, the base class can become quite large and it can be unclear why it contains so many member functions, or which function belongs to which protocol. Secondly, it may be desirable to have another provider class which provides some of the protocols provided by the first class, and others in addition. To support this requires an even larger umbrella protocol.
The straightforward method of providing protocols by strict single inheritance often leads to large base classes, representing many protocols which should really be independent of one another.
Some of these disadvantages can be overcome by using an intermediary object which represents the protocol, and has a pointer to the protocol provider. The base protocol class is essentially the same:
class TProtocol
    {
public:
    virtual void HandleEvent(TInt aEventCode)=0;
    };
but there is now a derived class for use with the
            CProtocolProvider only:
         
class TProtocolProviderIntermediary : public TProtocol
    {
public:
    // construct
    TProtocolProviderIntermediary(CProtocolProvider* aRealProvider);
    // protocol itself
    void HandleEvent(TInt aEventCode);
private:
    CProtocolProvider* iRealProvider; // real provider
    };
This class provides the protocol as far as the protocol user is
            concerned. The concrete implementation of HandleEvent() just
            passes the function call to the real protocol provider class, which has a
            non-virtual DoHandleEvent() to provide the required
            functionality:
         
void TProtocolProviderIntermediary::HandleEvent(TInt aEventCode)
    {
    iRealProvider->DoHandleEvent(aEventCode);
    }
With this system, CProtocolProvider is derived, not
            from the protocol definition class, but from CBase:
         
class CProtocolProvider : public CBase
    {
public:
    // construct/destruct
    static CProtocolProvider* NewLC();
    void Destruct();
    // implement the protocol
    void DoHandleEvent(TInt aEventCode); // handle protocol
protected:
    void ConstructL();
public:
    TProtocolProviderIntermediary* iProviderIntermediary;
    };
The TProtocolProviderIntermediary is constructed by
            the CProtocolProviders constructor, and destroyed by its
            destructor. For this reason, the TProtocolProviderIntermediary is
            a T class: it does not own the CProtocolProvider, and
            cannot be orphaned.
         
When a function in the protocol user requiring the protocol provider is called, it must now be called passing the intermediary object as a parameter:
LOCAL_C void doExampleL()
    {
    // show use of interface with simple class
    CProtocolProvider* provider=CProtocolProvider::NewLC();
    CProtocolUser* user=CProtocolUser::NewLC();
    user->DoSomething(provider->iProviderIntermediary);
    CleanupStack::PopAndDestroy(); // user
    CleanupStack::PopAndDestroy(); // provider
    }
The protocol users DoSomething() is
            essentially as it was before, except that its parameter is now a
            TProtocol*. Thus, the user knows only about the base
            TProtocol class. The virtual function mechanism causes the derived
            intermediarys HandleEvent() to be called, and this
            function passes on the request to the real protocol providers
            DoHandleEvent().
         
This method solves the problems associated with using only single inheritance:
any number of protocols may be supported, and separately encapsulated, by a particular class: each protocol requires an intermediary class, and objects of each intermediary class point to corresponding objects of the real protocol provider class
no large base classes are needed to provide umbrellas for several protocols
However, it has a serious disadvantage:
it is awkward: not only does each protocol require an abstract class (which cannot be avoided), but also, at each point in the derivation tree at which a protocol is introduced, a derived protocol class must be written which implements the protocol for the relevant class which really provides the protocol: further, the derived protocol object and the real protocol provider must be linked
if there are many classes which use many protocols in this way, not only is the method cumbersome to program, but it is uneconomical on memory, since each derived protocol class object requires at least two machine words of heap memory. This consideration becomes more serious if there are more small real protocol providers, providing many different protocols.
These problems can be overcome by using multiple inheritance. A
            base MProtocol class specifies the protocol:
         
class MProtocol
    {
public:
    virtual void HandleEvent(TInt aEventCode)=0;
    };
This time, however, the protocol provider is derived both from
            CBase
            and from MProtocol:
         
class CProtocolProvider : public CBase, public MProtocol
    {
public:
    // construct/destruct
    static CProtocolProvider* NewLC();
    void Destruct();
    // implement the protocol
    void HandleEvent(TInt aEventCode); // handle protocol
protected:
    void ConstructL();
    };
The protocol provider class provides a concrete implementation of
            the HandleEvent() function required by the protocol. The user
            class may now be invoked as follows:
         
LOCAL_C void doExampleL()
    {
    // show use of interface with simple class
    CProtocolProvider* provider=CProtocolProvider::NewLC();
    CProtocolUser* user=CProtocolUser::NewLC();
    user->DoSomething(provider);
    CleanupStack::PopAndDestroy(); // user
    CleanupStack::PopAndDestroy(); // provider
    }
The DoSomething() function requires an
            MProtocol* parameter. C++ casts the CProtocolProvider*
               provider pointer down to an MProtocol*, because
            MProtocol is one of the base classes of
            CProtocolProvider. When DoSomething() invokes
            HandleEvent(), the C++ virtual function mechanism ensures that it
            is CProtocolProviders HandleEvent() that is
            actually called. Thus, the user may use the protocol, without knowing anything
            specific about the concrete protocol provider class.
         
This method achieves the intended goals:
the protocol user is dependent on the protocol, but not on any particular provider
the protocol can be introduced into a class hierarchy at any desired point, by multiply inheriting from a base class and one or more interface classes
full encapsulation of different protocols is achieved
there is no inconvenient intermediate class, with its programming difficulties and wasteful memory use
Because protocols may be mixed into the derivation hierarchy of
            conventional classes at any convenient point in the hierarchy, such protocol
            specification classes are sometimes also called mixins, the origin of the
            prefix M.
         
The use of multiple inheritance is restricted to interfaces used as
            described above. C++s full multiple inheritance facilities are
            unnecessarily complex. This is perhaps recognised by the OO community now.
            Java, for instance, allows only single inheritance, but the
            interface and implements keywords support the same
            facilities as are provided by M classes. The restrictions are
            given in more detail here.
         
Firstly, M classes primarily define protocols, not
            implementations. In particular, they should not have any member data. The
            restriction implies that certain types of behaviour (e.g., that of active
            objects, see Active objects) may not be encapsulated in an interface, but
            must be derived in the conventional way.
         
Secondly, a C class may be derived from one other
            C class, and zero or more M classes. This restriction
            reflects the fact that multiple inheritance is only to be used for interfaces.
            It implies that it is still possible to uniquely identify a primary inheritance
            tree (the C class hierarchy), with interfaces as a side feature.
            If arbitrary multiple inheritance were allowed, it would be impossible to
            identify a primary inheritance tree. The restriction also guarantees that no
            C class will be a multiple base class, which makes it unnecessary
            to consider the complications of multiple base class inclusion, virtual
            inheritance, etc.
         
Thirdly, the C class must be the first specified class
            in any base class list. This emphasises the primary inheritance tree and,
            importantly, it makes conversions between any C class (including
            those with interfaces) and void* pointers freely possible.
            Admittedly, the C++ standards do not mandate that object layout follows the
            order in which base classes are specified, but in practice this is the case for
            most compilers, including those used for Symbian OS.
         
Fourthly, no M class may be mixed in more than once in
            any class, either as a direct base or as a base of any of its primary base
            classes. To put it another way: when deriving a C class
            CD from a base class CB, you may not mix in
            any M class MP which has already been mixed into the
            derivation of CB. This reflects the fact that
            CB already supports the protocol defined by MP: there
            is nothing to gain from mixing in this protocol class again. In addition, it
            makes it unnecessary to consider the complications of multiple base class
            inclusion, virtual inheritance, etc.
         
Finally, although it is legal to derive one M class
            from another, it is not legal to include a protocol twice by including both it
            and a derived protocol into a C class, at any point in the
            C classs base class graph. To put it another way, if there
            is a class MD derived from MB, then a C
            class cannot include both MB and MD. This is because
            any function in the C class which provided an implementation of
            MB protocol could conflict with the implementation of
            MD protocol.
         
A special case of an interface is the callback. In this situation, one class performs a certain function for another and, when this is done, calls a single function in the requesting class, to indicate that the requested operation is complete. This call-back function represents a protocol: the requesting class is the provider, and the performing class is the user. Apart from this, the performing class need know little or nothing about the requesting class. This is an ideal situation for a interface.
So far, we have discussed interfaces in the context where one class provides services according to a given protocol, and another uses those services. In a more general case, two classes (or systems of classes) may require services from each other, so that there is two-way interaction.
Services are always provided according to a protocol. The protocol can be provided using any of the techniques described in this document:
conventional derivation, which is most appropriate where the protocol characterises a classs main purpose
interface inheritance, which is most appropriate where a protocol may be a characteristic of many classes, but where these classes have diverse main purposes
intermediary objects, which may be appropriate where an interface would otherwise be used, but when multiple inheritance is disallowed, or inconvenient for some other reason
GUI applications use menus to present a user interface for selecting options. When an option has been chosen, the menu bar should forward a command somewhere by calling a member function of some class. The only thing that is important to the menu bar is that some object exists which can handle the command: beyond that, nothing matters about the object.
class CEikMenuBar ...
    {
public:
    ConstructL(MEikMenuObserver* aObserver, ...);
    // ...
private:
    MEikMenuObserver* iObserver;
    // ...
    }
A menu bar therefore uses a menu observer. This is
            passed in as a parameter at construction, stored as member data, and used when
            an option has been selected. The menu observer interface is defined by the menu
            component, as the MEikMenuObserver class.
         
This interface is implemented by the app UI (which also does many
            other things, which are irrelevant to menus). So, CEikAppUi
            implements menu observer interface by deriving from
            MEikMenuObserver:
         
class CEikAppUi : public CCoeAppUi, MEikMenuObserver
The app UI has a menu bar, and when it constructs the menu bar, the app UI passes itself to the menu bar, as the observer:
iMenuBar->ConstructL(this, ...);
C++ causes the this to be cast into the appropriate
            base class—in this case, an
            MEikMenuObserver—automatically.