Subclassing GObject
This page describes how to create a subclass of GObject in C, using best standard practices.
Preconditions
To use the instructions in this page, you need to be using GLib 2.44 or later (or git master as of February 2015). Additionally, the class that you are subclassing must support GLib's new auto-cleanup functionality (as a requirement of using the type declaration macros below). All classes in GLib and Gtk have this support.
Naming and conventions
In general, the program or library that you are working on should have a namespace that is used as the first part of the name of all of the classes that it contains. Gtk uses the prefix Gtk, GLib uses the prefix G, and so on.
Following this, you'll need a descriptive name for what the class is doing. This is typically a noun.
In our example, we'll assume that our namespace is MyApp and we'll make a class called MyAppWindow which is a subclass of GtkApplicationWindow.
When you define a class, it is expected that you will also define some additional standard macros that are used with that class. These macros are available for all object types. In our case these would be:
MY_APP_TYPE_WINDOW — a macro that evaluates to the GType of your new object type
MY_APP_WINDOW — a type-checking macro that casts GObject instances to your pointer type
MY_APP_IS_WINDOW — a macro for checking if a given GObject is an instance of your object type
- derivable classes will also contain other macros to help with further subclassing them
- all methods related to your class should have names starting with
my_app_window_ as a way to distinguish them from methods of other classes
a constructor function (my_app_window_new) will typically be provided
Most of the above macros will be written for you automatically if you follow the templates below.
File names
Nominally, each subclass is contained in its own separate .c file with an associated .h file. The .c file contains the implementation of the class and the .h describes the public interface of the class that is visible to its users.
Filenames are typically in lowercase and separated by dashes (-) in the places that you'd have underscores in the function names. In our example, we would expect to have files named my-app-window.c and my-app-window.h.
Two styles for subclassing
There are two styles of creating subclasses.
The difference between them is if you intend for your subclass to be further subclassed.
If your subclass will not be further subclassed then it is said to be "final". If your subclass wants to support further subclassing then it is "derivable".
A final class has several advantages:
- it is easier to implement a final subclass
- when creating a library, it is easier to maintain API and ABI compatibility
- if you create a final subclass because more of the implementation details are hidden from the users of the library
A derivable class has the advantage of being subclassable.
In general, it is better to make a class final unless you know that it needs to be derivable. It is always possible to make a final class derivable later without breaking API or ABI compatibility, but not the other way around.
Final class
Here is an example of creating our subclass as a final class.
my-app-window.h:
/* Copyright YEAR Copyright Holder * * Licence text goes here * * Author: you <your@email> */ #ifndef _my_app_window_h_ #define _my_app_window_h_ G_BEGIN_DECLS #define MY_APP_TYPE_WINDOW (my_app_window_get_type ()) G_DECLARE_FINAL_TYPE(MyAppWindow, my_app_window, MY_APP, WINDOW, GtkApplicationWindow) MyAppWindow * my_app_window_new (void); G_END_DECLS #endif /* _my_app_window_h_ */
my-app-window.c:
/* Copyright YEAR Copyright Holder * * Licence text goes here * * Author: you <your@email> */ #include "my-app-window.h" struct _MyAppWindow { GtkApplicationWindow parent_instance; // instance variables for subclass go here }; G_DEFINE_TYPE(MyAppWindow, my_app_window, GTK_TYPE_APPLICATION_WINDOW) static void my_app_window_init (MyAppWindow *window) { // initialisation goes here } static void my_app_window_class_init (MyAppWindowClass *class) { // virtual function overrides go here // property and signal definitions go here } MyAppWindow * my_app_window_new (void) { return g_object_new (MY_APP_TYPE_WINDOW, NULL); }
Some notes about the above:
- Each file should contain a comment at the top with information about the copyright owner, the licence information and the author of the file. The copyright information is required for legal reasons. The name of the author and the email address are useful for others who read the file and may have questions about its contents.
the #ifndef, #define and #endif in the header form something called a single include guard and is used to prevent the content of the header from being included more than once
The G_DECLARE_FINAL_TYPE macro takes your C structure name (MyAppWindow), the uppercase namespace name of your project (MY_APP), the uppercase name of your class (WINDOW), the lowercase prefix of your C functions (my_app_window) and the class name of your parent class (GtkApplicationWindow). These names are used to create the various macros that are expected to exist for your type, as well as defining its "Class" structure.
MY_APP_TYPE_WINDOW must be manually declared because it is not possible for the macro to emit a non-function macro for this definition
The struct _MyAppWindow definition is expected in this form (type name prefixed by _) by the type declaration macros.
The first item in your structure must be of the type of your parent class and should be named parent_instance. This must be a direct inclusion of the parent type. Do not use a pointer. If you get this part wrong, your program will very likely crash in obscure and confusing ways.
The G_DEFINE_TYPE macro takes the name of your class (MyAppWindow), the C function name prefix (my_app_window) and the GType of your parent class (GTK_TYPE_APPLICATION_WINDOW).
The gtk_app_window_init() and gtk_app_window_class_init() functions are expected to exist by the type definition macro.
As a general rule, _new() functions should only call g_object_new() with the passed in arguments as properties. If your class has extra code in _new() then it will be difficult (or impossible) to subclass or to use from language bindings.
Derivable class
Here is an example of creating a derivable class. Let's create a GtkLabel subclass called MyAppLabel.
my-app-label.h:
/* Copyright YEAR Copyright Holder * * Licence text goes here * * Author: you <your@email> */ #ifndef _my_app_label_h_ #define _my_app_label_h_ G_BEGIN_DECLS #define MY_APP_TYPE_LABEL (my_app_label_get_type ()) G_DECLARE_DERIVABLE_TYPE(MyAppLabel, my_app_label, MY_APP, LABEL, GtkApplicationLabel) struct _MyAppLabelClass { GtkLabelClass parent_class; gchar * (* transform_text) (MyAppLabel *label, const gchar *text); /*< private >*/ gpointer _padding[10]; }; MyAppLabel * my_app_label_new (void); void my_app_label_set_text (MyAppLabel *label, const gchar *text); G_END_DECLS #endif /* _my_app_label_h_ */
my-app-label.c:
/* Copyright YEAR Copyright Holder * * Licence text goes here * * Author: you <your@email> */ #include "my-app-label.h" typedef struct { guint num_changes; } MyAppLabelPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MyAppLabel, my_app_label, GTK_TYPE_APPLICATION_LABEL) static gchar * my_app_label_real_transform_text (MyAppLabel *label, const gchar *text, guint change_nr) { return g_strdup_printf ("%d %s", change_nr, text); } static void my_app_label_init (MyAppLabel *label) { // initialisation goes here } static void my_app_label_class_init (MyAppLabelClass *class) { class->transform_text = my_app_label_real_transform_text; } void my_app_label_transform_text (MyAppLabel *label, const gchar *text, guint change_nr) { g_return_if_fail (G_IS_MY_APP_LABEL (label)); return MY_APP_LABEL_GET_CLASS(label)->transform_text (label, text, change_nr); } void my_app_label_set_text (MyAppLabel *label, const gchar *text) { MyAppLabelPrivate *priv = my_app_label_get_instance_private (label); guint change_nr = priv->num_changes++; gchar *transformed; transformed = my_app_label_transform_text (label, text, change_nr); gtk_label_set_text (GTK_LABEL (label), transformed); g_free (transformed); } MyAppLabel * my_app_label_new (void) { return g_object_new (MY_APP_TYPE_LABEL, NULL); }
As compared with the other example, there are a few noticeable changes:
The header file now contains the definition of a _MyAppLabelClass structure. This structure is required when using G_DECLARE_DERIVABLE_TYPE. It contains the vtable of your class so that virtual functions can be overridden by subclasses.
There is an example of how to do a virtual function. You need a function pointer in the Class structure, a wrapper function (my_app_label_transform_text) and a default implementation (my_app_label_real_transform_text). You set the default implementation during your class_init function and the wrapper calls it. If a subclass wants to override it then they can do so from their own class_init function, but if they do not, then your default implementation will be used.
Because your MyAppLabel structure must be public (in order to be embedded in the instance structures of those who subclass you) you must use a MyAppLabelPrivate structure to hold the instance variables. This avoids issues with having to change API or ABI when changing the instances variables of the class.
You get access to the Private structure using my_app_label_get_instance_private().