一、接口定义
GObject接口如何工作的理论在“非实例化类类型:接口”一节中给出。 本节介绍如何定义和实现一个接口。
第一步是实现头文件。 该接口定义了两种方法:
/*
* Copyright/Licensing information.
*/
#ifndef __VIEWER_EDITABLE_H__
#define __VIEWER_EDITABLE_H__
#include <glib-object.h>
G_BEGIN_DECLS
#define VIEWER_TYPE_EDITABLE viewer_editable_get_type ()
G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject)
struct _ViewerEditableInterface
{
GTypeInterface parent_iface;
void (*save) (ViewerEditable *self,
GError **error);
void (*undo) (ViewerEditable *self,
guint n_steps);
void (*redo) (ViewerEditable *self,
guint n_steps);
};
void viewer_editable_save (ViewerEditable *self,
GError **error);
void viewer_editable_undo (ViewerEditable *self,
guint n_steps);
void viewer_editable_redo (ViewerEditable *self,
guint n_steps);
G_END_DECLS
#endif /* __VIEWER_EDITABLE_H__ */
该代码与继承自GObject的普通GType的代码相同,除了几个细节:
1、_GET_CLASS函数称为_GET_IFACE(由G_DECLARE_INTERFACE定义)。
2、实例类型ViewerEditable没有被完全定义:它仅被用作一个抽象类型,它表示实现该接口的任何对象的一个实例。
3、ViewerEditableInterface的父级是GTypeInterface,而不是GObjectClass。
ViewerEditable类型本身的实现是微不足道的:
1、G_DEFINE_INTERFACE创建一个viewer_editable_get_type函数,该函数在类型系统中注册类型。第三个参数用于定义一个先决条件接口(稍后我们再讨论一下)。当接口没有先决条件时,只需为此参数传递0。
2、viewer_editable_default_init预计会注册接口的信号,如果有的话(稍后会看到如何使用它们)。
3、接口方法viewer_editable_save,viewer_editable_undo和viewer_editable_redo取消引用接口结构以访问其关联的接口函数并调用它。
G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT);
static void
viewer_editable_default_init (ViewerEditableInterface *iface)
{
/* add properties and signals to the interface here */
}
void
viewer_editable_save (ViewerEditable *self,
GError **error)
{
ViewerEditableInterface *iface;
g_return_if_fail (VIEWER_IS_EDITABLE (self));
g_return_if_fail (error == NULL || *error == NULL);
iface = VIEWER_EDITABLE_GET_IFACE (self);
g_return_if_fail (iface->save != NULL);
iface->save (self, error);
}
void
viewer_editable_undo (ViewerEditable *self,
guint n_steps)
{
ViewerEditableInterface *iface;
g_return_if_fail (VIEWER_IS_EDITABLE (self));
iface = VIEWER_EDITABLE_GET_IFACE (self);
g_return_if_fail (iface->undo != NULL);
iface->undo (self, n_steps);
}
void
viewer_editable_redo (ViewerEditable *self,
guint n_steps)
{
ViewerEditableInterface *iface;
g_return_if_fail (VIEWER_IS_EDITABLE (self));
iface = VIEWER_EDITABLE_GET_IFACE (self);
g_return_if_fail (iface->redo != NULL);
iface->redo (self, n_steps);
}
二、实现
一旦界面被定义,实现其实很简单的。
第一步是定义一个正常的Final GObject类,正如在“Boilerplate标题代码”一节中所述。
第二步是通过使用G_DEFINE_TYPE_WITH_CODE和G_IMPLEMENT_INTERFACE而不是G_DEFINE_TYPE定义来实现ViewerFile:
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))
类可以通过在对G_DEFINE_TYPE_WITH_CODE的调用中使用多次调用G_IMPLEMENT_INTERFACE来实现多个接口。
接口初始化函数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. */
}