XPLC

"The best way to predict the future is to invent it." -- Alan Kay


Main
FAQ
Project
Documentation
Download
Links
Source Forge

Using the IMPLEMENT_IOBJECT Helper

The IMPLEMENT_IOBJECT macro is a helper to let you avoid the tedium of implementing IObject's methods yourself for all your components.

It is very simple to use:

  1. Do not implement any of IObject's methods.
  2. In one of your source file, use the UUID_MAP macros to declare the list of interfaces supported by your component (called the "interface map"). Each interface should be listed only once, even if it appears more than once in your inheritance tree.
  3. Put a line containing "IMPLEMENT_IOBJECT(MyComponent);" as the first line of your class definition.

A Simple Interface Map Example

Here is how you would declare an example component (assume IFoo has a single method called doFoo):

class FooComponent: public IFoo
{
    IMPLEMENT_IOBJECT(FooComponent);
public:
    virtual void doFoo();
};

This component needs a map that looks like the following (this goes in the source file):

UUID_MAP_BEGIN(FooComponent)
UUID_MAP_ENTRY(IObject)
UUID_MAP_ENTRY(IFoo)
UUID_MAP_END

As you see, we simply started the map with UUID_MAP_BEGIN, used the UUID_MAP_ENTRY macro once per supported interface and finished the map with UUID_MAP_END.

A More Advanced Interface Map Example

Now, if your component derives from more than one interface, say from both IFoo and IBar (which, you have guessed it, has a single method named doBar), a quirk of C++ makes the simple and obvious addition of a UUID_MAP_ENTRY(IBar) not possible, unfortunately. The reason is that there is now two IObject interfaces available, the one from IFoo and the one from IBar, and the compiler doesn't know which one to pick. Here is how the class is defined:

class AdvancedComponent: public IFoo, public IBar
{
    IMPLEMENT_IOBJECT(AdvancedComponent);
public:
    virtual void doFoo();
    virtual void doBar();
};

You have to use the UUID_MAP_ENTRY_2 macro to declare the so-called ambiguous interfaces, which allow you to specify which one you want to the compiler, as follows:

UUID_MAP_BEGIN(AdvancedComponent)
UUID_MAP_ENTRY_2(IObject, IFoo)
UUID_MAP_ENTRY(IFoo)
UUID_MAP_ENTRY(IBar)
UUID_MAP_END

The second parameter simply specifies whose IObject will be chosen. Why use IFoo over IBar? Using any other interface that has also derive from the ambiguous interface will also work correctly, but using the first interface your component derives from is slightly more efficient with most C++ compilers, so you should prefer using the first one.

And this is all there is to it!