Re: howto write an interface



On Tue, Sep 7, 2010 at 8:32 AM, David Nečas <yeti physics muni cz> wrote:
> On Mon, Sep 06, 2010 at 09:05:37PM +0200, joel krähemann wrote:
>> Hi, I want to write an interface with glib-object. The situation is a
>> parent object implements the interface, but the subclass should
>> overwrite the function pointers in the interface. The parent class
>> contains the following code in the function ags_recall_get_type:
>>
>> ...
>>
>> static const GInterfaceInfo ags_connectable_interface_info = {
>>   (GInterfaceInitFunc) ags_recall_connectable_interface_init,
>>   NULL, /* interface_finalize */
>>   NULL, /* interface_data */
>> };
>>
>> ...
>>
>> g_type_add_interface_static(ags_type_recall,
>>                           AGS_TYPE_CONNECTABLE,
>>                             &ags_connectable_interface_info);
>>
>> ...
>>
>> AgsRecall has subclasses which should overwrite the functions, but I
>> don't know what's the proper way in the subclass to do so. How do I tell
>> GInterface to call a function of the subclass to overwrite?
>> One more, is it correct to make an object cast on the interface e.g.
>> (where AgsConnectable is an interface which is implemented by
>> AgsRecall):
>>
>> void
>> ags_recall_connect(AgsConnectable connectable)
>> {
>>   AGS_RECALL(connectable);
>>
>>   ...
>> }
>
> This sounds somehow backwards.
>
> 1) You define an interface, with a virtual table, i.e. struct
> AgsConnectableInterface, containing the method connect():
>
>    struct _AgsConnectableInterface {
>        GTypeInterface parent;
>
>        void (*connect)(AgsConnectable *connectable);
>    };
>
>
> 2) Then standard macros AGS_TYPE_CONNECTABLE, AGS_CONNECTABLE,
> AGS_IS_CONNECTABLE, AGS_CONNECTABLE_GET_INTERFACE, see the docs.
>
> 3) Methods of this interface, e.g. ags_connectable_connect(), get
> AgsConnectable* as the argument and look up the virtual method to call:
>
>    void
>    ags_connectable_connect(AgsConnectable *connectable)
>    {
>        void (*connect_method)(AgsConnectable*);
>
>        g_return_if_fail(AGS_IS_CONNECTABLE(connectable));
>        connect_method = AGS_CONNECTABLE_GET_INTERFACE(connectable)->connect;
>        g_return_if_fail(connect_method);
>        connect_method(connectable);
>    }
>
> There is no public ags_recall_connect() as this makes no sense.  To
> invoke the connect() method of AgsRecall (or any other class
> implementing the interface) you call
>
>    ags_connectable_connect(AGS_CONNECTABLE(recall));
>
> 4) Each class implementing the interface, including subclasses of
> something that already implements the interface, does
>
>    {
>        static const GInterfaceInfo ags_connectable_interface_info = {
>            (GInterfaceInitFunc)ags_recall_connectable_init, NULL, NULL
>        };
>        g_type_add_interface_static(g_define_type_id,
>                                    AGS_TYPE_CONNECTABLE,
>                                    &ags_connectable_interface_info);
>    }
>
> in the type init function ags_recall_type_init().

I think one point to mention is that you'll need to implement all the
interface methods in subclasses again, even if you just want to use
the implementation in the parent.


> 5) Function ags_recall_connectable_init() gets the virtual table
> AgsConnectableInterface as the argument and fills it:
>
>    static void
>    ags_recall_connectable_init(AgsConnectableInterface *iface)
>    {
>        iface->connect = ags_recall_connect;
>    }
>
> where ags_recall_connect() is a static function implementing the method,
> not public.

Maybe also add (untested)

7) in order to call the parent implementation of the interface methods
from derived class, say AgsTotalRecall that is subclass of AgsRecall,
use g_type_interface_peek_parent()

static void
ags_total_recall_connect(AgsConnectable *connectable)
{
  AgsTotalRecall *self = AGS_TOTAL_RECALL(connectable);
  AgsConnectable *parent;

  g_debug("Hello world!"); // or whatever

  parent = g_type_interface_peek_parent(connectable);
  ags_connectable_connect(parent);
}

I suppose an alternative would be for ags_connectable_connect() to
recursively call peek_parent and call the first non-NULL method. Would
slightly reduce boilerplate in derived classes.


-- 
Tommi Komulainen                                 tommi komulainen iki fi


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]