可派生类型
有两种类型,final类型和derivable类型。final类型没有任何子对象。derivable有子对象。
这两个对象之间的主要区别是它们的类。final类型对象没有自己的类区域。类的唯一成员是它的父类。
派生对象在类中有自己的区域。该类对其子类开放。
G_DECLARE_DERIVABLE_TYPE 用于声明可派生类型。它像这样写在头文件中:
#define T_TYPE_NUMBER (t_number_get_type ())
G_DECLARE_DERIVABLE_TYPE (TNumber, t_number, T, NUMBER, GObject)
抽象类
抽象类型没有任何实例。这种类型的对象是可衍生的,它的子对象可以使用抽象对象的函数和信号。
本节的例子是TNumber, TInt和TDouble对象。TInt和TDouble已经在前一节中创建。它们分别代表整数和浮点数。数字比整数和浮点数更抽象。
TNumber是一个表示数字的抽象对象。TNumber是TInt和TDouble的父对象。TNumber没有被实例化,因为它的类型是抽象的。当一个实例具有TInt或TDouble类型时,它也是TNumber的实例。
TInt和TDouble有五种运算:加、减、乘、除和一元减运算。这些操作可以在TNumber对象上定义。
在本节中,我们将定义TNumber对象和上面的五个函数。此外,还将添加to_s函数。它将TNumber的值转换为字符串。它类似于sprintf函数。我们将重写TInt和TDouble来实现这些函数。
TNumber对象
/* filename: tnumber.h */
1 #ifndef __T_NUMBER_H__
2 #define __T_NUMBER_H__
3
4 #include <glib-object.h>
5
6 #define T_TYPE_NUMBER (t_number_get_type ())
7 G_DECLARE_DERIVABLE_TYPE (TNumber, t_number, T, NUMBER, GObject)
8
9 struct _TNumberClass {
10 GObjectClass parent_class;
11 TNumber* (*add) (TNumber *self, TNumber *other);
12 TNumber* (*sub) (TNumber *self, TNumber *other);
13 TNumber* (*mul) (TNumber *self, TNumber *other);
14 TNumber* (*div) (TNumber *self, TNumber *other);
15 TNumber* (*uminus) (TNumber *self);
16 char * (*to_s) (TNumber *self);
17 /* signal */
18 void (*div_by_zero) (TNumber *self);
19 };
20
21 /* arithmetic operator */
22 /* These operators create a new instance and return a pointer to it. */
23 TNumber *
24 t_number_add (TNumber *self, TNumber *other);
25
26 TNumber *
27 t_number_sub (TNumber *self, TNumber *other);
28
29 TNumber *
30 t_number_mul (TNumber *self, TNumber *other);
31
32 TNumber *
33 t_number_div (TNumber *self, TNumber *other);
34
35 TNumber *
36 t_number_uminus (TNumber *self);
37
38 char *
39 t_number_to_s (TNumber *self);
40 #endif /* __T_NUMBER_H__ */
41
- 7: G_DECLARE_DERIVABLE_TYPE宏。这类似于G_DECLARE_FINAL_TYPE宏。不同之处是可派生的类或最终的类。G_DECLARE_DERIVABLE_TYPE展开为:
1.
t_number_get_type()函数的声明。该函数必须在tnumber.c文件中定义。定义通常使用G_DEFINE_TYPE或其家族宏完成。
2.
定义TNumber实例,其成员仅为其父实例。
3.
声明TNumberClass。它应该稍后在头文件中定义。
4.
定义了方便宏T_NUMBER(转换为实例),T_NUMBER_CLASS(转换为类),T_IS_NUMBER(实例检查),T_IS_NUMBER_CLASS(类检查)和T_NUMBER_GET_CLASS。
5.
g_autoptr()的支持。
- 9-19: TNumberClass结构体的定义。
- 11-16:定义了一些函数指针。它们被称为类方法或虚函数。它们将被后代对象中的函数重写。方法是5个算术运算符和to_s函数。To_s函数类似于sprintf函数。
- 18:指向"div-by- 0 "信号的默认信号处理程序的指针。该指针的偏移量作为参数赋给g_signal_new。
- 21-40:函数。它们是公有的。
/* filename: tnumber.c */
1 #include "tnumber.h"
2
3 static guint t_number_signal;
4
5 G_DEFINE_ABSTRACT_TYPE (TNumber, t_number, G_TYPE_OBJECT)
6
7 static void
8 div_by_zero_default_cb (TNumber *self) {
9 g_printerr ("\nError: division by zero.\n\n");
10 }
11
12 static void
13 t_number_class_init (TNumberClass *class) {
14
15 /* virtual functions */
16 class->add = NULL;
17 class->sub = NULL;
18 class->mul = NULL;
19 class->div = NULL;
20 class->uminus = NULL;
21 class->to_s = NULL;
22 /* default signal handler */
23 class->div_by_zero = div_by_zero_default_cb;
24 /* signal */
25 t_number_signal =
26 g_signal_new ("div-by-zero",
27 G_TYPE_FROM_CLASS (class),
28 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
29 G_STRUCT_OFFSET (TNumberClass, div_by_zero),
30 NULL /* accumulator */,
31 NULL /* accumulator data */,
32 NULL /* C marshaller */,
33 G_TYPE_NONE /* return_type */,
34 0 /* n_params */
35 );
36 }
37
38 static void
39 t_number_init (TNumber *inst) {
40 }
41
42 TNumber *
43 t_number_add (TNumber *self, TNumber *other) {
44 g_return_val_if_fail (T_IS_NUMBER (self), NULL);
45 g_return_val_if_fail (T_IS_NUMBER (other), NULL);
46
47 TNumberClass *class = T_NUMBER_GET_CLASS(self);
48 return class->add ? class->add (self, other) : NULL;
49 }
50
51 TNumber *
52 t_number_sub (TNumber *self, TNumber *other) {
53 g_return_val_if_fail (T_IS_NUMBER (self), NULL);
54 g_return_val_if_fail (T_IS_NUMBER (other), NULL);
55
56 TNumberClass *class = T_NUMBER_GET_CLASS(self);
57 return class->sub ? class->sub (self, other) : NULL;
58 }
59
60 TNumber *
61 t_number_mul (TNumber *self, TNumber *other) {
62 g_return_val_if_fail (T_IS_NUMBER (self), NULL);
63 g_return_val_if_fail (T_IS_NUMBER (other), NULL);
64
65 TNumberClass *class = T_NUMBER_GET_CLASS(self);
66 return class->mul ? class->mul (self, other) : NULL;
67 }
68
69 TNumber *
70 t_number_div (TNumber *self, TNumber *other) {
71 g_return_val_if_fail (T_IS_NUMBER (self), NULL);
72 g_return_val_if_fail (T_IS_NUMBER (other), NULL);
73
74 TNumberClass *class = T_NUMBER_GET_CLASS(self);
75 return class->div ? class->div (self, other) : NULL;
76 }
77
78 TNumber *
79 t_number_uminus (TNumber *self) {
80 g_return_val_if_fail (T_IS_NUMBER (self), NULL);
81
82 TNumberClass *class = T_NUMBER_GET_CLASS(self);
83 return class->uminus ? class->uminus (self) : NULL;
84 }
85
86 char *
87 t_number_to_s (TNumber *self) {
88 g_return_val_if_fail (T_IS_NUMBER (self), NULL);
89
90 TNumberClass *class = T_NUMBER_GET_CLASS(self);
91 return class->to_s ? class->to_s (self) : NULL;
92 }
93
- 5: G_DEFINE_ABSTRACT_TYPE宏。此宏用于定义一个抽象类型对象。抽象类型没有实例化。这个宏被扩展为:
1.
t_number_init()函数的声明。
2.
t_number_class_init()函数的声明。
3.定义
t_number_get_type()函数。
4.
指向父类的静态变量t_number_parent_class的定义。 - 3,7 - 10,25 -35:定义除零信号。Div_by_zero_default_cb是“div-by- 0”信号的默认处理程序。默认处理程序没有用户数据参数。使用g_signal_new代替g_signal_new_class_handler。g_signal_new指定一个处理程序(通过类指针偏移量)。
- 12-36: t_number_class_init。
- 16-21:这些类方法是虚函数。它们被期望在TNumber的后代对象中被覆盖。这里赋值为NULL,以便在调用方法时不发生任何事情。
- 23:将函数dev_by_zero_default_cb的地址分配给class->div_by_zero。这是“div-by- 0”信号的默认处理程序。
- 38-40: t_number_init是实例的初始化函数。但是抽象对象没有被实例化。在这个函数中什么都没有做。但是你不能忽略这个函数的定义。
- 42-92:公有函数。如果指向类方法的指针不是NULL,这些函数只调用相应的类方法。
TInt object
tint.h是TInt对象的头文件。TInt是TNumber的子对象。
1 #ifndef __T_INT_H__
2 #define __T_INT_H__
3
4 #include <glib-object.h>
5 #include "tnumber.h"
6
7 #define T_TYPE_INT (t_int_get_type ())
8 G_DECLARE_FINAL_TYPE (TInt, t_int, T, INT, TNumber)
9
10 /* create a new TInt instance */
11 TInt *
12 t_int_new_with_value (int value);
13
14 TInt *
15 t_int_new (void);
16 #endif /* __T_INT_H__ */
17
- 10-16:声明公有函数。算术函数和to_s是在TNumber中声明的,所以TInt不会声明这些函数。只声明实例创建函数。
tint.c实现了虚函数(类方法)。TNumberClass中方法的指针在这里被重写。
/* filename:tint.c */
1 #include "tint.h"
2 #include "tdouble.h"
3
4 #define PROP_INT 1
5 static GParamSpec *int_property = NULL;
6
7 struct _TInt {
8 TNumber parent;
9 int value;
10 };
11
12 G_DEFINE_TYPE (TInt, t_int, T_TYPE_NUMBER)
13
14 static void
15 t_int_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
16 TInt *self = T_INT (object);
17
18 if (property_id == PROP_INT) {
19 self->value = g_value_get_int (value);
20 } else
21 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
22 }
23
24 static void
25 t_int_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
26 TInt *self = T_INT (object);
27
28 if (property_id == PROP_INT)
29 g_value_set_int (value, self->value);
30 else
31 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
32 }
33
34 static void
35 t_int_init (TInt *d) {
36 }
37
38 /* arithmetic operator */
39 /* These operators create a new instance and return a pointer to it. */
40 #define t_int_binary_op(op) \
41 int i; \
42 double d; \
43 if (T_IS_INT (other)) { \
44 g_object_get (T_INT (other), "value", &i, NULL); \
45 return T_NUMBER (t_int_new_with_value (T_INT(self)->value op i)); \
46 } else { \
47 g_object_get (T_DOUBLE (other), "value", &d, NULL); \
48 return T_NUMBER (t_int_new_with_value (T_INT(self)->value op (int) d)); \
49 }
50
51 static TNumber *
52 t_int_add (TNumber *self, TNumber *other) {
53 g_return_val_if_fail (T_IS_INT (self), NULL);
54
55 t_int_binary_op (+)
56 }
57
58 static TNumber *
59 t_int_sub (TNumber *self, TNumber *other) {
60 g_return_val_if_fail (T_IS_INT (self), NULL);
61
62 t_int_binary_op (-)
63 }
64
65 static TNumber *
66 t_int_mul (TNumber *self, TNumber *other) {
67 g_return_val_if_fail (T_IS_INT (self), NULL);
68
69 t_int_binary_op (*)
70 }
71
72 static TNumber *
73 t_int_div (TNumber *self, TNumber *other) {
74 g_return_val_if_fail (T_IS_INT (self), NULL);
75 int i;
76 double d;
77
78 if (T_IS_INT (other)) {
79 g_object_get (T_INT (other), "value", &i, NULL);
80 if (i == 0) {
81 g_signal_emit_by_name (self, "div-by-zero");
82 return NULL;
83 } else
84 return T_NUMBER (t_int_new_with_value (T_INT(self)->value / i));
85 } else {
86 g_object_get (T_DOUBLE (other), "value", &d, NULL);
87 if (d == 0) {
88 g_signal_emit_by_name (self, "div-by-zero");
89 return NULL;
90 } else
91 return T_NUMBER (t_int_new_with_value (T_INT(self)->value / (int) d));
92 }
93 }
94
95 static TNumber *
96 t_int_uminus (TNumber *self) {
97 g_return_val_if_fail (T_IS_INT (self), NULL);
98
99 return T_NUMBER (t_int_new_with_value (- T_INT(self)->value));
100 }
101
102 static char *
103 t_int_to_s (TNumber *self) {
104 g_return_val_if_fail (T_IS_INT (self), NULL);
105 int i;
106
107 g_object_get (T_INT (self), "value", &i, NULL);
108 return g_strdup_printf ("%d", i);
109 }
110
111 static void
112 t_int_class_init (TIntClass *class) {
113 TNumberClass *tnumber_class = T_NUMBER_CLASS (class);
114 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
115
116 /* override virtual functions */
117 tnumber_class->add = t_int_add;
118 tnumber_class->sub = t_int_sub;
119 tnumber_class->mul = t_int_mul;
120 tnumber_class->div = t_int_div;
121 tnumber_class->uminus = t_int_uminus;
122 tnumber_class->to_s = t_int_to_s;
123
124 gobject_class->set_property = t_int_set_property;
125 gobject_class->get_property = t_int_get_property;
126 int_property = g_param_spec_int ("value", "val", "Integer value", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE);
127 g_object_class_install_property (gobject_class, PROP_INT, int_property);
128 }
129
130 TInt *
131 t_int_new_with_value (int value) {
132 TInt *d;
133
134 d = g_object_new (T_TYPE_INT, "value", value, NULL);
135 return d;
136 }
137
138 TInt *
139 t_int_new (void) {
140 TInt *d;
141
142 d = g_object_new (T_TYPE_INT, NULL);
143 return d;
144 }
145
- 4- 5,14 - 32,124 -127:属性“value”的定义。这和以前一样。
- 7-10: TInt结构的定义。必须在G_DEFINE_TYPE之前定义。
- 12: G_DEFINE_TYPE宏。这个宏展开为:
1.
t_int_init()函数的声明。
2.
t_int_get_type()函数的定义。
3.
定义指向父类的静态变量t_int_parent_class。 - 34-36: t_int_init。
- 40-109:这些函数连接到TIntClass中的类方法指针。它们是tnumber.c中定义的虚函数的实现。
- 40-49:定义在t_int_add, t_int_sub和t_int_mul中使用的宏。这个宏类似于t_int_div函数。请参阅下面对t_int_div的解释。
- 51-70: t_int_add, t_int_sub, t_int_mul函数。使用宏t_int_binary_op。
- 72 - 93: t_int_div。Self是调用函数的对象。other是另一个TNumber对象。它可以是TInt或TDouble。如果是TDouble,则在执行除法之前将其值转换为int。如果除数(other)为零,则发出“div-by- 0”信号。信号在TNumber中定义,所以TInt不知道信号id。发射使用g_signal_emit_by_name而不是g_signal_emit完成。t_int_div的返回值是TNumber类型的对象。但是,因为TNumber是抽象的,所以该对象的实际类型是TInt。
- 95-100:一元负运算符的函数。
- 102-109: to_s函数。这个函数将int转换为字符串。例如,如果该对象的值为123,则结果为字符串“123”。如果字符串变得无用,调用者应该释放它。
- 111—128:t_int_class_init。
- 117-122:类方法被重写。例如,如果在TInt对象上调用t_number_add,则该函数调用类方法*tnumber_class->add。指针指向t_int_add函数。因此,最后调用t_int_add。
- 130-144:实例创建功能不变。
TDouble object
TDoubleicloud对象由TDouble .h和TDouble .c定义。它的定义与TInt非常相似。因此,这个小节只显示文件的内容。
/* filename: tdouble.h */
1 #ifndef __T_DOUBLE_H__
2 #define __T_DOUBLE_H__
3
4 #include <glib-object.h>
5 #include "tnumber.h"
6
7 #define T_TYPE_DOUBLE (t_double_get_type ())
8 G_DECLARE_FINAL_TYPE (TDouble, t_double, T, DOUBLE, TNumber)
9
10 /* create a new TDouble instance */
11 TDouble *
12 t_double_new_with_value (double value);
13
14 TDouble *
15 t_double_new (void);
16 #endif /* __T_DOUBLE_H__ */
17
/* filename: tdouble.c */
1 #include "tdouble.h"
2 #include "tint.h"
3
4 #define PROP_DOUBLE 1
5 static GParamSpec *double_property = NULL;
6
7 struct _TDouble {
8 TNumber parent;
9 double value;
10 };
11
12 G_DEFINE_TYPE (TDouble, t_double, T_TYPE_NUMBER)
13
14 static void
15 t_double_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {
16 TDouble *self = T_DOUBLE (object);
17 if (property_id == PROP_DOUBLE) {
18 self->value = g_value_get_double (value);
19 } else
20 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
21 }
22
23 static void
24 t_double_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {
25 TDouble *self = T_DOUBLE (object);
26
27 if (property_id == PROP_DOUBLE)
28 g_value_set_double (value, self->value);
29 else
30 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
31 }
32
33 static void
34 t_double_init (TDouble *d) {
35 }
36
37 /* arithmetic operator */
38 /* These operators create a new instance and return a pointer to it. */
39 #define t_double_binary_op(op) \
40 int i; \
41 double d; \
42 if (T_IS_INT (other)) { \
43 g_object_get (T_INT (other), "value", &i, NULL); \
44 return T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value op (double) i)); \
45 } else { \
46 g_object_get (T_DOUBLE (other), "value", &d, NULL); \
47 return T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value op d)); \
48 }
49
50 static TNumber *
51 t_double_add (TNumber *self, TNumber *other) {
52 g_return_val_if_fail (T_IS_DOUBLE (self), NULL);
53
54 t_double_binary_op (+)
55 }
56
57 static TNumber *
58 t_double_sub (TNumber *self, TNumber *other) {
59 g_return_val_if_fail (T_IS_DOUBLE (self), NULL);
60
61 t_double_binary_op (-)
62 }
63
64 static TNumber *
65 t_double_mul (TNumber *self, TNumber *other) {
66 g_return_val_if_fail (T_IS_DOUBLE (self), NULL);
67
68 t_double_binary_op (*)
69 }
70
71 static TNumber *
72 t_double_div (TNumber *self, TNumber *other) {
73 g_return_val_if_fail (T_IS_DOUBLE (self), NULL);
74 int i;
75 double d;
76
77 if (T_IS_INT (other)) {
78 g_object_get (T_INT (other), "value", &i, NULL);
79 if (i == 0) {
80 g_signal_emit_by_name (self, "div-by-zero");
81 return NULL;
82 } else
83 return T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value / (double) i));
84 } else {
85 g_object_get (T_DOUBLE (other), "value", &d, NULL);
86 if (d == 0) {
87 g_signal_emit_by_name (self, "div-by-zero");
88 return NULL;
89 } else
90 return T_NUMBER (t_double_new_with_value (T_DOUBLE(self)->value / d));
91 }
92 }
93
94 static TNumber *
95 t_double_uminus (TNumber *self) {
96 g_return_val_if_fail (T_IS_DOUBLE (self), NULL);
97
98 return T_NUMBER (t_double_new_with_value (- T_DOUBLE(self)->value));
99 }
100
101 static char *
102 t_double_to_s (TNumber *self) {
103 g_return_val_if_fail (T_IS_DOUBLE (self), NULL);
104 double d;
105
106 g_object_get (T_DOUBLE (self), "value", &d, NULL);
107 return g_strdup_printf ("%lf", d);
108 }
109
110 static void
111 t_double_class_init (TDoubleClass *class) {
112 TNumberClass *tnumber_class = T_NUMBER_CLASS (class);
113 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
114
115 /* override virtual functions */
116 tnumber_class->add = t_double_add;
117 tnumber_class->sub = t_double_sub;
118 tnumber_class->mul = t_double_mul;
119 tnumber_class->div = t_double_div;
120 tnumber_class->uminus = t_double_uminus;
121 tnumber_class->to_s = t_double_to_s;
122
123 gobject_class->set_property = t_double_set_property;
124 gobject_class->get_property = t_double_get_property;
125 double_property = g_param_spec_double ("value", "val", "Double value", -G_MAXDOUBLE, G_MAXDOUBLE, 0, G_PARAM_READWRITE);
126 g_object_class_install_property (gobject_class, PROP_DOUBLE, double_property);
127 }
128
129 TDouble *
130 t_double_new_with_value (double value) {
131 TDouble *d;
132
133 d = g_object_new (T_TYPE_DOUBLE, "value", value, NULL);
134 return d;
135 }
136
137 TDouble *
138 t_double_new (void) {
139 TDouble *d;
140
141 d = g_object_new (T_TYPE_DOUBLE, NULL);
142 return d;
143 }
144
/* filename: mainc.c */
1 #include <glib-object.h>
2 #include "tnumber.h"
3 #include "tint.h"
4 #include "tdouble.h"
5
6 static void
7 notify_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data) {
8 const char *name;
9 int i;
10 double d;
11
12 name = g_param_spec_get_name (pspec);
13 if (T_IS_INT (gobject) && strcmp (name, "value") == 0) {
14 g_object_get (T_INT (gobject), "value", &i, NULL);
15 g_print ("Property \"%s\" is set to %d.\n", name, i);
16 } else if (T_IS_DOUBLE (gobject) && strcmp (name, "value") == 0) {
17 g_object_get (T_DOUBLE (gobject), "value", &d, NULL);
18 g_print ("Property \"%s\" is set to %lf.\n", name, d);
19 }
20 }
21
22 int
23 main (int argc, char **argv) {
24 TNumber *i, *d, *num;
25 char *si, *sd, *snum;
26
27 i = T_NUMBER (t_int_new ());
28 d = T_NUMBER (t_double_new ());
29
30 g_signal_connect (G_OBJECT (i), "notify::value", G_CALLBACK (notify_cb), NULL);
31 g_signal_connect (G_OBJECT (d), "notify::value", G_CALLBACK (notify_cb), NULL);
32
33 g_object_set (T_INT (i), "value", 100, NULL);
34 g_object_set (T_DOUBLE (d), "value", 12.345, NULL);
35
36 num = t_number_add (i, d);
37
38 si = t_number_to_s (i);
39 sd = t_number_to_s (d);
40 snum = t_number_to_s (num);
41
42 g_print ("%s + %s is %s.\n", si, sd, snum);
43
44 g_object_unref (num);
45 g_free (snum);
46
47 num = t_number_add (d, i);
48 snum = t_number_to_s (num);
49
50 g_print ("%s + %s is %s.\n", sd, si, snum);
51
52 g_object_unref (num);
53 g_free (sd);
54 g_free (snum);
55
56 g_object_set (T_DOUBLE (d), "value", 0.0, NULL);
57 sd = t_number_to_s (d);
58 if ((num = t_number_div(i, d)) != NULL) {
59 snum = t_number_to_s (num);
60 g_print ("%s / %s is %s.\n", si, sd, snum);
61 g_object_unref (num);
62 g_free (snum);
63 }
64
65 g_object_unref (i);
66 g_object_unref (d);
67 g_free (si);
68 g_free (sd);
69
70 return 0;
71 }
72
- 6-20:“notify”处理程序。这个处理程序已经升级,可以同时支持TInt和TDouble。
22-71:函数main。
30-31:连接i (TInt)和d (TDouble)上的notify信号。
33-34:设置i和d的value属性
36: i加d。答案是TInt对象。
47:将i加到d。答案是TDouble对象。两个TNumber对象的加法不是可交换的,因为交换后的结果类型不同。
56-63:测试除零信号。
类初始化过程
- GObjectClass在main函数之前已经被初始化(这个和GCC编译器有关,GCC编译器已经给初始化)
- 第一次调用g_object_new (T_TYPE_INT,…)或g_object_new (T_TYPE_DOUBLE,…)初始化TNumberClass。因为TNumber是一个抽象对象,所以不能实例化它。相反,它的子对象TInt或TDouble可以被实例化。当子类第一次被实例化时,TNumberClass会在子类初始化之前被初始化。初始化过程如下。
- 给TNumberClass类分配内存。
- 拷贝父类部分(GObjectClass)。
- t_number_class_init被调用去初始化TNumberClass。这包括初始化指向类方法处理程序的指针和默认信号处理程序。
下图显示了这个过程。
TIntClass的初始化过程
- GNumberClass在开始初始化GIntClass之前已经初始化。
- 第一次调用g_object_new (T_TYPE_INT,…)初始化TIntClass。初始化过程如下。
- 内存被分配给TIntClass。TIntClass没有自己的区域。因此,它的结构与其父类(TNumberClass)相同。
- 类的父类(TNumberClass)部分(这与整个TIntClass相同)是从TNumberClass复制的。
- 调用t_int_class_init来初始化TIntClass。这包括重写类方法set_property和get_property。
下图显示了这个过程。
翻译自:GObject tutorial