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

4.4.1.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 schemes.

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 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 the `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;
  friend MyHalo;

  // Declare the iBumpMap embedded interface.
  class MyBumpMap : public iBumpMap
  {
    SCF_DECLARE_EMBEDDED_IBASE(MyGraphics3D);
    ...
  } scfiBumpMap;
  friend MyBumpMap

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, and has another special characteristic: It does not use a reference count, as embedded interfaces may never delete themselves. IncRef() and DecRef() of embedded objects simply call the corresponding function of their `scfParent', which is the object in which they are embedded.

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

SCF_IMPLEMENT_EMBEDDED_IBASE (MyGraphics3D::MyHalo)
  SCF_IMPLEMENTS_INTERFACE (iHalo)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

SCF_IMPLEMENT_IBASE (MyGraphics3D::MyBumpMap)
  SCF_IMPLEMENTS_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 appropriate values (zero and `this'). Likewise, you should destroy embedded interfaces with the SCF_DESTRUCT_EMBEDDED_IBASE() macro. Here is how to do it:

 
MyGraphics3D::MyGraphics3D(iBase* iParent)
{
  SCF_CONSTRUCT_IBASE(iParent);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiHalo);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiBumpMap);
  ...
}

MyGraphics3D::~MyGraphics3D()
{
  ...
  SCF_DESTRUCT_EMBEDDED_IBASE(scfiBumpMap);
  SCF_DESTRUCT_EMBEDDED_IBASE(scfiHalo);
  SCF_DESTRUCT_IBASE();
}

You should not call SCF_CONSTRUCT_IBASE() within embedded object's constructor since all work needed to initialize `iBase' fields is done in the carrier object's constructor. Likewise, you should not call SCF_DESTRUCT_IBASE() within the embedded object's destructor.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated using texi2html 1.76.