你将学到什么

使用GObject模拟实现接口

使用接口

  • 首先按照学习笔记(一)定义一个普通的GObject类
  • 使用G_DEFINE_TYPE_WITH_CODEG_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));
}

需要值得注意的一点是

重写接口方法

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函数实现。

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. */
}
04-16 21:28