To specify that an interface requires the presence of other interfaces when implemented, GObject introduces the concept of prerequisites: it is possible to associate a list of prerequisite types to an interface. For example, if object A wishes to implement interface I1, and if interface I1 has a prerequisite on interface I2, A has to implement both I1 and I2.
The mechanism described above is, in practice, very similar to Java's interface I1 extends interface I2. The example below shows the GObject equivalent:
1 2 |
/* Make the ViewerEditableLossy interface require ViewerEditable interface. */ G_DEFINE_INTERFACE (ViewerEditableLossy, viewer_editable_lossy, VIEWER_TYPE_EDITABLE) |
In the G_DEFINE_INTERFACE
call above, the third parameter defines the prerequisite type. This
is the GType of either an interface or a class. In this case
the ViewerEditable interface is a prerequisite of
ViewerEditableLossy. The code
below shows how an implementation can implement both interfaces and
register their implementations:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
static void viewer_file_editable_lossy_compress (ViewerEditableLossy *editable) { ViewerFile *self = VIEWER_FILE (editable); g_print ("File implementation of lossy editable interface compress method: %s.\n", self->filename); } static void viewer_file_editable_lossy_interface_init (ViewerEditableLossyInterface *iface) { iface->compress = viewer_file_editable_lossy_compress; } static void viewer_file_editable_save (ViewerEditable *editable, GError **error) { ViewerFile *self = VIEWER_FILE (editable); g_print ("File implementation of editable interface save method: %s.\n", self->filename); } static void viewer_file_editable_undo (ViewerEditable *editable, guint n_steps) { ViewerFile *self = VIEWER_FILE (editable); g_print ("File implementation of editable interface undo method: %s.\n", self->filename); } static void viewer_file_editable_redo (ViewerEditable *editable, guint n_steps) { ViewerFile *self = VIEWER_FILE (editable); g_print ("File implementation of editable interface redo method: %s.\n", self->filename); } static void viewer_file_editable_interface_init (ViewerEditableInterface *iface) { iface->save = viewer_file_editable_save; iface->undo = viewer_file_editable_undo; iface->redo = viewer_file_editable_redo; } static void viewer_file_class_init (ViewerFileClass *klass) { /* Nothing here. */ } static void viewer_file_init (ViewerFile *self) { /* Instance variable initialisation code. */ } G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, viewer_file_editable_interface_init) G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE_LOSSY, viewer_file_editable_lossy_interface_init)) |
It is very important to notice that the order in which interface
implementations are added to the main object is not random:
g_type_add_interface_static
,
which is called by
G_IMPLEMENT_INTERFACE
,
must be invoked first on the interfaces which have no prerequisites and then on
the others.