Mastering GObject: A Practical Guide to C’s Object System
This article introduces GObject, the object‑oriented C framework from GLib, explains its core concepts, demonstrates how to define classes and instances with code examples, shows signal usage, and highlights its cross‑language interoperability for building robust software components.
Source code: https://gitlab.gnome.org/GNOME/glib/ Documentation: https://docs.gtk.org/gobject/index.html
1. Core Concepts of GObject
Dynamic type system – Types can be registered at runtime, allowing pure C programs to build fully object‑oriented modules.
Reference‑counted memory management – Each GObject carries an atomic reference count; g_object_ref() and g_object_unref() manage lifetime automatically.
Property system – Generic g_object_set() / g_object_get() functions work with GParamSpec descriptors, enabling uniform get/set semantics.
Signal mechanism – Objects can emit named signals and other objects can connect callbacks, providing a lightweight event system.
2. Basic Object and Class Structures
GObject separates the class description from each instance. The class structure is allocated once; the instance structure is allocated for every object.
typedef struct _GObject GObject; struct _GObject {
GTypeInstance g_type_instance;
/*< private >*/
guint ref_count; /* (atomic) */
GData *qdata;
}; struct _GObjectClass {
GTypeClass g_type_class;
/*< private >*/
GSList *construct_properties;
/*< public >*/
GObject* (*constructor)(GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties);
void (*set_property)(GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec);
void (*get_property)(GObject *object, guint property_id,
GValue *value, GParamSpec *pspec);
void (*dispose)(GObject *object);
void (*finalize)(GObject *object);
void (*dispatch_properties_changed)(GObject *object,
guint n_pspecs, GParamSpec **pspecs);
void (*notify)(GObject *object, GParamSpec *pspec);
void (*constructed)(GObject *object);
/*< private >*/
gsize flags;
gsize n_construct_properties;
gpointer pspecs;
gsize n_pspecs;
gpointer pdummy[3];
};3. Minimal Example – Creating and Inspecting Objects
#include <glib-object.h>
int main(int argc, char **argv) {
GObject *instance1, *instance2;
GObjectClass *class1, *class2;
/* Create two independent GObject instances */
instance1 = g_object_new(G_TYPE_OBJECT, NULL);
instance2 = g_object_new(G_TYPE_OBJECT, NULL);
g_print("instance1 address: %p
", instance1);
g_print("instance2 address: %p
", instance2);
/* Retrieve the shared class structure */
class1 = G_OBJECT_GET_CLASS(instance1);
class2 = G_OBJECT_GET_CLASS(instance2);
g_print("class address (instance1): %p
", class1);
g_print("class address (instance2): %p
", class2);
/* Release the objects */
g_object_unref(instance1);
g_object_unref(instance2);
return 0;
}Running the program prints two distinct instance addresses but the same class address, demonstrating that all instances of the same type share a single GObjectClass structure.
4. Defining and Emitting Signals
A typical workflow is:
Declare a static signal identifier array (e.g., file_signals[CHANGED]).
Register the signal with g_signal_newv() during class initialization.
Emit the signal at the appropriate point in the object’s method.
Connect user callbacks with g_signal_connect().
/* Register a "changed" signal for a file object */
file_signals[CHANGED] =
g_signal_newv("changed",
G_TYPE_FROM_CLASS(object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
NULL, NULL, NULL, NULL,
G_TYPE_NONE, /* return type */
0, NULL); /* no parameters */ /* Method that writes data and then notifies listeners */
void viewer_file_write(ViewerFile *self, const guint8 *buffer, gsize size) {
g_return_if_fail(VIEWER_IS_FILE(self));
g_return_if_fail(buffer != NULL || size == 0);
/* ... actual write logic ... */
g_signal_emit(self, file_signals[CHANGED], 0);
} /* Connect a callback to the signal */
g_signal_connect(file, "changed", (GCallback)changed_event, NULL);5. Cross‑Language Interoperability
Because the GObject type system is introspection‑aware, language bindings can be generated automatically. The same C library can be used from C++, Java, Python, Ruby, .NET/Mono, and many other environments, making GObject a common foundation for cross‑platform GUI toolkits (e.g., GTK) and other libraries.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
