glib之gobject G_DEFINE_TYPE用法

1.my_demo.h

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
#ifndef _MY_DEMO_H_
#define _MY_DEMO_H_
#include <glib-object.h>

#ifdef __cplusplus
extern "C" {
#endif

//宏
#define MY_TYPE_DEMO (my_demo_get_type())
#define MY_DEMO(object) G_TYPE_CHECK_INSTANCE_CAST((object), MY_TYPE_DEMO, MyDemo)
#define MY_DEMO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), MY_TYPE_DEMO, MyDemoClass))
#define MY_IS_DEMO(object) G_TYPE_CHECK_INSTANCE_TYPE((object), MY_TYPE_DEMO))
#define MY_IS_DEMO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), MY_TYPE_DEMO))
#define MY_DEMO_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), MY_TYPE_DEMO, MyDemoClass))

typedef struct MyDemoPrivate MyDemoPrivate;

struct MyDemoPrivate
{
    gchar *name;
    gint64 age;
};

//实例结构体
typedef struct _MyDemo MyDemo;

struct _MyDemo {
    GObject parent;
    MyDemoPrivate *priv;
};

//类结构体
typedef struct _MyDemoClass MyDemoClass;

struct _MyDemoClass {
    GObjectClass parent_class;
};

GType my_demo_get_type(void) G_GNUC_CONST;//my_demo_get_type将会使用宏G_DEFINE_TYPE去实现(G_DEFINE_TYPE(MyDemo,my_demo,G_TYPE_OBJECT)),其中的my通常表示命名空间,demo表示对象名字,get_type为固定字段

MyDemo *my_demo_new(const gchar *name, gint64 age);

#ifdef __cplusplus
}
#endif

#endif // _MY_DEMO_H_

2.my_demo.c

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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#include "my_demo.h"
#include <stdio.h>

enum
{
    PROP_0,
    PROP_NAME,
    PROP_AGE,
    N_PROPERTIES
};

#define MY_DEMO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MY_TYPE_DEMO, MyDemoPrivate))

static void my_demo_init(MyDemo *self);
static void my_demo_class_init(MyDemoClass *klass);

/*
 * G_DEFINE_TYPE 可以让 GObject 库的数据类型系统能够识别我们所定义的 MyDemo 类类型,
 * 它接受三个参数,第一个参数是类名,即 MyDemo;第二个参数则是类的成员函数名称的前缀,例如 my_demo_get_type 函数即为 MyDemo 类的一个成员函数,"my_demo"是它的前缀;第三个参数则指明 MyDemo 类类型的父类型为G_TYPE_OBJECT。
 * G_DEFINE_TYPE中会调用一个 g_type_register_static_simple 的函数,这个函数的作用就是将用户自己定义的类型注册到系统中,
 * G_DEFINE_TYPE还定义了2个函数(my_demo_init 和 my_demo_class_init),需要自己实现这两个函数。它们是对象的初始化函数,相当于c++的构造函数,第一个函数在每个对象创建的时候都会被调用,
 * 第二个函数只有在第一次创建对象的时候被调用(比如在调用g_type_class_ref的时候,如果class没有初始化,就会调用my_demo_class_init)
*/
G_DEFINE_TYPE (MyDemo, my_demo, G_TYPE_OBJECT);


static void my_demo_dispose(GObject *object);
static void my_demo_finalize(GObject *object);

/*
//以下代码为替换宏G_DEFINE_TYPE的另外一种对my_demo_get_type函数的实现方法,代码不好理解,不建议使用这种方法
static gpointer my_demo_parent_class = ((void*) 0);
static void     my_demo_class_intern_init(gpointer klass)
{
    my_demo_parent_class = g_type_class_peek_parent(klass);
    my_demo_class_init ((MyDemoClass*)klass);
}
GType my_demo_get_type (void)
{
    static volatile gsize g_define_type_id__volatile = 0;
    if (g_once_init_enter(&g_define_type_id__volatile))
    {
        GType g_define_type_id =
        g_type_register_static_simple (((GType)((20) << (2))),
                                       g_intern_static_string("MyDemo"),
                                       sizeof(MyDemoClass),
                                       (GClassInitFunc)my_demo_class_intern_init,
                                       sizeof(MyDemo),
                                       (GInstanceInitFunc)my_demo_init,
                                       (GTypeFlags)0);
        { {{};} }
        g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
    }
    return g_define_type_id__volatile;
}
*/

static void my_demo_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
    MyDemo *self;

    g_return_if_fail(object != NULL);

    self = MY_DEMO (object);
    //self->priv = MY_DEMO_GET_PRIVATE(self);

    switch (prop_id)
    {
    case PROP_NAME:
        self->priv->name = g_value_dup_string(value);
        break;
    case PROP_AGE:
        self->priv->age = g_value_get_int64(value);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}

static void my_demo_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
    MyDemo *self;

    g_return_if_fail(object != NULL);

    self = MY_DEMO(object);

    switch (prop_id)
    {
    case PROP_NAME:
        g_value_set_string(value, self->priv->name);
        break;
    case PROP_AGE:
        g_value_set_int64(value, self->priv->age);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}

//类结构体初始化函数
static void my_demo_class_init(MyDemoClass *klass)
{
    printf("%s\n", __FUNCTION__);

    int signal_id = g_signal_new("broadcast_msg",
        my_demo_get_type(),/*G_OBJECT_CLASS_TYPE(kclass)*/
        G_SIGNAL_RUN_LAST,
        0,
        NULL,
        NULL,
        g_cclosure_marshal_VOID__STRING,
        G_TYPE_NONE,/*返回值,因为信号没有返回,所以为NONE*/
        1,/*参数数目*/
        G_TYPE_STRING/*参数类型*/
    );

    GObjectClass *object_class = G_OBJECT_CLASS(klass);
    object_class->finalize = my_demo_finalize;
    object_class->dispose = my_demo_dispose;

    object_class->set_property = my_demo_set_property;
    object_class->get_property = my_demo_get_property;

    g_object_class_install_property(object_class,
                                    PROP_NAME,
                                    g_param_spec_string("name",
                                                      "name",
                                                      "Specify the name of demo",
                                                      "Unknown",
                                                      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));

    g_object_class_install_property(object_class,
                                    PROP_AGE,
                                    g_param_spec_int64 ("age",
                                                     "age",
                                                     "Specify age number",
                                                     G_MININT64, G_MAXINT64, 0,
                                                     G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));

    // 如果对struct MyDemoPrivate 里面添加了成员变量,则执行下面这行代码
    g_type_class_add_private(klass, sizeof(MyDemoPrivate));
}

//实例结构体初始化函数
static void my_demo_init(MyDemo *self)
{
    printf("%s\n", __FUNCTION__);
    self->priv = MY_DEMO_GET_PRIVATE(self);
}

static void my_demo_dispose(GObject *object)
{
    printf("%s\n", __FUNCTION__);
}

static void my_demo_finalize(GObject *object)
{
    printf("%s\n", __FUNCTION__);

    MyDemo *self;

    g_return_if_fail(object != NULL);

    self = MY_DEMO(object);

    if (self->priv->name)
        g_free (self->priv->name);

    G_OBJECT_CLASS(my_demo_parent_class)->finalize(object);
}

MyDemo *my_demo_new(const gchar *name, gint64 age)
{
    MyDemo *demo;

    demo = MY_DEMO(g_object_new(MY_TYPE_DEMO,
                                "name", name,
                                "age", age,
                                NULL));

    printf("get property name:%s, age:%ld\n", demo->priv->name, demo->priv->age);

    return demo;
}

3.main.c

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
#include <glib.h>
#include <glib-unix.h>
#include <stdio.h>

#include "my_demo.h"

static GMainLoop *loop = NULL;

static gboolean signal_handler(gpointer user_data)
{
    g_main_loop_quit(loop);
    return FALSE;
}

void handler_receive_msg(GObject *sender, char *name, gpointer data)
{
    MyDemo *demo = G_TYPE_CHECK_INSTANCE_CAST(sender, my_demo_get_type(), MyDemo);
    printf("handler: [%s] from [%s: %ld]\n", name, demo->priv->name, demo->priv->age);
}

int main(int argc, char* argv[])
{
#if !GLIB_CHECK_VERSION(2,32,0)
    if (! g_thread_supported ())
        g_thread_init (NULL);
#endif
#if !GLIB_CHECK_VERSION(2,36,0)
    g_type_init ();
#endif

    loop = g_main_loop_new(NULL, FALSE);
    g_unix_signal_add_full(G_PRIORITY_DEFAULT,
                                    SIGINT,
                                    signal_handler,
                                    NULL,
                                    NULL);
    int i;
    MyDemo *demos[3];
    int len = sizeof(demos) / sizeof(demos[0]);

    for (i = 0; i < len; i++) {
        printf("construction demos[%d]\n", i);
        //创建对象
        //demos[i]= g_object_new(MY_TYPE_DEMO, NULL);
        /*demos[i]= g_object_new(MY_TYPE_DEMO,
                               "name", "kobe",
                               "age", i,
                               NULL);*/
        gchar *name = g_strdup_printf("kobe%d", i);
        demos[i] = my_demo_new(name, i);
        g_free(name);
        //绑定信号
        g_signal_connect(demos[i], "broadcast_msg", G_CALLBACK(handler_receive_msg), NULL);
        //发送信号
        g_signal_emit_by_name(demos[i], "broadcast_msg", "lixiang");
    }

    //析构
    for(i = 0; i < len; i++){
        printf("destruction demos[%d]\n", i);
        g_object_unref(demos[i]);
    }

    g_main_loop_run(loop);
    g_main_loop_unref(loop);

    return 0;
}

4.Makefile

1
2
3
4
5
6
7
8
9
10
11
12
13
CC = gcc
CC_FLAGS = $(shell pkg-config --cflags glib-2.0 gthread-2.0 gobject-2.0)
CC_FLAGS += -std=c99 -g
LD_FLAGS = $(shell pkg-config --libs glib-2.0 gthread-2.0 gobject-2.0)

gobjectdemo:main.o my_demo.o
    $(CC) -o $@ $+ $(LD_FLAGS)

%.o:%.c
    $(CC) $(CC_FLAGS) -c -o $@ $<
 
clean:
    rm -rf *.o gobjectdemo

5.安装、编译glib

1
2
3
# sudo apt install libglib2.0-dev
# make
# ./gobjectdemo

官网