本文引用自http://imtx.cn,原文作者:TualatriX
原文:http://library.gnome.org/devel/gobject/2.14/chapter-gtype.html
由Glib类型系统操作的一个类型,比传统上所讲的Object类型更具一般化。下面查看类型系统中有关类结构和注册新类型的函数,是会对此最好的解释。
typedef struct _GTypeInfo GTypeInfo; struct _GTypeInfo { /* interface types, classed types, instantiated types */ guint16 class_size; GBaseInitFunc base_init; GBaseFinalizeFunc base_finalize; /* classed types, instantiated types */ GClassInitFunc class_init; GClassFinalizeFunc class_finalize; gconstpointer class_data; /* instantiated types */ guint16 instance_size; guint16 n_preallocs; GInstanceInitFunc instance_init; /* value handling */ const GTypeValueTable *value_table; }; GType g_type_register_static (GType parent_type, const gchar *type_name, const GTypeInfo *info, GTypeFlags flags); GType g_type_register_fundamental (GType type_id, const gchar *type_name, const GTypeInfo *info, const GTypeFundamentalInfo *finfo, GTypeFlags flags);
g_type_register_static和g_type_register_fundamental这两个C函数定义在gtype.h中,并在gtype.c中具体实现。你可以用来在程序的类型系统中注册一个新的GType。一般情况下你永远也不需要使用g_type_register_fundamental(除非你是Tim Janik才会这样做),但是这次你要做,在最后一章会向你解释如何创建一个基本类型。
基本类型是不需要从任何其他类型取得的最顶级的类型, 相对的,其他非基本类型是继承于其他类型的。在由g_type_init初始化时,类型系统不仅仅初始化它的内部数据结构,同时也注册一些核心类型:其中一些是基本类型,其他则是从基本类型继承的。
不论是基本还是非基本类型,均由下面的定义步骤:
- 类的大小:GTypeInfo的class_size。
- 类的初始化函数(C++ 构造函数):GTypeInfo的base_init和class_init。
- 类的销毁函数(C++析构函数):GTypeInfo的base_finalize和class_finalize。
- 实例的大小(C++参数new):GTypeInfo中的instance_size。
- 实例化策略(C++ 类的new operator):GTypeInfo的n_preallocs。
- 复制函数(C++的复制操作):GTypeInfo的value_table。
- 类的字符标志:GTypeFlags。
基本类型同样可以由GTypeFundamentalFlags来定义,并保存在GTypeFundamentallInfo中。非基本类型一般传递一个parent_type至g_type_register_static和g_type_register_dynamic中,然后交给父类来定义。
复制函数
所有的glib类型(基本和非基本,类化和非类化,可实例化和不可实例化)的最大共同点是都可以通过单一的API来复制或指定它们。
GValue结构被用作所有类型的抽象的容器,它的极度简化的API(定义在gobject/gvalue.h)可以被使用请求value_table函数被注册当类型注册中:举个例子,g_value_copy复制了GValue的内容至另一个GValue。这与C++指派它的复制操作来修改默认的按位复制C++/C结构是类似的。
下面的代码向你展示了你是如何复制一个64位的整型,同样GObject的实例指针也是这样(代码在/gtype/test.c中):
static void test_int (void) { GValue a_value = {0, }; GValue b_value = {0, }; guint64 a, b; a = 0xdeadbeaf; g_value_init (&a_value, G_TYPE_UINT64); g_value_set_uint64 (&a_value, a); g_value_init (&b_value, G_TYPE_UINT64); g_value_copy (&a_value, &b_value); b = g_value_get_uint64 (&b_value); if (a == b) { g_print ("Yay !! 10 lines of code to copy around a uint64./n"); } else { g_print ("Are you sure this is not a Z80 ?/n"); } } static void test_object (void) { GObject *obj; GValue obj_vala = {0, }; GValue obj_valb = {0, }; obj = g_object_new (MAMAN_BAR_TYPE, NULL); g_value_init (&obj_vala, MAMAN_BAR_TYPE); g_value_set_object (&obj_vala, obj); g_value_init (&obj_valb, G_TYPE_OBJECT); /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference. This function thus calls g_object_ref. It is interesting to note that the assignment works here because MAMAN_BAR_TYPE is a G_TYPE_OBJECT. */ g_value_copy (&obj_vala, &obj_valb); g_object_unref (G_OBJECT (obj)); g_object_unref (G_OBJECT (obj)); }
上面代码的重点是关于复制指令的确切语义,并没有详细的定义复制是如何实现的。复制函数的实现可能是决定请求一新块的内存,并把数据从源复制到目的。或者可能是简单的增加实例的引用数和复制引用至新的GValue。
value_table用于详细说明这些定义在gtype.h的函数的使用并彻底地描述在由GObject提供的API文档中,这是为什么我们不追究细节的原因。
typedef struct _GTypeValueTable GTypeValueTable; struct _GTypeValueTable { void (*value_init) (GValue *value); void (*value_free) (GValue *value); void (*value_copy) (const GValue *src_value, GValue *dest_value); /* varargs functionality (optional) */ gpointer (*value_peek_pointer) (const GValue *value); gchar *collect_format; gchar* (*collect_value) (GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags); gchar *lcopy_format; gchar* (*lcopy_value) (const GValue *value, guint n_collect_values, GTypeCValue *collect_values, guint collect_flags); };
有趣的是,你同样不需要详细指定一个value_table在注册过程中,因为value_tables一般从非基本类型的父类中继承,这意味着除非你想写一个基本类型,否则你将不需要提供一个新的value_table因为它可以从父类继承value_table。
请注意,另外一个注册函数是g_type_register_dynamic。我们将不讨论这个函数,因为它与_static版本非常相似。