GType类型系统(上)
发布者:
ouyang
glib version : 2.36.4
文章结构
本文首先介绍GType,及其相关知识。随后用一个例子演示了如何使用GType。
在下一篇中,将从源码角度分析GType如何实现封装,继承,多态。
什么是GType ?
GLib是一个跨平台的GTK的支撑库,它提供了多种高级的数据结构,如内存块、双向和单向链表、哈希表、动态字符串等。
Gobject是glib提供的一个轻便的对象系统,而gtype为它提供了一个动态的运行时面向对象的类型系统。
什么是GType 支持什么样的系统?
多层次、单根继承的类型系统。
它的对象由两部分组成:类结构和实例结构。
类结构唯一,它为该对象所有实例的共有部分;实例结构可以有多个,它是对象的具体实现。
或者说:实例里面保存了数据,而类主要保存了操作数据的方法。或者说类是一个类的所有对象公有的,而实例结构是一个实例特有的。
至于它为什么要这样设计,可以参考这里:GObject设计思想 。
怎样使用GType ?
GType支撑三种类型:
-
基本类型,通过g_type_register_fundamental 来注册,它需要的信息由GTypeInfo和GTypeFundamentalInfo传入。比如gobject里面的GObject就是一个基本类型。由于大部分的基本类型都已经预先注册好了,基本上不用关系该类型的使用。
-
静态类型,g_type_register_static来注册,其类型信息由GTypeInfo传入。GTK里面的各种窗口和容器类型都是通过这种方式注册的。
-
动态类型,g_type_register_dynamic注册,其类型信息由GTypePlugin传入。之所谓分为动态和静态,是因为动态的类型可以在运行时加载和卸载。
cloverprince的一系列博客从简到繁介绍怎么样使用GType注册我们的类。看完这些例子,相信也会加深对GType为什么要这样设计的理解。
从例子出发
在接下来的例子中,我们将注册一个基本类型和一个静态类型。
首先注册一个基本类型,我们把它叫做大猩猩。我们定义它的类结构和实例结构:
typedef struct {
GTypeInstance g_type_instance;
/*< private >*/
int m_privateInt;
} OrangutanObject;
typedef struct {
GTypeClass g_type_class;
void (*create) ();
} OranObjectClass;
void oran_object_create() {
printf("Give birth to a new Orangutan\n");
}
在实例结构中,第一个数据是固定的父类的Instace结构。接下来是一些私有数据。
在类结构中,我们定义了Orangutan的构造函数形式。类结构的第一个数据必须是父类的Class结构,它是该类型的一个标识。
另外,我们定义了一个构造函数。
接下来, 注册基本类型需要GTypeInfo和GTypeFundamentalInfo:
static const GTypeFundamentalInfo orang_info = {
(GTypeFundamentalFlags)(G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE |
G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE),
};
static void OranClassInitFunc(OranObjectClass* klass, gpointer data) {
klass->create = oran_object_create;
}
static void OranInstanceInitFunc(OranObject* instance, gpointer data) {
instance->m_privateInt = 42;
}
static const GTypeInfo oran_type_info = {
sizeof(mybaseclass_t);//class_size;
NULL, //base_init;
NULL, //base_finalize;
(GClassInitFunc)OranClassInitFunc, //class_init;
NULL, //class_finalize;
NULL, //class_data;
sizeof(mybaseinstance_t),//instance_size;
0, //n_preallocs;
(GInstanceInitFunc)OranInstanceInitFunc, //instance_init;
NULL, //value_table;
};
GTypeInfo 各参数的含义注释已经很清楚了。而GTypeFundamentalInfo 可以看出其成员是一个enum,这个enum标识了要注册的类型能否实例化,能否被继承等信息。准备工作就绪后,是时候为“猩猩”安家落户了:
static GType GetOranType() = {
static GType type = 0;
if (type == 0) {
type = g_type_register_fundamental (
g_type_fundamental_next(),//A predefined type identifier.
“OrangutanClass”,//0-terminated string used as the name of the new type.
&oran_type_info, //GTypeInfo structure for this type.
&orang_info, //GTypeFundamentalInfo structure for this type.
GTypeFlags(0) //Bitwise combination of #GTypeFlags values
);
return type;
}
GTypeFlags 是什么呢?它也是一个enum:
typedef enum {
G_TYPE_FLAG_ABSTRACT = (1 << 4), // Indicates an abstract type. No instances can be created for an abstract type.
G_TYPE_FLAG_VALUE_ABSTRACT = (1 << 5) //Indicates an abstract value type
} GTypeFlags;
接下来,我们要为“orangutan”添加一个进化后的子类“human”。同样实现类结构和实例结构:
struct _HumanObject {
OrangutanObject parent; /* <private> */ int m_privateInt;
};
typedef _HumanObject HumanObject;
struct _HumanObjectClass {
OranObjectClass parent_klass;};
typedef _HumanObjectClass HumanObjectClass;
我们需要将create方法替换一下,不能继续”Give birth to a new Orangutan”了;同时初始化GTypeInfo,并调用g_type_register_static注册我们的HumanClass,因为我们并不准备注册一个基本类型。
void human_object_create() {
printf("Give birth to a new man!\n");
}
static void HumanClassInitFunc(HumanObjectClass* klass, gpointer data) {
OranObjectClass *klass_oran = G_TYPE_CHECK_CLASS_CAST(klass, GetOranType(), OranObjectClass);
klass_oran->create = human_object_create;
}
static void HumanInstanceInitFunc(HumanObject* instance, gpointer data) {
instance->m_privateInt = 42;
}
static const GTypeInfo human_type_info = {
sizeof(HumanObjectClass), //fill it with humanobject class;
NULL, //base_init;
NULL, //base_finalize;
(GClassInitFunc)HumanClassInitFunc, //use human class init func;
NULL, //class_finalize;
NULL, //class_data;
sizeof(HumanObject),//human size;
0, //n_preallocs;
(GInstanceInitFunc)HumanInstanceInitFunc, //human instance init func;
NULL, //value_table;
};
GType GetHumanType() {
static GType type = 0;
if (type == 0) {
type = g_type_register_static(
GetOranType(),
"HumanClass",
&human_type_info,
GTypeFlags(0)
);
}
return type;
}
现在,可以测试我们的”Orangutan”以及”Human”,希望Human不要”give birth to a new orangutan” :)
int main() {
g_type_init();
printf("Orangutan Class ID: %d, name: %s\n", GetOranType(), g_type_name(GetOranType()));
OrangutanObject* orangutan = (OrangutanObject*)g_type_create_instance(GetOranType());
OranObjectClass* klass = G_TYPE_INSTANCE_GET_CLASS(orangutan, GetOranType(), OranObjectClass);
klass->create();
printf("Human Class ID: %d, name: %s\n", GetHumanType(), g_type_name(GetHumanType()));
HumanObject* human = (HumanObject*)g_type_create_instance(GetHumanType());
OranObjectClass* h_klass = G_TYPE_INSTANCE_GET_CLASS(human, GetHumanType(), OranObjectClass);
h_klass->create();
printf("Orangutan instance private int : %d.\n", orangutan->m_privateInt);
printf("Human instance private int : %d.\n", human->m_privateInt);
return 0;
}
上面的代码都很简单,需要注意一下的是g_type_init()这个函数。使用g_type之前,需要调用它。它会做一些必要的初始化工作(注册一些基本类型等)。
看看输出:
Orangutan Class ID: 196, name: OrangutanClass
Give birth to a new Orangutan
Human Class ID: 5277952, name: HumanClass
Give birth to a new man!
Orangutan instance private int : 0.
Human instance private int : 42.
一切正如我们的预期。
需要说明的是,这仅仅是一个简单的例子。更复杂的例子可以参考上面两节提到的GObject设计思想和cloverprince的一系列博客。或者gobject的源码(后续将会介绍)。
疑问
这个简单的例子介绍了 gtype的简单用法,也带来更多的疑问:
-
GType 是什么?是什么类型?
-
GTypeInstance, GTypeClass是什么?
-
GTypeInfo的value_table是什么?它的用途是什么?
-
虚函数是怎么实现的?
-
怎么处理多层继承的情况?怎么实现虚继承?怎么写接口类?
。。。
这些问题,都将在下一篇 GType类型系统(下)
中解答
睿初科技软件开发技术博客,转载请注明出处
blog comments powered by Disqus
发布日期
标签
最近发表
- volatile与多线程
- TDD practice in UI: Develop and test GUI independently by mockito
- jemalloc源码解析-核心架构
- jemalloc源码解析-内存管理
- boost::bind源码分析
- 小试QtTest
- 一个gtk下的目录权限问题
- Django学习 - Model
- Code snippets from C & C++ Code Capsule
- Using Eclipse Spy in GUI products based on RCP
文章分类
- cpp 3
- wxwidgets 4
- swt/jface 1
- chrome 3
- memory_management 5
- eclipse 1
- 工具 4
- 项目管理 1
- cpplint 1
- 算法 1
- 编程语言 1
- python 5
- compile 1
- c++ 7
- 工具 c++ 1
- 源码分析 c++ 3
- c++ boost 2
- data structure 1
- wxwidgets c++ 1
- template 1
- boost 1
- wxsocket 1
- wxwidget 2
- java 2
- 源码分析 1
- 网路工具 1
- eclipse插件 1
- django 1
- gtk 1
- 测试 1
- 测试 tdd 1
- multithreading 1