首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

GObject对象系统(2)

GObject对象系统(2)

对象的实现下面的代码实现了上面的Boy对象的定义:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/* boy.c */
#include "boy.h"
enum { BOY_BORN, LAST_SIGNAL };
static gint boy_signals[LAST_SIGNAL] = { 0 };
static void boy_cry (void);
static void boy_born(void);
static void boy_init(Boy *boy);
static void boy_class_init(BoyClass *boyclass);
GType boy_get_type(void)
{
    static GType boy_type = 0;
    if(!boy_type)
    {
        static const GTypeInfo boy_info = {
            sizeof(BoyClass),
            NULL,NULL,
            (GClassInitFunc)boy_class_init,
            NULL,NULL,
            sizeof(Boy),
            0,
            (GInstanceInitFunc)boy_init
        };
        boy_type = g_type_register_static(G_TYPE_OBJECT,"Boy",&boy_info,0);
    }
    return boy_type;
}
static void boy_init(Boy *boy)
{
    boy->age = 0;
    boy->name = "none";
    boy->cry = boy_cry;
}
static void boy_class_init(BoyClass *boyclass)
{
    boyclass->boy_born = boy_born;
    boy_signals[BOY_BORN] = g_signal_new("boy_born",
                BOY_TYPE,
                G_SIGNAL_RUN_FIRST,
                G_STRUCT_OFFSET(BoyClass,boy_born),
                NULL,NULL,
                g_cclosure_marshal_VOID__VOID,
                G_TYPE_NONE, 0, NULL);
}
Boy *boy_new(void)
{
    Boy *boy;
    boy = g_object_new(BOY_TYPE, NULL);
    g_signal_emit(boy,boy_signals[BOY_BORN],0);
    return boy;
}
int boy_get_age(Boy *boy)
{
    return boy->age;
}
void boy_set_age(Boy *boy, int age)
{
    boy->age = age;
}
char *boy_get_name(Boy *boy)
{
    return boy->name;
}
void boy_set_name(Boy *boy, char *name)
{
    boy->name = name;
}
Boy*  boy_new_with_name(gchar *name)
{
    Boy* boy;
    boy = boy_new();
    boy_set_name(boy, name);
    return boy;
}
Boy*  boy_new_with_age(gint age)
{
    Boy* boy;
    boy = boy_new();
    boy_set_age(boy, age);
    return boy;
}
Boy *boy_new_with_name_and_age(gchar *name, gint age)
{
    Boy *boy;
    boy = boy_new();
    boy_set_name(boy,name);
    boy_set_age(boy,age);
    return boy;
}
static void boy_cry (void)
{
    g_print("The Boy is crying ......\n");
}
static void boy_born(void)
{
    g_print("Message : A boy was born .\n");
}
void  boy_info(Boy *boy)
{
    g_print("The Boy name is %s\n", boy->name);
    g_print("The Boy age is %d\n", boy->age);
}




在这段代码中,出现了实现Boy对象的关键函数,这是在Boy对象的定义中未出现的,也是没必要出现的。就是两个初始化函数,boy_init和boy_class_init,它们分别用来初始化实例结构和类结构。它们并不被在代码中明显调用,关键是将其用宏转换为地址指针,然后赋值到GTypeInfo结构中,然后由GType系统自行处理,同时将它们定义为静态的也是非常必要的。
GTypeInfo结构中定义了对象的类型信息,包括以下内容:
  • 包括类结构的长度(必需,即我们定义的BoyClass结构的长度);
  • 基础初始化函数(base initialization function,可选);
  • 基础结束化函数(base finalization function,可选);         
    (以上两个函数可以对对象使用的内存来做分配和释放操作,使用时要用GBaseInitFunc和GBaseFinalizeFunc来转换为指针,本例中均未用到,故设为NULL。)
  • 类初始化函数(即我们这里的boy_class_init函数,用GclassInit宏来转换,可选,仅用于类和实例类型);
  • 类结束函数(可选);
  • 实例初始化函数(可选,即我们这里的boy_init函数);
  • 最后一个成员是GType变量表(可选)。
定义好GTypeInfo结构后就可以用g_type_register_static函数来注册对象的类型了。
g_type_register_static函数用来注册对象的类型,它的第一个参数是表示此对象的父类的对象类型,我们这里是G_TYPE_OBJECT,这个宏用来表示GObject的父类;第二个参数表示此对象的名称,这里为"Boy";第三个参数是此对象的GTypeInfo结构型指针,这里赋值为&boyinfo;第四个参数是对象注册成功后返回此对象的整型ID标识。
g_object_new函数,用来创建一个基于G_OBJECT的对象,它可以有多个参数,第一个参数是上面说到的已注册的对象标识ID;第二个参数表示后面参数的数量,如果为0,则没有第三个参数;第三个参数开始类型都是GParameter类型,它也是一个结构型,定义为:
1
2
3
4
struct GParameter{
        const gchar* name;
        GValue value;
    };




关于GValue,它是变量类型的统一定义,它是基础的变量容器结构,用于封装变量的值和变量的类型,可以GOBJECT文档的GVALUE部分。

信号的定义和应用在GObject系统中,信号是一种定制对象行为的手段,同时也是一种多种用途的通知机制。初学者可能是在GTK+中首先接触到信号这一概念的,事实上在普通的字符界面编程中也可以正常应用,这可能是很多初学者未曾想到的。
一个对象可以没有信号,也可以有多个信号。当有一或多个信号时,信号的名称定义是必不可少的,此时C语言的枚举类型的功能就凸显出来了,用LAST_SIGNAL来表示最后一个信号(不用实现的信号)是一种非常良好的编程风格。这里为Boy对象定义了一个信号BOY_BORN,在对象创建时发出,表示Boy对象诞生。
同时还需要定义静态的整型指针数组来保存信号的标识,以便于下一步处理信号时使用。
对象的类结构是所有对象的实例所共有的,我们将信号也定义在对象的类结构中,如此信号同样也是所有对象的实例所共有的,任意一个对象的实例都可以处理信号。因此我们有必要在在类初始化函数中创建信号(这也可能是GObject设计者的初衷)。函数g_signal_new用来创建一个新的信号,它的详细使用方法可以在GObject的API文档中找到。信号创建成功后,返回一个信号的标识ID,如此就可以用发射信号函数g_signal_emit向指定义对象的实例发射信号,从而执行相应的功能。
本例中每创建一个新的Boy对象,就会发射一次BOY_BORN信号,也就会执行一次我们定义的boy_born函数,也就输出一行"Message : A boy was born ."信息。
返回列表