Re: GObject: NULL virtual methods during instance init



On 10 Aug 2001, Owen Taylor wrote:

> 
> Gustavo J A M Carneiro <ee96090 fe up pt> writes:
> 
> >   I'm getting something weird. I have class A and class B, where class B
> > is derived from class A. Class A defines a virtual method, "vfunc",
> > which is pure virtual and only implemented in class B.
> > I created an instance of class B. During class A's instance init func
> > (but called with a B object) I try to invoke vfunc this way:
> > 
> >  AClass *class;
> >  class = A_GET_CLASS(self);
> >  if (class->vfunc)
> >     class->vfunc(self, args);
> > 
> > But at this point class->vfunc is NULL. I do initialize it correctly at
> > class B's class_init function.
> >   Generally, I've been using GObject with virtual methods for some time
> > and had no problem at all until now.
> >   Am I doing anything wrong here? What?
> >   Thanks in advance for any help.
> 
> In gtk_type_new() in GTK+-1.2 there is an explanation for this behavior.
> I think it's a little weird, but hard to change now.

this is not just "a little weird", we actually had good reasons to do this ;)

>   /* we need to call the base classes' object_init_func for derived
>    * objects with the object's ->klass field still pointing to the
>    * corresponding base class, otherwise overridden class functions
>    * could get called with partly-initialized objects. the real object
>    * class is passed as second argment to the initializers.
>    */

that's only half of the storry though. we used to do instanceB->klass = classB;
prior to invoking classA_init (instance); for gtk pre-1.2, or maybe even pre-1.0,
i forgot. but some C++ people (kenelson, codex?) pointed out how this is broken
in that classA_init() could invoke classA methods that are overridden in classB
and call these through instanceB->klass. classB functions usually expect the
B portion of instance to be setup correctly, and could blatantly crash if that
is not the case, but instance initialization of the instance's B portion hasn't
happened at classA_init() time, because initialization order happens down the
tree, i.e.:
g_object_init (instance);
classA_init (instance);
classB_init (instance);

it was also brought up that C++ would do (in GObject terms):

instance->klass = GObjectClass;
g_object_init (instance);
instance->klass = ClassA;
classA_init (instance);
instance->klass = ClassB;
classB_init (instance);

so the type system was changed to mimick this behaviour. however, i decided that,
occasionally, the resulting class _is_ required, which is why we now actually do:

instance->klass = GObjectClass;
g_object_init (instance, ClassB);
instance->klass = ClassA;
classA_init (instance, ClassB);
instance->klass = ClassB;
classB_init (instance, ClassB);

so initializers that need it, do have access to the real type of the object being
initialized.


hmmm, lemme dig a bit...
ok, original bug report on this appended.
>  
> Regards,
>                                         Owen
> 

---
ciaoTJ


Date: 12 Jul 1998 05:06:38 +0300
From: Tero Pulkkinen <terop students cc tut fi>
To: Christof Petig <christof petig wtal de>
Cc: glaurent worldnet fr, gtkdev gtk org
Subject: Re: Strange bug within gtkmm (perhaps wrong memory region)


(this goes to gtkdev and the other people who know about the problem
already..)

I think I've found a bug in gtk's object initialization code. It only
appears when people derive from a gtk object and where this object's
object_init() calls (directly, or indirectly) virtual functions. Gtk
calls the most derived class methods with partly initialized object,
when (I think) it should be called only those methods that has been
initialized using their object_init method.

This is what happens:
  we have a widget FooDialog derived from GtkDialog

  we create an FooDialog object
  it calls object_init and class_init functions of all base classes first
  then calls gtk_dialog_init, which calls virtual functions.
  (basically gtk_container_add()). This virtual function should
  be calling gtk_dialog_add(), because only dialog part of it has been
  initialized with gtk_dialog_init().

  But it calls foodialog_add() method with uninitialized object and this
  fails. (well, it is unreasonable that all derived class virtual methods
  should handle situation where part of the object is not initialized
  properly..) (also, C++ handles it like that with constructors...  :)

Below is patch that fixes it. Maybe its time for gtk1.0.5.

(This fixes the dialog problems some people have been having with glade and
gtk--.)

-- 
-- Tero Pulkkinen -- terop modeemi cs tut fi --

--- gtktypeutils.cc.old Sun Jul 12 03:43:37 1998
+++ gtktypeutils.c      Sun Jul 12 03:47:43 1998
@@ -280,16 +280,17 @@

   klass = gtk_type_class (type);
   object = g_malloc0 (node->type_info.object_size);
-  object->klass = klass;

   for (i = node->n_supers; i > 0; i--)
     {
       GtkTypeNode *pnode;

       LOOKUP_TYPE_NODE (pnode, node->supers[i]);
+      object->klass = pnode->klass;
       if (pnode->type_info.object_init_func)
        (* pnode->type_info.object_init_func) (object);
     }
+  object->klass = klass;
   if (node->type_info.object_init_func)
     (* node->type_info.object_init_func) (object);








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