add chain up section

This commit is contained in:
Mathieu Lacage 2004-06-10 09:41:43 +00:00
parent ff8ade82ff
commit 33129dca91

View File

@ -592,30 +592,6 @@ maman_bar_class_init (MamanBarClass *klass)
<para>
Children can then implement the subclass with code such as:
<programlisting>
static void
maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
{
MamanBarClass *bar_class = MAMAN_BAR_CLASS (klass);
/* implement pure virtual class function. */
bar_class->do_specific_action_one = maman_bar_subtype_do_specific_action_one;
}
</programlisting>
</para>
<para>
Finally, it is interesting to note that, just like in C++, it is possible
to make each object class method chain to its parent class method:
<programlisting>
static void
maman_bar_real_do_action_two (MamanBar *self, /* parameters */)
{
MamanBarClass *bar_class = g_type_class_peek_parent (klass);
/* chain up */
bar_class->do_action (self, /* parameters */);
/* do local stuff here. */
}
static void
maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
{
@ -631,14 +607,68 @@ maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
<sect2 id="howto-gobject-chainup">
<title>Chaining up</title>
<p>Chaining up is commonly used to implement the Chain Of Responsability pattern in C++: each class in a
given inheritance hierarchy is expected to override the same method and then call from within each method
the overriden method of the parent. Personally, I am not sure this is a very smart idea (a detailed explanation
of why I think it is a bad idea would take too much space for this document) but I can show you how to do it and
here is an example.
</p>
<para>Chaining up is often loosely defined by the folowing set of conditions:
<itemizedlist>
<listitem><para>Parent class A defines a public virtual method named <function>foo</function> and
provides a default implementation.</para></listitem>
<listitem><para>Child class B re-implements method <function>foo</function>.</para></listitem>
<listitem><para>In the method B::foo, the child class B calls its parent class method A::foo.</para></listitem>
</itemizedlist>
There are many uses to this idiom:
<itemizedlist>
<listitem><para>You need to change the behaviour of a class without modifying its code. You create
a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour
slightly and chain up to ensure that the previous behaviour is not really modifed, just extended.
</para></listitem>
<listitem><para>You are lazy, you have access to the source code of the parent class but you don't want
to modify it to add method calls to new specialized method calls: it is faster to hack the child class
to chain up than to modify the parent to call down.</para></listitem>
<listitem><para>You need to implement the Chain Of Responsability pattern: each object of the inheritance
tree chains up to its parent (typically, at the begining or the end of the method) to ensure that
they each handler is run in turn.</para></listitem>
</itemizedlist>
I am personally not really convinced any of the last two uses are really a good idea but since this
programming idiom is often used, this section attemps to explain how to implement it.
</para>
<p>To invoke the parent method XXX</p>
<para>To explicitely chain up to the implementation of the virtual method in the parent class,
you first need a handle to the original parent class structure. This pointer can then be used to
access the original class function pointer and invoke it directly.
<footnote>
<para>The <emphasis>original</emphasis> adjective used in this sentence is not innocuous. To fully
understand its meaning, you need to recall how class structures are initialized: for each object type,
the class structure associated to this object is created by first copying the class structure of its
parent type (a simple <function>memcpy</function>) and then by invoking the class_init callback on
the resulting class structure. Since the class_init callback is responsible for overwriting the class structure
with the user re-implementations of the class methods, we cannot merely use the modified copy of the parent class
structure stored in our derived instance. We want to get a copy of the class structure of an instance of the parent
class.
</para>
</footnote>
</para>
<para>The function <function>g_type_class_peek_parent</function> is used to access the original parent
class structure. Its input is a pointer to the class of the derived object and it returns a pointer
to the original parent class structure. The code below shows how you could use it:
<programlisting>
static void
b_method_to_call (B *obj, int a)
{
BClass *klass;
AClass *parent_class;
klass = B_GET_CLASS (obj);
parent_class = g_type_class_peek_parent (klass);
/* do stuff before chain up */
parent_class->method_to_call (obj, a);
/* do stuff after chain up */
}
</programlisting>
A lot of people who use this idiom in GTK+ store the parent class structure pointer in a global static
variable to avoid the costly call to <function>g_type_class_peek_parent</function> for each function call.
Typically, the class_init callback initializes the global static variable. <filename>gtk/gtkhscale.c</filename>
does this.
</para>
</sect2>
@ -695,7 +725,7 @@ GType maman_ibaz_get_type (void);
void maman_ibaz_do_action (MamanIbaz *self);
#endif //MAMAN_IBAZ_H
#endif /*MAMAN_IBAZ_H*/
</programlisting>
This code is almost exactly similar to the code for a normal <type>GType</type>
which derives from a <type>GObject</type> except for a few details: