GTYPE类型系统分析 zz

os posted @ 2013年8月10日 18:48 in GObject , 1214 阅读

转载时请注明出处和作者联系方式

作者联系方式:会飞的鱼 <parker30_liu at hotmail dot com>

刚开始接触GLib库时,对GLib传统的习惯和特有的概念不熟悉,在编写基于GLib的程序时总是很不顺手,心中很是不爽。后来随着写的代码多了,渐渐熟悉了GLib的这些术语、概念、编码风格,情况好多了。但对GLib的类型系统还是不大清楚,只不过是照葫芦画瓢学的不错而已,对基于GType的使用在较深入时还是一知半解。最近有了些空余时间,于是去仔细看了GType相关的代码,总算弄得比较清楚了。记录在此,以便查阅,有不对之处,请高手指正。

Gtype提供了GLib的数据类型系统和数据类型定义,是GObject对象系统的基础。GLib定义了一些基本数据类型,并允许用户定义一些基本类型的派生类型,还可以定义动态类型,如GObject的对象系统的各种类型的对象都是GObject的派生类型。GType只支持单继承,但允许通过接口继承的方式实现变形的多继承,避免了类似C++的多继承的复杂性和多继承导致的各种问题,规范了程序员对多继承的使用。GType提供了一个基于C语言的具有完备的多层抽象结构的继承体系的良好实现,使得我们可以使用C语言来进行面向对象的程序设计和实现。

首先,从GType这个数据类型的定义开始,一步一步地进入这个复杂的GType类型系统,让我们来解开这个迷宫吧。下面的分析是基于GLib的2.12.6版本的源代码来进行的,可能和较早的版本有些出入,请大家注意。

在最新的GLib中,GType是一个ulong类型,即无符号长整型数。GType的意义是用来指向整个GLib类型系统的一个类型节点。对于基本类型,GType是该类型在基本类型中的序号乘以4(乘以4是用来和非基本类型兼容,内存地址低二位为0)。对于非基本类型,GType是该类型的类型节点的类型信息的内存地址。

基本类型最多有256个,现在GLib只使用了49个,包括GLib已经定义的基本类型、GLib保留的基本类型、BSE保留的基本类型,其余的基本类型给用户使用。下面是GLib中已经定义的基本类型。

 

 

#define G_TYPE_INVALID G_TYPE_MAKE_FUNDAMENTAL (0)

#define G_TYPE_NONE G_TYPE_MAKE_FUNDAMENTAL (1)

#define G_TYPE_INTERFACE G_TYPE_MAKE_FUNDAMENTAL (2)

#define G_TYPE_CHAR G_TYPE_MAKE_FUNDAMENTAL (3)

#define G_TYPE_UCHAR G_TYPE_MAKE_FUNDAMENTAL (4)

#define G_TYPE_BOOLEAN G_TYPE_MAKE_FUNDAMENTAL (5)

#define G_TYPE_INT G_TYPE_MAKE_FUNDAMENTAL (6)

#define G_TYPE_UINT G_TYPE_MAKE_FUNDAMENTAL (7)

#define G_TYPE_LONG G_TYPE_MAKE_FUNDAMENTAL (8)

#define G_TYPE_ULONG G_TYPE_MAKE_FUNDAMENTAL (9)

#define G_TYPE_INT64 G_TYPE_MAKE_FUNDAMENTAL (10)

#define G_TYPE_UINT64 G_TYPE_MAKE_FUNDAMENTAL (11)

#define G_TYPE_ENUM G_TYPE_MAKE_FUNDAMENTAL (12)

#define G_TYPE_FLAGS G_TYPE_MAKE_FUNDAMENTAL (13)

#define G_TYPE_FLOAT G_TYPE_MAKE_FUNDAMENTAL (14)

#define G_TYPE_DOUBLE G_TYPE_MAKE_FUNDAMENTAL (15)

#define G_TYPE_STRING G_TYPE_MAKE_FUNDAMENTAL (16)

#define G_TYPE_POINTER G_TYPE_MAKE_FUNDAMENTAL (17)

#define G_TYPE_BOXED G_TYPE_MAKE_FUNDAMENTAL (18)

#define G_TYPE_PARAM G_TYPE_MAKE_FUNDAMENTAL (19)

#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20)

 

宏G_TYPE_MAKE_FUNDAMENTAL是将类型序号乘以4以得到基本类型的值。除了基本数据使用的类型如G_TYPE_CHAR等外,还有如下几个基本类型。

  • G_TYPE_INVALID

无效的GType类型,此种类型不是GType类型。

  • G_TYPE_NONE

空的GType类型,和C语言的void相当。

  • G_TYPE_BOXED

多个GType类型的数据组合在一起的得到的GType类型,可以是单一GType类型数据组成的数组,也可以是不同GType类型数据组成的异质数组。如字符串数组(G_TYPE_STRV)、GValue数组(G_TYPE_VALUE_ARRAY)、日期数据类型(G_TYPE_DATE)。此类型只能单层继承。

  • G_TYPE_PARAM

参数数据类型,用于进行函数、信号等的参数传递的GType类型。

  • G_TYPE_OBJECT

GObject对象的GType类型,是GLib对象系统的根对象类型,是一个可以实例化的类类型,可以多层继承,但只能单根继承。G_TYPE_OBJECT类型的派生类型的实例化对象在不混淆的情况下也可以称为GObject对象。

  • G_TYPE_INTERFACE

接口类型,定义了对数据或对象进行操作的接口方法,凡实现了某一个接口的所有方法的GObject对象可以称其继承了该接口。

Gtype的基本类型是可以继承的,其继承关系由类型节点确定,类型节点保存了GType类型的类型信息。所有基本类型的类型节点的指针保存在一个基本类型节点数组中,基本类型的值除以4就是该基本类型节点在基本类型节点数组中的序号。

类型节点的数据结构如下所示。

 

struct _TypeNode

{

GTypePlugin *plugin;

guint n_children : 12;

guint n_supers : 8;

guint _prot_n_ifaces_prerequisites : 9;

guint is_classed : 1;

guint is_instantiatable : 1;

guint mutatable_check_cache : 1; /* combines some common path checks */

GType *children;

TypeData * volatile data;

GQuark qname;

GData *global_gdata;

union {

IFaceEntry *iface_entries; /* for !iface types */

GType *prerequisistes;

} _prot;

GType supers[1]; /* flexible array */

};

类型节点数据结构中的supers和children确定了各个GType类型的继承关系。n_supers是所继承的所有祖先类型的个数,数组supers保存了该类型继承的所有祖先类型,n_children是所有子类型的个数,数组children保存了该类型的所有子类型。所有GType类型组成了下图所示的关系。


 

图中箭头由派生类指向基类,虚线框的节点类型是和我们的分析无关的继承关系。该图描述了无继承,单层继承,多层继承这几种继承关系。

基本类型的类型节点除了普通类型的信息外,还有基本类型的类型信息。基本类型的信息决定了该基本类型及其派生类型的如下几个特性。

  • G_TYPE_FLAG_CLASSED

该基本类型是一个类类型。

  • G_TYPE_FLAG_INSTANTIABLE

该基本类型是可以实例化的类型,即是否可以创建该类型的对象。

  • G_TYPE_DERIVABLE

该基本类型是可以单层继承的类型,只允许一层的平坦的继承。

  • G_TYPE_DEEP_DERIVABLE

该基本类型是可以多层继承的类型,可以有子类型、孙子类型,子子孙孙无穷尽也。

普通类型的信息有如下几个类型特性。

  • G_TYPE_FLAG_ABSTRACT

该类型是一个抽象类型。

  • G_TYPE_FLAG_VALUE_ABSTRACT

该类型是一个值抽象类型,是GValue用的,表明该类型的实例是一个GValue值

 

每个类型节点的祖先类型数组supers是按如下方式排列,祖先类型数组的大小是1(self) + n_supers + 1(0),n_supers最大值是255,即最大继承层次是255层。

 

自身类型

父类型

祖父类型

...

基本类型

0

 

每个类型节点的子类型按创建的次序增加到子类型数组children中,n_children最大值是4095,即最多有4095个子类型。

类型节点数据结构的qname保存了该GType类型的名字,这是一个夸克(夸克是GLib的特有术语,相当于字符串的ID)。plugin是用于动态类型的类型数据入口。

is_classed指明该类型是否是一个类,is_instantiatable指明该类型是否可以实例化。这两个成员的值从基本类型继承而来。

global_gdata是GType的一个特色,用于保存GType类型相关的附属信息,其本身是一个由QData组成的动态数组GData。每个QData是个夸克指针对,夸克保存该信息的名字,指针指向该信息的内容。可以通过函数g_type_set_qdata()设置该类型相关的附属信息,通过函数g_type_get_qdata()获取该类型相关的附属信息。这是一个十分方便和好用的功能。

 

_prot是一个联合,当该类型是一个接口时,是一个由GType类型组成的动态数组,实现这个接口的GType必须要实现该GType类型数组中的所有GType类型,该数组中一般都是接口类型,最多只有一个可实例化的类型。若不是接口,是一般的类,则是一个由接口入口IFaceEntry组成的动态数组,这个数组保存了这个类继承的所有接口。_prot_n_ifaces_prerequisites是动态数组元素的个数。

data是该GType类型的类型数据,保存了和该类型相关的接口、类或实例对象的数据。类型数据的数据结构如下所示。

 

union _TypeData

{

CommonData common;

IFaceData iface;

ClassData class;

InstanceData instance;

};

 

 

 

这是一个联合,当类型是一个接口时,为接口数据IFaceData。当类型是一个类时,为类数据ClassData。当类型是一个对象实例时,为对象数据InstanceData。当类型是其他一般的类型时,为类型公共数据CommonData。接口数据IFaceData、类数据ClassData、对象数据InstanceData都包含有公共数据CommonData。

 

 

CommonData的数据结构如下所示。

 

struct _CommonData

{

guint ref_count;

GTypeValueTable *value_table;

};

ref_count是引用计数,是大部分面向对象系统用来保证对象能够在复杂的环境下正确的创建、引用、销毁的一种技术。

value_table是该gtype类型的值处理函数表,如值的初始化函数、值的释放函数、值拷贝函数等,这是同类型的gtype实例之间实现值拷贝的基础。下面是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);

};

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter