GObject and inheritance

I was doing some serious software on Glib. And I realized that there's some topics I don't really understand. IRC also didn't help so...

When we are doing inheritance, we can have two clases. The first one A inherits from GObject directly, B inherits from A. Then I came to this:

https://developer.gnome.org/gobject/stable/chapter-gobject.html

static void
viewer_file_constructed (GObject *obj)
{
  /* update the object state depending on constructor properties */

  /* Always chain up to the parent constructed function to complete object
   * initialisation. */
  G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj);
}

static void
viewer_file_class_init (ViewerFileClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->constructed = viewer_file_constructed;
}

But when you have this kind of arrangement. The child class does this: object_class->constructed = viewer_file_constructed; in B overriding in fact the only memory address for constructed. So it means that G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj); will call B->constructed recursively. And it's not what we want.

Maybe I don't understand but I suppose that the memory structure in B is as this:

struct _B
{
  A parent_instance;

  /* instance members */
};

The internal representation should be something like:

[   Gobject struct memory ]
[                         ]
[   Gobject variables     ]
[   A struct memory       ]
[   A variables           ] 
[                         ]
[   B struct memory       ]
[   B variables           ] 

So the GObject memory when casting in B is the shared by B and A classing. And all addresses are the same on the same i...

Is this correct? So if I want to overwrite constructed... Do I have to save the pointer that had before and then overwrite it in init with mine? So I can call the original one after I do my processing?

The same applies with the properties. Because A defines it's properties by an enum, that can go from 0 to N.

So I suppose that B properties should start at N, not 0. Otherwise the properties of A are handled by B and maybe with different data structures, and names.

Check this: https://developer.gnome.org/gobject/stable/gobject-properties.html

enum
{
  PROP_FILENAME = 1,
  PROP_ZOOM_LEVEL,
  N_PROPERTIES
};

If both clases defines a property with index 1. There will be a problem there because glib doesn't know who should handle. I suppose the child class B will handle it but improperly because maybe B is waiting, say a PROP_DIRECTORY, but since the index is the same. Would glib able to send to right instance?

I can only thing it will work if on register glib will add some offset depending on hierarchy level. Can someone explain how this really works? I cannot find any document with desired technical detail.

Upvotes: 1

Views: 2586

Answers (1)

Philip Withnall
Philip Withnall

Reputation: 5705

The internal representation should be something like:

Not quite. There’s a different between the GObject and GObjectClass structs. There’s one GObject struct instance per object instance, but only one GObjectClass instance for the entire class.

If you have a class FooBar deriving from GObject, the FooBarClass struct will look something like:

typedef struct
{
  GObjectClass parent_class;

  /* Virtual methods for FooBar instances: */
  void (*vfunc) (FooBar *self);
} FooBarClass;

There will be an instance of FooBarClass on the heap. Since it contains the entire GObjectClass struct as its parent_class member, that means it has its own finalize, dispose, get_property, etc. virtual method pointers.

Separately in the heap, there is an instance of GObjectClass for the GObject type. It contains another set of finalize, dispose, etc. virtual method pointers.

Since FooBar derives from GObject, foo_bar_parent_class will be set to point to the GObjectClass instance. This is what allows chaining up.

So if you want to implement the constructed virtual method and chain up (you must chain up constructed), just do as the example code in the documentation you linked to does. It is correct.


The same applies with the properties. Because A defines it's properties by an enum, that can go from 0 to N.

Incorrect. When a property is registered with a class using g_object_class_install_properties(), the property indices are associated with the GObjectClass instance inside the class struct for that class. They are not associated with the stand-along GObjectClass struct for the GObject type. This is the same principle as above.

In other words, there is no global registry of property indices: it’s all done per-class. So you can (and should) start the indexing of properties from 1 for each of your classes. They will not conflict.

Note that, as stated in the documentation for g_object_class_install_properties(), the property index 0 is special, and must not be used. You must start your property indexing from 1.


As ptomato says, this is way beyond the level of detail appropriate for the documentation. You should read the source code.

Upvotes: 7

Related Questions