一、接口定义
GObject接口如何工作的理论在“非实例化类类型:接口”一节中给出。 本节介绍如何定义和实现一个接口。 第一步是取一个正确的名称。 该接口定义了两种方法:
/* * Copyright/Licensing information. */#ifndef __VIEWER_EDITABLE_H__#define __VIEWER_EDITABLE_H__#includeG_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 voidviewer_editable_default_init (ViewerEditableInterface *iface){ /* add properties and signals to the interface here */}voidviewer_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);}voidviewer_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);}voidviewer_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);}
二、实现
一旦界面被定义,实现它是相当微不足道的。 第一步是定义一个正常的最终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 voidviewer_file_editable_save (ViewerFile *self, GError **error){ g_print ("File implementation of editable interface save method: %s.\n", self->filename);}static voidviewer_file_editable_undo (ViewerFile *self, guint n_steps){ g_print ("File implementation of editable interface undo method: %s.\n", self->filename);}static voidviewer_file_editable_redo (ViewerFile *self, guint n_steps){ g_print ("File implementation of editable interface redo method: %s.\n", self->filename);}static voidviewer_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 voidviewer_file_init (ViewerFile *self){ /* Instance variable initialisation code. */}