mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-06-08 13:50:07 +02:00
add chain up section
This commit is contained in:
parent
ff8ade82ff
commit
33129dca91
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user