ZhangZe

Computer World--Linux, BSD

博客园 首页 新随笔 联系 管理


      简单的说,GObject对象系统是一个建立在GLIB基础上的,用C语言完成的,具有跨平台特色的、灵活的、可扩展的、

 

非常容易映射到其它语言的面向对象的框架。如果你是一个C语言的执着的追随者,你没有理由不研究一下它。
前言

大多数现代的计算机语言都带有自己的类型和对象系统,并附带算法结构。正象GLib提供的基本类型和算法结构(如链表、哈希表等)一样,GObject的对象系统提供了一种灵活的、可扩展的、并容易映射(到其它语言)的面向对象的C语言框架。它的实质可以概括为:

    * 一个通用类型系统,用来注册任意的、轻便的、单根继承的、并能推导出任意深度的结构类型的界面,它照顾组合对象的定制、初始化和内存管理,类结构,保持对象的父子关系,处理这些类型的动态实现。也就是说,这些类型的实现是在运行时重置和卸载的;
    * 一个基本类型的实现集,如整型,枚举型和结构型等;
    * 一个基本对象体系之上的基本对象类型的实现的例子--GObject基本类型;
    * 一个信号系统,允许用户非常灵活的自定义虚的或重载对象的方法,并且能充当非常有效力的通知机制;
    * 一个可扩展的参数/变量体系,支持所有的能被用作处理对象属性或其它参数化类型的基本的类型。

类型(GType)与对象(GObject)

GLib中最有特色的是它的对象系统--GObject System,它是以Gtype为基础而实现的一套单根继承的C语言的面向对象的框架。

GType 是GLib 运行时类型认证和管理系统。GType API 是GObject的基础系统,所以理解GType是理解GObject的关键。Gtype提供了注册和管理所有基本数据类型、用户定义对象和界面类型的技术实现。(注意:在运用任一GType和GObject函数之前必需运行g_type_init()函数来初始化类型系统。)

为实现类型定制和注册这一目的,所有类型必需是静态的或动态的这二者之一。静态的类型永远不能在运行时加载或卸载,而动态的类型则可以。静态类型由 g_type_register_static()创建,通过GTypeInfo结构来取得类型的特殊信息。动态类型则由 g_type_register_dynamic()创建,用GTypePlugin结构来取代GTypeInfo,并且还包括 g_type_plugin_*()系列API。这些注册函数通常只运行一次,目的是取得它们返回的专有类的类型标识。

还可以用g_type_register_fundamental来注册基础类型,它同时需要GTypeInfo和GTypeFundamentalInfo两个结构,事实上大多数情况下这是不必要的,因为系统预先定义的基础类型是优于用户自定义的。

(本文重点介绍创建和使用静态的类型。)
对象的定义

在GObject系统中,对象由三个部分组成:

   1. 对象的ID标识(唯一,无符号长整型,所有此类对象共同的标识);
   2. 对象的类结构(唯一,结构型,由对象的所有实例共同拥有);
   3. 对象的实例(多个,结构型,对象的具体实现)。

基于GObject的对象到底是什么样的呢?下面是基于GObject的简单对象 -- Boy的定义代码:

/* boy.h */

#ifndef __BOY_H__
#define __BOY_H__

#include <glib-object.h>

#define BOY_TYPE (boy_get_type())

#define BOY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),BOY_TYPE,Boy))

typedef struct _Boy Boy;
typedef struct _BoyClass BoyClass;

struct _Boy {
GObject parent;

gint age;
gchar *name;
void (*cry)(void);
};

struct _BoyClass {
GObjectClass parent_class;

void (*boy_born)(void);
};

GType    boy_get_type(void);

Boy*  boy_new(void);

int    boy_get_age(Boy *boy);

void    boy_set_age(Boy *boy, int age);

char* boy_get_name(Boy *boy);

void    boy_set_name(Boy *boy, char *name);

Boy*  boy_new_with_name(gchar *name);

Boy*  boy_new_with_age(gint age);

Boy*  boy_new_with_name_and_age(gchar *name, gint age);

void  boy_info(Boy *boy);

#endif /* __BOY_H__*/

这是一段典型的C语言头文件定义,包括编译预处理,宏定义,数据结构定义和函数声明;首先要看的是两个数据结构对象Boy和BoyClass,

结构类型_Boy是Boy对象的实例,就是说我们每创建一个Boy对象,也就同时创建了一个Boy结构。Boy对象中的parent表示此对象的父类,

GObject系统中所有对象的共同的根都是GObject类,所以这是必须的;其它的成员可以是公共的,这里包括表示年龄的age,

表示名字的name和表示方法的函数指针cry,外部代码可以操作或引用它们。

结构类型_BoyClass是Boy对象的类结构,它是所有Boy对象实例所共有的。BoyClass中的parent_class是GObjectClass,

同GObject是所有对象的共有的根一样,GObejctClass是所有对象的类结构的根。在BoyClass中我们还定义了一个函数指针boy_born,

也就是说这一函数指针也是所有Boy对象实例共有的,所有的Boy实例都可以调用它;同样,如果需要的话,你也可以在类结构中定义其它数据成员。

其余的函数定义包括三种,

一种是取得Boy对象的类型ID的函数boy_get_type,这是必须有的;

另一种是创建Boy对象实例的函数boy_new和boy_new_with_*,这是非常清晰明了的创建对象的方式,

当然你也可以用g_object_new函数来创建对象;

第三种是设定或取得Boy对象属性成员的值的函数boy_get_*和boy_set_*。

正常情况下这三种函数都是一个对象所必需的,另外一个函数boy_info用来显示此对象的当前状态。

宏在GObject系统中用得相当广泛,也相当重要,这里我们定义了两个非常关键的宏,BOY_TYPE宏封装了boy_get_type函数,

可以直接取得并替代Boy对象的ID标识;

BOY(obj)宏是G_TYPE_CHECK_INSTANCE_CAST宏的再一次封装,目的是将一个Gobject对象强制转换为Boy对象,

这在对象的继承中十分关键,也经常用到。

posted on 2010-05-21 18:00  ze_zhang  阅读(635)  评论(0编辑  收藏  举报