Fix up GObject interface documentation

* Document how to override interfaces already implemented
   in a base class, and also call those base class implementations
   from a derived reimplementation.
 * Don't recomend people use base_init() style functions to
   initialize interface signals and properties, use default_init()
   aka class_init() instead (as G_DEFINE_INTERFACE() uses).
 * The above solves the interface init called multiple times
   problem, so remove some needless naysaying about that.
 * Document default_init() in the interface initialization discussion
 * Linkify more stuff.
 * Remove some crud and typos

https://bugzilla.gnome.org/show_bug.cgi?id=675504
This commit is contained in:
Stef Walter 2012-05-05 12:51:16 +02:00
parent 2cf9608d48
commit 3b0f1cc432
2 changed files with 313 additions and 141 deletions

View File

@ -322,8 +322,9 @@ GType maman_bar_get_type (void)
</para> </para>
<para> <para>
When having no special requirements you also can use the <function>G_DEFINE_TYPE</function> If you have no special requirements you can use the
macro: <function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>
macro to define a class:
<programlisting> <programlisting>
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT) G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT)
</programlisting> </programlisting>
@ -688,7 +689,7 @@ void maman_ibaz_do_action (MamanIbaz *self)
MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
} }
</programlisting> </programlisting>
<function>maman_ibaz_get_type</function> registers a type named <emphasis>MamanIBaz</emphasis> <function>maman_ibaz_get_type</function> registers a type named <emphasis>MamanIbaz</emphasis>
which inherits from G_TYPE_INTERFACE. All interfaces must be children of G_TYPE_INTERFACE in the which inherits from G_TYPE_INTERFACE. All interfaces must be children of G_TYPE_INTERFACE in the
inheritance tree. inheritance tree.
</para> </para>
@ -706,14 +707,13 @@ void maman_ibaz_do_action (MamanIbaz *self)
Once an interface type is registered, you must register implementations for these Once an interface type is registered, you must register implementations for these
interfaces. The function named <function>maman_baz_get_type</function> registers interfaces. The function named <function>maman_baz_get_type</function> registers
a new GType named MamanBaz which inherits from <link linkend="GObject"><type>GObject</type></link> and which a new GType named MamanBaz which inherits from <link linkend="GObject"><type>GObject</type></link> and which
implements the interface <type>MamanIBaz</type>. implements the interface <type>MamanIbaz</type>.
<programlisting> <programlisting>
static void maman_baz_do_action (MamanIbaz *self) static void maman_baz_do_action (MamanIbaz *self)
{ {
g_print ("Baz implementation of IBaz interface Action.\n"); g_print ("Baz implementation of Ibaz interface Action.\n");
} }
static void static void
baz_interface_init (gpointer g_iface, baz_interface_init (gpointer g_iface,
gpointer iface_data) gpointer iface_data)
@ -728,7 +728,7 @@ maman_baz_get_type (void)
static GType type = 0; static GType type = 0;
if (type == 0) { if (type == 0) {
const GTypeInfo info = { const GTypeInfo info = {
sizeof (MamanBazInterface), sizeof (MamanBazClass),
NULL, /* base_init */ NULL, /* base_init */
NULL, /* base_finalize */ NULL, /* base_finalize */
NULL, /* class_init */ NULL, /* class_init */
@ -771,22 +771,38 @@ struct _GInterfaceInfo
}; };
</programlisting> </programlisting>
</para> </para>
<para> <para>
When having no special requirements you also can use the <function>G_DEFINE_INTERFACE</function> macro: If you have no special requirements you can use the
<link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link> macro
to implement an interface:
<programlisting> <programlisting>
G_DEFINE_INTERFACE (MamanBaz, maman_baz, G_TYPE_OBJECT) static void
maman_baz_do_action (MamanIbaz *self)
{
g_print ("Baz implementation of Ibaz interface Action.\n");
}
static void
maman_ibaz_interface_init (MamanIbazInterface *iface)
{
iface->do_action = maman_baz_do_action;
}
G_DEFINE_TYPE_WITH_CODE (MamanBaz, maman_baz, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ,
maman_ibaz_interface_init));
</programlisting> </programlisting>
</para> </para>
<sect2 id="gtype-non-instantiable-classed-init"> <sect2 id="gtype-non-instantiable-classed-init">
<title>Interface Initialization</title> <title>Interface Initialization</title>
<para> <para>
When an instantiable classed type which registered an interface When an instantiable classed type which implements an interface
implementation is created for the first time, its class structure (either directly or by inheriting an implementation from a superclass)
is initialized following the process is created for the first time, its class structure is initialized
described in <xref linkend="gtype-instantiable-classed"/>. following the process described in <xref linkend="gtype-instantiable-classed"/>.
After that, the interface implementations associated with After that, the interface implementations associated with
the type are initialized. the type are initialized.
</para> </para>
@ -802,28 +818,65 @@ G_DEFINE_INTERFACE (MamanBaz, maman_baz, G_TYPE_OBJECT)
</para> </para>
<para> <para>
Finally, the interface' most-derived <function>base_init</function> function and then The interface's <function>base_init</function> function is called,
and then the interface's <function>default_init</function> is invoked.
Finally if the type has registered an implementation of the interface,
the implementation's <function>interface_init</function> the implementation's <function>interface_init</function>
function are invoked. It is important to understand that if there are multiple function is invoked. If there are multiple implementations of an
implementations of an interface the <function>base_init</function> and interface the <function>base_init</function> and
<function>interface_init</function> functions will be <function>interface_init</function> functions will be invoked once
invoked once for each implementation initialized. for each implementation initialized.
</para> </para>
<para> <para>
It is thus common for base_init functions to hold a local static boolean variable It is thus recommended to use a <function>default_init</function> function to
which makes sure that the interface type is initialized only once even if there are initialize an interface. This function is called only once for the interface no
multiple implementations of the interface: matter how many implementations there are. The
<function>default_init</function> function is declared by
<link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link>
which can be used to define the interface:
<programlisting> <programlisting>
static void G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, G_TYPE_OBJECT);
maman_ibaz_base_init (gpointer g_iface)
{
static gboolean initialized = FALSE;
if (!initialized) { static void
/* create interface signals here. */ maman_ibaz_default_init (MamanIbazInterface *iface)
initialized = TRUE; {
/* add properties and signals here, will only called once */
}
</programlisting>
</para>
<para>
Or you can do that yourself in a GType function for your interface:
<programlisting>
GType
maman_ibaz_get_type (void)
{
static volatile gsize type_id = 0;
if (g_once_init_enter (&amp;type_id)) {
const GTypeInfo info = {
sizeof (MamanIbazInterface),
NULL, /* base_init */
NULL, /* base_finalize */
maman_ibaz_default_init, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
0, /* instance_size */
0, /* n_preallocs */
NULL /* instance_init */
};
GType type = g_type_register_static (G_TYPE_INTERFACE,
"MamanIbaz",
&amp;info, 0);
g_once_init_leave (&amp;type_id, type);
} }
return type_id;
}
static void
maman_ibaz_default_init (MamanIbazInterface *iface)
{
/* add properties and signals here, will only called once */
} }
</programlisting> </programlisting>
</para> </para>
@ -835,7 +888,6 @@ maman_ibaz_base_init (gpointer g_iface)
</para> </para>
<para> <para>
The above process can be summarized as follows:
<table id="ginterface-init-table"> <table id="ginterface-init-table">
<title>Interface Initialization</title> <title>Interface Initialization</title>
<tgroup cols="3"> <tgroup cols="3">
@ -853,24 +905,31 @@ maman_ibaz_base_init (gpointer g_iface)
</thead> </thead>
<tbody> <tbody>
<row> <row>
<entry morerows="1">First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> for type <entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
implementing interface for <emphasis>any</emphasis> type implementing interface
</entry> </entry>
<entry>interface' base_init function</entry> <entry>interface's <function>base_init</function> function</entry>
<entry>On interface' vtable</entry> <entry>On interface's vtable</entry>
<entry>Register interface' signals here (use a local static <entry>Rarely necessary to use this. Called once per instantiated classed type implementing the interface.</entry>
boolean variable as described above to make sure not to register them
twice.).</entry>
</row> </row>
<row> <row>
<!--entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> for type <entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
implementing interface for <emphasis>each</emphasis> type implementing interface
</entry--> </entry>
<entry>interface' interface_init function</entry> <entry>interface's <function>default_init</function> function</entry>
<entry>On interface' vtable</entry> <entry>On interface's vtable</entry>
<entry>Register interface's signals, properties, etc. here. Will be called once.</entry>
</row>
<row>
<entry>First call to <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
for <emphasis>any</emphasis> type implementing interface
</entry>
<entry>implementation's <function>interface_init</function> function</entry>
<entry>On interface's vtable</entry>
<entry> <entry>
Initialize interface' implementation. That is, initialize the interface Initialize interface implementation. Called for each class that that
method pointers in the interface structure to the function's implementation. implements the interface. Initialize the interface method pointers
in the interface structure to the implementing class's implementation.
</entry> </entry>
</row> </row>
</tbody> </tbody>

View File

@ -794,7 +794,7 @@ b_method_to_call (B *obj, int a)
<title>How to define and implement interfaces</title> <title>How to define and implement interfaces</title>
<sect1 id="howto-interface-define"> <sect1 id="howto-interface-define">
<title>How to define interfaces</title> <title>How to define an interface</title>
<para> <para>
The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/> The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/>
@ -802,7 +802,8 @@ b_method_to_call (B *obj, int a)
</para> </para>
<para> <para>
As above, the first step is to get the header right: As above, the first step is to get the header right. This interface
defines two methods:
<programlisting> <programlisting>
#ifndef __MAMAN_IBAZ_H__ #ifndef __MAMAN_IBAZ_H__
#define __MAMAN_IBAZ_H__ #define __MAMAN_IBAZ_H__
@ -823,11 +824,13 @@ struct _MamanIbazInterface
GTypeInterface parent_iface; GTypeInterface parent_iface;
void (*do_action) (MamanIbaz *self); void (*do_action) (MamanIbaz *self);
void (*do_something) (MamanIbaz *self);
}; };
GType maman_ibaz_get_type (void); GType maman_ibaz_get_type (void);
void maman_ibaz_do_action (MamanIbaz *self); void maman_ibaz_do_action (MamanIbaz *self);
void maman_ibaz_do_something (MamanIbaz *self);
#endif /* __MAMAN_IBAZ_H__ */ #endif /* __MAMAN_IBAZ_H__ */
</programlisting> </programlisting>
@ -854,51 +857,28 @@ void maman_ibaz_do_action (MamanIbaz *self);
<para> <para>
The implementation of the <type>MamanIbaz</type> type itself is trivial: The implementation of the <type>MamanIbaz</type> type itself is trivial:
<itemizedlist> <itemizedlist>
<listitem><para><function>maman_ibaz_get_type</function> registers the <listitem><para><function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function>
type in the type system. creates a <function>maman_ibaz_get_type</function> function which registers the
type in the type system. The third argument is used to define a
<link linkend="howto-interface-prerequisite">prerequisite interface</link>
(which we'll talk about more later). Just pass <code>0</code> for this
argument when an interface has no prerequisite.
</para></listitem> </para></listitem>
<listitem><para><function>maman_ibaz_base_init</function> is expected <listitem><para><function>maman_ibaz_default_init</function> is expected
to register the interface's signals if there are any (we will see a bit to register the interface's signals if there are any (we will see a bit
(later how to use them). Make sure to use a static local boolean variable later how to use them).</para></listitem>
to make sure not to run the initialization code twice (as described in <listitem><para>The interface methods <function>maman_ibaz_do_action</function>
<xref linkend="gtype-non-instantiable-classed-init"/>, and <function>maman_ibaz_do_something</function> dereference the interface
<function>base_init</function> is run once for each interface implementation structure to access its associated interface function and call it.
instantiation)</para></listitem>
<listitem><para><function>maman_ibaz_do_action</function> dereferences
the class structure to access its associated class function and calls it.
</para></listitem> </para></listitem>
</itemizedlist> </itemizedlist>
<programlisting> <programlisting>
G_DEFINE_INTERFACE (MamanIbaz, maman_ibaz, 0);
static void static void
maman_ibaz_base_init (gpointer g_class) maman_ibaz_default_init (gpointer g_class)
{ {
static gboolean is_initialized = FALSE;
if (!is_initialized)
{
/* add properties and signals to the interface here */ /* add properties and signals to the interface here */
is_initialized = TRUE;
}
}
GType
maman_ibaz_get_type (void)
{
static GType iface_type = 0;
if (iface_type == 0)
{
const GTypeInfo info = {
sizeof (MamanIbazInterface),
maman_ibaz_base_init, /* base_init */
NULL, /* base_finalize */
};
iface_type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbaz",
&amp;info, 0);
}
return iface_type;
} }
void void
@ -908,12 +888,20 @@ maman_ibaz_do_action (MamanIbaz *self)
MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self); MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
} }
void
maman_ibaz_do_something (MamanIbaz *self)
{
g_return_if_fail (MAMAN_IS_IBAZ (self));
MAMAN_IBAZ_GET_INTERFACE (self)->do_something (self);
}
</programlisting> </programlisting>
</para> </para>
</sect1> </sect1>
<sect1 id="howto-interface-implement"> <sect1 id="howto-interface-implement">
<title>How To define implement an Interface?</title> <title>How to implement an interface</title>
<para> <para>
Once the interface is defined, implementing it is rather trivial. Once the interface is defined, implementing it is rather trivial.
@ -954,15 +942,22 @@ GType maman_baz_get_type (void);
#endif /* __MAMAN_BAZ_H__ */ #endif /* __MAMAN_BAZ_H__ */
</programlisting> </programlisting>
<!-- Ha ha! "nothing weird or scary". I actually laughed out loud. Oh boy.
The fact that we're so intimate with GObject that all this doesn't look
wierd, that's the scary thing. :) -->
There is clearly nothing specifically weird or scary about this header: There is clearly nothing specifically weird or scary about this header:
it does not define any weird API or derives from a weird type. it does not define any weird API or derive from a weird type.
</para> </para>
<para> <para>
The second step is to implement <type>MamanBaz</type> by defining The second step is to implement <type>MamanBaz</type> by defining
its GType. Instead of using <function>G_DEFINE_TYPE</function> we its GType. Instead of using
use <function>G_DEFINE_TYPE_WITH_CODE</function> and the <function><link linkend="G-DEFINE-TYPE:CAPS">G_DEFINE_TYPE</link></function>
<function>G_IMPLEMENT_INTERFACE</function> macros. we use
<function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function>
and the
<function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>
macros.
<programlisting> <programlisting>
static void maman_ibaz_interface_init (MamanIbazInterface *iface); static void maman_ibaz_interface_init (MamanIbazInterface *iface);
@ -971,13 +966,15 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
maman_ibaz_interface_init)); maman_ibaz_interface_init));
</programlisting> </programlisting>
This definition is very much like all the similar functions we looked This definition is very much like all the similar functions we looked
at previously. The only interface-specific code present here is the call at previously. The only interface-specific code present here is the call to
to <function>G_IMPLEMENT_INTERFACE</function>. <function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>.
</para> </para>
<note><para>Classes can implement multiple interfaces by using multiple <note><para>Classes can implement multiple interfaces by using multiple calls to
calls to <function>G_IMPLEMENT_INTERFACE</function> inside the call <function><link linkend="G-IMPLEMENT-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>
to <function>G_DEFINE_TYPE_WITH_CODE</function>.</para></note> inside the call to
<function><link linkend="G-DEFINE-TYPE-WITH-CODE:CAPS">G_DEFINE_TYPE_WITH_CODE</link></function>
</para></note>
<para> <para>
<function>maman_baz_interface_init</function>, the interface <function>maman_baz_interface_init</function>, the interface
@ -987,14 +984,22 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
static void static void
maman_baz_do_action (MamanBaz *self) maman_baz_do_action (MamanBaz *self)
{ {
g_print ("Baz implementation of IBaz interface Action: 0x%x.\n", g_print ("Baz implementation of Ibaz interface Action: 0x%x.\n",
self->instance_member);
}
static void
maman_baz_do_something (MamanBaz *self)
{
g_print ("Baz implementation of Ibaz interface Something: 0x%x.\n",
self->instance_member); self->instance_member);
} }
static void static void
maman_ibaz_interface_init (MamanIbazInterface *iface) maman_ibaz_interface_init (MamanIbazInterface *iface)
{ {
iface->do_action = baz_do_action; iface->do_action = maman_baz_do_action;
iface->do_something = maman_baz_do_something;
} }
static void static void
@ -1005,17 +1010,16 @@ maman_baz_init (MamanBaz *self)
} }
</programlisting> </programlisting>
</para> </para>
</sect1> </sect1>
<sect1> <sect1 id="howto-interface-prerequisite">
<title>Interface definition prerequisites</title> <title>Interface definition prerequisites</title>
<para> <para>
To specify that an interface requires the presence of other interfaces To specify that an interface requires the presence of other interfaces
when implemented, GObject introduces the concept of when implemented, GObject introduces the concept of
<emphasis>prerequisites</emphasis>: it is possible to associate <emphasis>prerequisites</emphasis>: it is possible to associate
a list of prerequisite interfaces to an interface. For example, if a list of prerequisite types to an interface. For example, if
object A wishes to implement interface I1, and if interface I1 has a object A wishes to implement interface I1, and if interface I1 has a
prerequisite on interface I2, A has to implement both I1 and I2. prerequisite on interface I2, A has to implement both I1 and I2.
</para> </para>
@ -1025,16 +1029,15 @@ maman_baz_init (MamanBaz *self)
Java's interface I1 extends interface I2. The example below shows Java's interface I1 extends interface I2. The example below shows
the GObject equivalent: the GObject equivalent:
<programlisting> <programlisting>
/* inside the GType function of the MamanIbar interface */ /* Make the MamanIbar interface require MamanIbaz interface. */
type = g_type_register_static (G_TYPE_INTERFACE, "MamanIbar", &amp;info, 0); G_DEFINE_INTERFACE (MamanIbar, maman_ibar, MAMAN_TYPE_IBAZ);
/* Make the MamanIbar interface require MamanIbaz interface. */
g_type_interface_add_prerequisite (type, MAMAN_TYPE_IBAZ);
</programlisting> </programlisting>
The code shown above adds the MamanIbaz interface to the list of In the <function><link linkend="G-DEFINE-INTERFACE:CAPS">G_DEFINE_INTERFACE</link></function>
prerequisites of MamanIbar while the code below shows how an call above, the third parameter defines the prerequisite type. This
implementation can implement both interfaces and register their is the GType of either an interface or a class. In this case
implementations: the MamanIbaz interface is a prerequisite of the MamanIbar. The code
below shows how an implementation can implement both interfaces and
register their implementations:
<programlisting> <programlisting>
static void static void
maman_ibar_do_another_action (MamanIbar *ibar) maman_ibar_do_another_action (MamanIbar *ibar)
@ -1056,7 +1059,16 @@ maman_ibaz_do_action (MamanIbaz *ibaz)
{ {
MamanBar *self = MAMAN_BAR (ibaz); MamanBar *self = MAMAN_BAR (ibaz);
g_print ("Bar implementation of IBaz interface Action: 0x%x.\n", g_print ("Bar implementation of Ibaz interface Action: 0x%x.\n",
self->instance_member);
}
static void
maman_ibaz_do_something (MamanIbaz *ibaz)
{
MamanBar *self = MAMAN_BAR (ibaz);
g_print ("Bar implementation of Ibaz interface Something: 0x%x.\n",
self->instance_member); self->instance_member);
} }
@ -1064,6 +1076,7 @@ static void
maman_ibaz_interface_init (MamanIbazInterface *iface) maman_ibaz_interface_init (MamanIbazInterface *iface)
{ {
iface->do_action = maman_ibaz_do_action; iface->do_action = maman_ibaz_do_action;
iface->do_something = maman_ibaz_do_something;
} }
static void static void
@ -1087,22 +1100,24 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
It is very important to notice that the order in which interface It is very important to notice that the order in which interface
implementations are added to the main object is not random: implementations are added to the main object is not random:
<function><link linkend="g-type-add-interface-static">g_type_add_interface_static</link></function>, <function><link linkend="g-type-add-interface-static">g_type_add_interface_static</link></function>,
which is called by <function>G_IMPLEMENT_INTERFACE</function>, must be which is called by
invoked first on the interfaces which have no prerequisites and then on <function><link linkend="G-DEFINE-INTERFACE:CAPS">G_IMPLEMENT_INTERFACE</link></function>,
must be invoked first on the interfaces which have no prerequisites and then on
the others. the others.
</para> </para>
</sect1> </sect1>
<sect1 id="howto-interface-properties"> <sect1 id="howto-interface-properties">
<title>Interface Properties</title> <title>Interface properties</title>
<para> <para>
Starting from version 2.4 of GLib, GObject interfaces can also have GObject interfaces can also have
properties. Declaration of the interface properties is similar to properties. Declaration of the interface properties is similar to
declaring the properties of ordinary GObject types as explained in declaring the properties of ordinary GObject types as explained in
<xref linkend="gobject-properties"/>, <xref linkend="gobject-properties"/>, except that
except that <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> is used to <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function>
declare the properties instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. is used to declare the properties instead of
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
</para> </para>
<para> <para>
@ -1114,31 +1129,17 @@ G_DEFINE_TYPE_WITH_CODE (MamanBar, maman_bar, G_TYPE_OBJECT,
That really is one line extended to six for the sake of clarity That really is one line extended to six for the sake of clarity
</para> </para>
</footnote> </footnote>
line in the <function>maman_ibaz_base_init</function> line in the <function>maman_ibaz_default_init</function> as shown below:
<footnote>
<para>
The <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function>
can also be called from <function>class_init</function> but it must
not be called after that point.
</para>
</footnote>
as shown below:
<programlisting> <programlisting>
static void static void
maman_ibaz_base_init (gpointer g_iface) maman_ibaz_default_init (gpointer g_iface)
{ {
static gboolean is_initialized = FALSE;
if (!is_initialized)
{
g_object_interface_install_property (g_iface, g_object_interface_install_property (g_iface,
g_param_spec_string ("name", g_param_spec_string ("name",
"Name", "Name",
"Name of the MamanIbaz", "Name of the MamanIbaz",
"maman", "maman",
G_PARAM_READWRITE)); G_PARAM_READWRITE));
is_initialized = TRUE;
}
} }
</programlisting> </programlisting>
</para> </para>
@ -1152,9 +1153,9 @@ maman_ibaz_base_init (gpointer g_iface)
</para> </para>
<para> <para>
An implementation shall declare and define it's properties in the usual An implementation declares and defines it's properties in the usual
way as explained in <xref linkend="gobject-properties"/>, except for one way as explained in <xref linkend="gobject-properties"/>, except for one
small change: it must declare the properties of the interface it small change: it can declare the properties of the interface it
implements using <function><link linkend="g-object-class-override-property">g_object_class_override_property</link></function> implements using <function><link linkend="g-object-class-override-property">g_object_class_override_property</link></function>
instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. instead of <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
The following code snippet shows the modifications needed in the The following code snippet shows the modifications needed in the
@ -1233,6 +1234,118 @@ maman_baz_class_init (MamanBazClass *klass)
</para> </para>
</sect1> </sect1>
<sect1 id="howto-interface-override">
<title>Overriding interface methods</title>
<para>
If a base class already implements an interface, and in a derived
class you wish to implement the same interface overriding only certain
methods of that interface, you just reimplement the interface and
set only the interface methods you wish to override.
</para>
<para>
In this example MamanDerivedBaz is derived from MamanBaz. Both
implement the MamanIbaz interface. MamanDerivedBaz only implements one
method of the MamanIbaz interface and uses the base class implementation
of the other.
<programlisting>
static void
maman_derived_ibaz_do_action (MamanIbaz *ibaz)
{
MamanDerivedBaz *self = MAMAN_DERIVED_BAZ (ibaz);
g_print ("DerivedBaz implementation of Ibaz interface Action\n");
}
static void
maman_derived_ibaz_interface_init (MamanIbazInterface *iface)
{
/* Override the implementation of do_action */
iface->do_action = maman_derived_ibaz_do_action;
/*
* We simply leave iface->do_something alone, it is already set to the
* base class implementation.
*/
}
G_DEFINE_TYPE_WITH_CODE (MamanDerivedBaz, maman_derived_baz, MAMAN_TYPE_BAZ,
G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ,
maman_derived_ibaz_interface_init)
static void
maman_derived_baz_class_init (MamanDerivedBazClass *klass)
{
}
static void
maman_derived_baz_init (MamanDerivedBaz *self)
{
}
</programlisting>
</para>
<para>
To access the base class interface implementation use
<function><link linkend="g-type-interface-peek-parent">g_type_interface_peek_parent</link></function>
from within an interface's <function>default_init</function> function.
</para>
<para>
If you wish to call the base class implementation of an interface
method from an derived class where than interface method has been
overridden then you can stash away the pointer returned from
<function><link linkend="g-type-interface-peek-parent">g_type_interface_peek_parent</link></function>
in a global variable.
</para>
<para>
In this example MamanDerivedBaz overides the
<function>do_action</function> interface method. In it's overridden method
it calls the base class implementation of the same interface method.
<programlisting>
static MamanIbazInterface *maman_ibaz_parent_interface = NULL;
static void
maman_derived_ibaz_do_action (MamanIbaz *ibaz)
{
MamanDerivedBaz *self = MAMAN_DERIVED_BAZ (ibaz);
g_print ("DerivedBaz implementation of Ibaz interface Action\n");
/* Now we call the base implementation */
maman_ibaz_parent_interface->do_action (ibaz);
}
static void
maman_derived_ibaz_interface_init (MamanIbazInterface *iface)
{
maman_ibaz_parent_interface = g_type_interface_peek_parent (iface);
iface->do_action = maman_derived_ibaz_do_action;
}
G_DEFINE_TYPE_WITH_CODE (MamanDerivedBaz, maman_derived_baz, MAMAN_TYPE_BAZ,
G_IMPLEMENT_INTERFACE (MAMAN_TYPE_IBAZ,
maman_derived_ibaz_interface_init)
static void
maman_derived_baz_class_init (MamanDerivedBazClass *klass)
{
}
static void
maman_derived_baz_init (MamanDerivedBaz *self)
{
}
</programlisting>
</para>
</sect1>
</chapter> </chapter>
<!-- End Howto Interfaces --> <!-- End Howto Interfaces -->