GObject is a
GTypeInstance has its own system of constructing and initialising instances. It’s very simple: you call
GType allocates the necessary memory for the instance and then calls each
_init() function, from the base type to the most derived type. There are no properties here.
But we want to create a
GObject. That’s always done with
g_object_new(). The first thing that
g_object_new() does is to sort the properties that you pass to it into construct and non-construct properties. The list of construct properties is in the order that you passed them. Added to this list (at the end) are any construct properties that you did not pass to
g_object_new(), with their default values.
g_object_new() then calls the
constructor() virtual function for your class with the list of construct properties. This is usually the internal function
g_object_construct, but you can override it (but you must chain up). This is the first place that you can possibly intercept construction of a
g_type_create_instance() which results in all the
_init() functions being called (as described above). It then sets the construct properties in the order that they were given to
g_object_new() (with the default values at the end). This results in you getting a lot of
Then it returns. Your
constructor() override gets another chance to do things here if you want.
constructed() virtual function is called to let you know that we’re (almost) done. If you implement this then you need to chain up.
Finally, the non-construct properties that you passed to
g_object_new() are set in the order passed. More
_set_property() calls for you.
g_object_new() returns. A lot of people take this chance to do some extra things in their C API constructor function (but binding authors and those who want to subclass you may get angry if you do that).
The long and the short of it is that there are a bunch of different parts of your code that you can hook into to do various things during object construction (in order of when they are called):
constructor()override (before chainup) of each class from most derived to base
_init()function of each class from base to most derived
_set_property()function for each construct property given to
g_object_new(), in order
_set_property()function for each construct property not given to
constructor()override (after chainup) of each class from base to most derived
constructed()override (before chainup) of each class from most derived to base
constructed()override (after chainup) from each class from base to most derived
_set_property()for the remaining properties passed to
- whatever code you do in your
There are a few conclusion to draw from all of this that a lot of people first using
GObject are often surprised about:
- you do not have access to values of properties passed to
g_object_new()(even construct properties) from your
_init()function. You should think of
_init()as doing the work necessary to make it safe for
_set_property()calls to begin happening to your object.
_init()is not a great place to set values for properties on your parent class. If those properties are construct properties then they will later be reset to their default values by the later call to
_set_property()(even if the property was not passed to
g_object_new()). Consider using
constructed()for this instead.
- none-the-less, as a potential parent class, you should expect that your subclasses may attempt to set non-construct properties from their
_init()functions which means that you may end up seeing
_set_property()for non-construct properties before you see it for construct properties (delivered by
GObjectin the usual way).
And a couple more notes and general advice:
_init()doesn’t have access to any properties, you should limit it to simple always-the-same initialisation tasks such as setting up your
->privpointer or allocating internal arrays and hashtables or so on.
constructor()is difficult and ugly. Attempting to manipulate the property array that gets passed through is even more complicated. You almost certainly don’t want to do this unless you are doing something exceptionally evil.
constructed()is easy to override and at this point all your construct properties have been set. This is a good place to do the ‘heavy lifting’ of initialising your object that is dependent on construct properties. This is where
GSettingsopens its schemas, for example.
constructed()is somewhat less useful than it would have been if it was called after all properties (not just construct-only ones) were set, but we probably can’t change it at this point.