The GObject base class

Object instanciation
Object memory management
Reference count
Weak References
Reference counts and cycles
Object properties
Accessing multiple properties at once

The two previous chapters discussed the details of Glib's Dynamic Type System and its signal control system. The GObject library also contains an implementation for a base fundamental type named GObject.

GObject is a fundamental classed instantiable type. It implements:

All the GNOME libraries which use the GLib type system (like Gtk+ and GStreamer) inherit from GObject which is why it is important to understand the details of how it works.

Object instanciation

The g_object_new family of functions can be used to instantiate any GType which inherits from the GObject base type. All these functions make sure the class and instance structures have been correctly initialized by glib's type system and then invoke at one point or another the constructor class method which is used to:

  • Allocate and clear memory through g_type_create_instance,

  • Initialize the object' instance with the construction properties.

Although one can expect all class and instance members (except the fields pointing to the parents) to be set to zero, some consider it good practice to explicitly set them.

Objects which inherit from GObject are allowed to override this constructor class method: they should however chain to their parent constructor method before doing so:

  GObject*   (*constructor)     (GType                  type,
                                 guint                  n_construct_properties,
                                 GObjectConstructParam *construct_properties);

The example below shows how MamanBar overrides the parent's constructor:

#define MAMAN_TYPE_BAR                  (maman_bar_get_type ())
#define MAMAN_BAR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
#define MAMAN_BAR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
#define MAMAN_IS_BAR(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
#define MAMAN_BAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))

typedef struct _MamanBar MamanBar;
typedef struct _MamanBarClass MamanBarClass;

struct _MamanBar {
  GObject parent;
  /* instance members */
};

struct _MamanBarClass {
  GObjectClass parent;

  /* class members */
};

/* used by MAMAN_TYPE_BAR */
GType maman_bar_get_type (void);

static GObject *
maman_bar_constructor (GType                  type,
                       guint                  n_construct_properties,
                       GObjectConstructParam *construct_properties)
{
  GObject *obj;

  {
    /* Invoke parent constructor. */
    MamanBarClass *klass;
    GObjectClass *parent_class;  
    klass = MAMAN_BAR_CLASS (g_type_class_peek (MAMAN_TYPE_BAR));
    parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
    obj = parent_class->constructor (type,
                                     n_construct_properties,
                                     construct_properties);
  }
  
  /* do stuff. */

  return obj;
}

static void
maman_bar_instance_init (GTypeInstance   *instance,
                         gpointer         g_class)
{
  MamanBar *self = (MamanBar *)instance;
  /* do stuff */
}

static void
maman_bar_class_init (gpointer g_class,
                      gpointer g_class_data)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
  MamanBarClass *klass = MAMAN_BAR_CLASS (g_class);

  gobject_class->constructor = maman_bar_constructor;
}

GType maman_bar_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    static const GTypeInfo info = {
      sizeof (MamanBarClass),
      NULL,   /* base_init */
      NULL,   /* base_finalize */
      maman_bar_class_init,   /* class_init */
      NULL,   /* class_finalize */
      NULL,   /* class_data */
      sizeof (MamanBar),
      0,      /* n_preallocs */
      maman_bar_instance_init    /* instance_init */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "MamanBarType",
                                   &info, 0);
  }
  return type;
}

If the user instantiates an object MamanBar with:

MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);

If this is the first instantiation of such an object, the maman_b_class_init function will be invoked after any maman_b_base_class_init function. This will make sure the class structure of this new object is correctly initialized. Here, maman_bar_class_init is expected to override the object's class methods and setup the class' own methods. In the example above, the constructor method is the only overridden method: it is set to maman_bar_constructor.

Once g_object_new has obtained a reference to an initialized class structure, it invokes its constructor method to create an instance of the new object. Since it has just been overridden by maman_bar_class_init to maman_bar_constructor, the latter is called and, because it was implemented correctly, it chains up to its parent's constructor. The problem here is how we can find the parent constructor. An approach (used in GTK+ source code) would be to save the original constructor in a static variable from maman_bar_class_init and then to re-use it from maman_bar_constructor. This is clearly possible and very simple but I was told it was not nice and the prefered way is to use the g_type_class_peek and g_type_class_peek_parent functions.

Finally, at one point or another, g_object_constructor is invoked by the last constructor in the chain. This function allocates the object's instance' buffer through g_type_create_instance which means that the instance_init function is invoked at this point if one was registered. After instance_init returns, the object is fully initialized and should be ready to answer any user-request. When g_type_create_instance returns, g_object_constructor sets the construction properties (ie: the properties which were given to g_object_new) and returns to the user's constructor which is then allowed to do useful instance initialization...

The process described above might seem a bit complicated (it is actually overly complicated in my opinion..) but it can be summarized easily by the table below which lists the functions invoked by g_object_new and their order of invocation.

The array below lists the functions invoked by g_object_new and their order of invocation:

Table 4. g_object_new

Invocation time Function Invoked Function's parameters Remark
First call to g_object_new for target type target type's base_init function On the inheritance tree of classes from fundamental type to target type. base_init is invoked once for each class structure. I have no real idea on how this can be used. If you have a good real-life example of how a class' base_init can be used, please, let me know.
target type's class_init function On target type's class structure Here, you should make sure to initialize or override class methods (that is, assign to each class' method its function pointer) and create the signals and the properties associated to your object.
interface' base_init function On interface' vtable  
interface' interface_init function On interface' vtable  
Each call to g_object_new for target type target type's class constructor method: GObjectClass->constructor On object's instance If you need to complete the object initialization after all the construction properties are set, override the constructor method and make sure to chain up to the object's parent class before doing your own initialization. In doubt, do not override the constructor method.
type's instance_init function On the inheritance tree of classes from fundamental type to target type. the instance_init provided for each type is invoked once for each instance structure. Provide an instance_init function to initialize your object before its construction properties are set. This is the preferred way to initialize a GObject instance. This function is equivalent to C++ constructors.


Readers should feel concerned about one little twist in the order in which functions are invoked: while, technically, the class' constructor method is called before the GType's instance_init function (since g_type_create_instance which calls instance_init is called by g_object_constructor which is the top-level class constructor method and to which users are expected to chain to), the user's code which runs in a user-provided constructor will always run after GType's instance_init function since the user-provided constructor must (you've been warned) chain up before doing anything useful.