使用GObject模拟实现接口ide
G_DEFINE_TYPE_WITH_CODE
和G_IMPLEMENT_INTERFACE
替代G_DEFINE_TYPE
来实现类定义static void viewer_file_editable_interface_init (ViewerEditableInterface *iface); G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, viewer_file_editable_interface_init))
viewer_file_editable_interface_init
,接口内声明的每一个虚函数指针都要被赋予实现static void viewer_file_editable_save (ViewerFile *self, GError **error) { g_print ("File implementation of editable interface save method: %s.\n", self->filename); } static void viewer_file_editable_undo (ViewerFile *self, guint n_steps) { g_print ("File implementation of editable interface undo method: %s.\n", self->filename); } static void viewer_file_editable_redo (ViewerFile *self, guint n_steps) { 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_init (ViewerFile *self) { /* Instance variable initialisation code. */ }
若是一个接口的实现依赖另外一个接口的实现,有点相似继承,那么首先按照上面的方式实现两个接口的定义,而后在定义GType
的时候依次使用G_IMPLEMENT_INTERFACE
添加两个接口的实现。函数
/* Make the ViewerEditableLossy interface require ViewerEditable interface. */ G_DEFINE_INTERFACE (ViewerEditableLossy, viewer_editable_lossy, VIEWER_TYPE_EDITABLE); 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))
接口一样也能够拥有属性,不过是使用g_object_interface_install_property
函数而不是像定义GType
同样使用g_object_class_install_property
函数来安装属性,以下所示:学习
static void viewer_editable_default_init (ViewerEditableInterface *iface) { g_object_interface_install_property (iface, g_param_spec_double ("autosave-frequency", "Autosave frequency", "Frequency (in per-seconds) to autosave backups of the editable content at Or zero to disable autosaves.", 0.0, /* minimum */ G_MAXDOUBLE, /* maximum */ 0.0, /* default */ G_PARAM_READWRITE)); }
须要值得注意的一点是ui
ViewerAudioFile继承自ViewerFile,二者都实现了ViewerEditable接口。ViewerAudioFile仅实现了ViewerEditable接口的其中一个方法,其余接口方法使用基类ViewerFile的实现,以下所示:指针
static void viewer_audio_file_editable_save (ViewerEditable *editable, GError **error) { ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); g_print ("Audio file implementation of editable interface save method.\n"); } static void viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) { /* Override the implementation of save(). */ iface->save = viewer_audio_file_editable_save; /* * Leave iface->undo and ->redo alone, they are already set to the * base class implementation. */ } G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, viewer_audio_file_editable_interface_init)) static void viewer_audio_file_class_init (ViewerAudioFileClass *klass) { /* Nothing here. */ } static void viewer_audio_file_init (ViewerAudioFile *self) { /* Nothing here. */ }
在接口的default_init
函数里面使用g_type_interface_peek_parent
函数能够获取基类的接口实现,可将其保存到全局变量中供其余函数使用。下面的例子中,ViewerAudioFile
重写了接口的save
函数,并在重写函数中直接调用基类ViewerFile
接口的save
函数实现。code
static ViewerEditableInterface *viewer_editable_parent_interface = NULL; static void viewer_audio_file_editable_save (ViewerEditable *editable, GError **error) { ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); g_print ("Audio file implementation of editable interface save method.\n"); /* Now call the base implementation */ viewer_editable_parent_interface->save (editable, error); } static void viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) { viewer_editable_parent_interface = g_type_interface_peek_parent (iface); iface->save = viewer_audio_file_editable_save; } G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, viewer_audio_file_editable_interface_init)) static void viewer_audio_file_class_init (ViewerAudioFileClass *klass) { /* Nothing here. */ } static void viewer_audio_file_init (ViewerAudioFile *self) { /* Nothing here. */ }