GObject 参考手册:概念:GLib 动态类型系统:不可实例的类型:接口

GType’s interfaces are very similar to Java’s interfaces. They allow to describe a common API that several classes will adhere to. Imagine the play, pause and stop buttons on hi-fi equipment – those can be seen as a playback interface. Once you know what they do, you can control your CD player, MP3 player or anything that uses these symbols. To declare an interface you have to register a non-instantiable classed type which derives from GTypeInterface. The following piece of code declares such an interface.
GType的接口(Interface)与Java的接口非常类似。它允许描述一个通用的API,使得多个类可以粘合在一起。想像一下,Hi-Fi音响设备中的暂停和播放按钮──这可以被视做一个回放接口。如果你知道你要做什么,你可以用来这个接口来控制你的CD机,MP3或其他使用相同符号的东西。要声明一个接口,你需要注册一个从GTypeInterface继承的不可实例的类型。下面的代码声明了这样的一个接口:

#define MAMAN_IBAZ_TYPE                (maman_ibaz_get_type ())
#define MAMAN_IBAZ(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz))
#define MAMAN_IS_IBAZ(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE))
#define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE, MamanIbazInterface))
 
typedef struct _MamanIbaz MamanIbaz; /* dummy object */
typedef struct _MamanIbazInterface MamanIbazInterface;
 
struct _MamanIbazInterface {
  GTypeInterface parent;
 
  void (*do_action) (MamanIbaz *self);
};
 
GType maman_ibaz_get_type (void);
 
void maman_ibaz_do_action (MamanIbaz *self);

The interface function, maman_ibaz_do_action is implemented in a pretty simple way:
这里用非常简单的方法来实现maman_ibaz_do_action这个接口函数:

void maman_ibaz_do_action (MamanIbaz *self)
{
  MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);
}

maman_ibaz_get_type registers a type named MamanIBaz which inherits from G_TYPE_INTERFACE. All interfaces must be children of G_TYPE_INTERFACE in the inheritance tree.
maman_ibaz_get_type 注册了一个从G_TYPE_INTERFACE继承的名为MamanIBaz的类型。在继承树中,所有的接口必须是G_TYPE_INTERFACE的子类。

An interface is defined by only one structure which must contain as first member a GTypeInterface structure. The interface structure is expected to contain the function pointers of the interface methods. It is good style to define helper functions for each of the interface methods which simply call the interface’ method directly: maman_ibaz_do_action is one of these.
一个接口只有一个包含GTypeInterface的结构来定义。接口的结构应该要包含一个函数指针指向这个接口的方法。用类似于maman_ibaz_do_action的方法在每个接口方法中定义帮助函数,可以使得我们直接调用接口方法,这是一个良好的风格。

Once an interface type is registered, you must register implementations for these interfaces. The function named maman_baz_get_type registers a new GType named MamanBaz which inherits from GObject and which implements the interface MamanIBaz.
一旦一个接口的类型被注册后,你必须来实现这个接口。其中,命名为maman_baz_get_type注册一个名为MamanBaz的由GObject继承来的新的GType,并在接口Interface中实现。

static void maman_baz_do_action (MamanIbaz *self)
{
  g_print ("Baz implementation of IBaz interface Action.\n");
}
 
static void
baz_interface_init (gpointer         g_iface,
                    gpointer         iface_data)
{
  MamanIbazInterface *iface = (MamanIbazInterface *)g_iface;
  iface->do_action = maman_baz_do_action;
}
 
GType 
maman_baz_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    static const GTypeInfo info = {
      sizeof (MamanBazInterface),
      NULL,   /* base_init */
      NULL,   /* base_finalize */
      NULL,   /* class_init */
      NULL,   /* class_finalize */
      NULL,   /* class_data */
      sizeof (MamanBaz),
      0,      /* n_preallocs */
      NULL    /* instance_init */
    };
    static const GInterfaceInfo ibaz_info = {
      (GInterfaceInitFunc) baz_interface_init,    /* interface_init */
      NULL,               /* interface_finalize */
      NULL          /* interface_data */
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "MamanBazType",
                                   &info, 0);
    g_type_add_interface_static (type,
                                 MAMAN_IBAZ_TYPE,
                                 &ibaz_info);
  }
  return type;
}

g_type_add_interface_static records in the type system that a given type implements also FooInterface (foo_interface_get_type returns the type of FooInterface). The GInterfaceInfo structure holds information about the implementation of the interface:
g_type_add_interface_static记录了在类型系统中如FooInterface来实现的接口(foo_interface_get_type返回FooInterface的类型),GInterfaceInfo保存着关于接口实现的信息:

struct _GInterfaceInfo
{
  GInterfaceInitFunc     interface_init;
  GInterfaceFinalizeFunc interface_finalize;
  gpointer               interface_data;
};

Interface Initialization
接口初始化

When an instantiable classed type which registered an interface implementation is created for the first time, its class structure is initialized following the process described in the section called “Instantiable classed types: objects”. Once the class structure is initialized,the function type_class_init_Wm (implemented in gtype.c) initializes the interface implementations associated with that type by calling type_iface_vtable_init_Wm for each interface.
当一个对象的第一次注册一个接口实现时, 它的类结构由下述的方法所初始化。等类结构初始化后,函数type_class_init_Wm(实现在gtype.c)会初始化由类关联的每个接口,以type_iface_vtable_init_Wm调用每个接口。

First a memory buffer is allocated to hold the interface structure. The parent’s interface structure is then copied over to the new interface structure (the parent interface is already initialized at that point). If there is no parent interface, the interface structure is initialized with zeros. The g_type and the g_instance_type fields are then initialized: g_type is set to the type of the most-derived interface and g_instance_type is set to the type of the most derived type which implements this interface.
首先为接口结构分配内存缓冲,父接口结构先被复制(父接口先被初始化)。如果没有父接口,接口结构将由0初始化。g_type和 g_instance_type将在其后被初始化:g_type被设置为最先起源的接口,g_instance_type被设置为最先起源的实现这个接口的类。

Finally, the interface’ most-derived base_init function and then the implementation’s interface_init function are invoked. It is important to understand that if there are multiple implementations of an interface the base_init and interface_init functions will be invoked once for each implementation initialized.
最终,接口的最顶层的 base_init 函数和实现接口的interface_init被调用。了解下面是重要的:如果有一个接口有多个base_init和interface_init的实现,那么每个实现都被调用一次以初始化。

It is thus common for base_init functions to hold a local static boolean variable which makes sure that the interface type is initialized only once even if there are multiple implementations of the interface:
base_init 函数保持了一个本地静态变量用来确保这个接口类型只被初始化一次而不管它是否被实现了几次:

static void
maman_ibaz_base_init (gpointer g_iface)
{
  static gboolean initialized = FALSE;
 
  if (!initialized) {
    /* create interface signals here. */
    initialized = TRUE;
  }
}

If you have found the stuff about interface hairy, you are right: it is hairy but there is not much I can do about it. What I can do is summarize what you need to know about interfaces:
如果你发现接口很烦,确实如此。它确实很烦,但是我也没办法啊。我只有把接口的过程归纳一下了!

Invocation time Function Invoked Function’s parameters Remark
First call to g_type_create_instance for type implementing interface interface’ base_init function On interface’ vtable Register interface’ signals here (use a local static boolean variable as described above to make sure not to register them twice.).
interface’ interface_init function On interface’ vtable Initialize interface’ implementation. That is, initialize the interface method pointers in the interface structure to the function’s implementation.

Interface Destruction
接口的销毁

When the last instance of an instantiable type which registered an interface implementation is destroyed, the interface’s implementations associated to the type are destroyed by type_iface_vtable_finalize_Wm (in gtype.c).
当最后一个实现某接口的实例被销毁以后,这个与类型相关联的接口实现也将由type_iface_vtable_finalize_Wm来销毁(gtype.c)

type_iface_vtable_finalize_Wm invokes first the implementation’s interface_finalize function and then the interface’s most-derived base_finalize function.
type_iface_vtable_finalize_Wm调用了第一个实现的interface_finalize函数,接着是接口最底层的base_finalize函数。

Again, it is important to understand, as in the section called “Interface Initialization”, that both interface_finalize and base_finalize are invoked exactly once for the destruction of each implementation of an interface. Thus, if you were to use one of these functions, you would need to use a static integer variable which would hold the number of instances of implementations of an interface such that the interface’s class is destroyed only once (when the integer variable reaches zero).
同样,下面的理解非常重要,如“接口的初始化”中描述的,interface_finalize和base_finalize都将被调用来确保一个接口的实现被正确的销毁。例如,如果你曾用过其中一个函数,你将需要使用一个静态的整形来保持有关实例实现的接口的数量,这样接口的类才会只被销毁一次(当整型变量为0时)。

The above process can be summarized as follows:
上面的处理过程总结如下:

Invocation time Function Invoked Function’s parameters
Last call to g_type_free_instance for type implementing interface interface’ interface_finalize function On interface’ vtable
interface’ base_finalize function On interface’ vtable

Now that you have read this section, you can forget about it. Please, forget it as soon as possible.
你已经读完了这章,现在你可以忘记它了。请尽可能快地忘记它!

Leave a Reply

Your email address will not be published. Required fields are marked *