On Tue, Sep 7, 2010 at 8:32 AM, David Nečas <yeti@xxxxxxxxxxxxxxx> 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@xxxxxx _______________________________________________ gtk-list mailing list gtk-list@xxxxxxxxx http://mail.gnome.org/mailman/listinfo/gtk-list