使用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. */ }