[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.4.3 Classes Implementing Multiple Interfaces

Sometimes we will want one object to implement several interfaces. For example, the 3D graphics driver could provide a basic `iGraphics3D' interface and several additional optional interfaces such as `iHalo', `iBumpMap', and so on. There are two ways to do this:

To simplify the following discussion we'll refer them as multiple interface and embedded interface methods.

Multiple Interfacing

You can declare a class to inherit from several interfaces at once. This is useful if all implemented interfaces will need to access often same member variables. For example, both the `iHalo' and `iBumpMap' implementations will need to access many member variables from `iGraphics3D' such as pixel format, screen dimensions and so on. You declare such classes this way:

 
class MyGraphics3D :
    public iGraphics3D, public iHalo, public iBumpMap
{
public:
  ...
};

When implementing the methods imposed by the `iBase' interface you should use the IMPLEMENT_INTERFACE() macro once for each implemented interface:

 
SCF_IMPLEMENT_IBASE(MyGraphics3D)
  SCF_IMPLEMENTS_INTERFACE(iGraphics3D)
  SCF_IMPLEMENTS_INTERFACE(iHalo)
  SCF_IMPLEMENTS_INTERFACE(iBumpMap)
SCF_IMPLEMENT_IBASE_END

Embedded Interfaces

Another way to implement several interfaces in one object is to embed an object that implements some interface into the another object, known as the "carrier" object. This method is preferable when a secondary interface seldom needs access to the carrier object's members, since you will need to access them through scfParent pointer. Here is an example:

 
class MyGraphics3D : public iGraphics3D
{
  // Declare the iHalo embedded interface.
  class MyHalo : public iHalo
  {
    SCF_DECLARE_EMBEDDED_IBASE(MyGraphics3D);
    ...
  } scfiHalo;
  // Declare the iBumpMap embedded interface.
  class MyBumpMap : public iBumpMap
  {
    SCF_DECLARE_EMBEDDED_IBASE(MyGraphics3D);
    ...
  } scfiBumpMap;

public:
  SCF_DECLARE_IBASE;
  ...
};

Note that you don't need to use special names for classes; use anything you want (that is, the `My' prefix is not required; you could name the above class `GraphixThreeDeeImplementation' if you like; this is true for embedded classes as well). But most SCF macros that have the word `EMBEDDED' within their names expect embedded object names to follow the form `scfInterfaceName'. For instance, `scfiBase', `scfiTest', `scfiGraphics3D', and so on.

When you declare the `iBase' methods within an embedded class, you can use the SCF_DECLARE_EMBEDDED_IBASE(OuterClass) macro instead of `SCF_DECLARE_IBASE'. In this case the `scfParent' member will be of type OuterClass* rather than of type iBase*; this will allow the member class to talk with its parent directly, thus allowing for direct member variables and functions access. In fact, the `SCF_DECLARE_IBASE' macro uses SCF_DECLARE_EMBEDDED_IBASE(iBase). `SCF_DECLARE_EMBEDDED_IBASE' itself has another special characteristic: It does not use a reference count, as embedded interfaces may never delete themselves. IncRef and DecRef simply call the corresponding function of their scfParent, which is the object they are embedded in.

When using SCF_DECLARE_EMBEDDED_IBASE, you should implement the methods with the SCF_IMPLEMENT_EMBEDDED_IBASE() macro instead of SCF_IMPLEMENT_IBASE().

 
SCF_IMPLEMENT_IBASE(MyGraphics3D)
  SCF_IMPLEMENTS_INTERFACE (iGraphics3D)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iHalo)
  SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iBumpMap)
SCF_IMPLEMENT_IBASE_END

And finally, in the parent object's constructor you should initialize all embedded interface objects with the SCF_CONSTRUCT_EMBEDDED_IBASE(InterfaceName) macro. This will initialize `scfRefCount' and `scfParent' fields within `scfInterfaceName' member variables to appropiate values (zero and `this'). Here is how to do it:

 
MyGraphics3D::MyGraphics3D(iBase* iParent)
{
  SCF_CONSTRUCT_IBASE(iParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(iHalo);
  SCF_CONSTRUCT_EMBEDDED_IBASE(iBumpMap);
  ...
}

You should not call SCF_CONSTRUCT_IBASE() within embedded object's constructor (in fact, it can not have a constructor at all) since all work needed to initialize iBase fields is done in the carrier object's constructor.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated using texi2html