有两种类型,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来实现这些函数。
/* filename: tnumber.h */1 #ifndef __T_NUMBER_H__2 #define __T_NUMBER_H__3 4 #include 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
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()的支持。
/* 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 void8 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
1.
t_number_init()函数的声明。2.
t_number_class_init()函数的声明。3.定义
t_number_get_type()函数。4.
指向父类的静态变量t_number_parent_class的定义。tint.h是TInt对象的头文件。TInt是TNumber的子对象。
1 #ifndef __T_INT_H__2 #define __T_INT_H__3 4 #include 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
tint.c实现了虚函数(类方法)。TNumberClass中方法的指针在这里被重写。
/* filename:tint.c */1 #include "tint.h"2 #include "tdouble.h"3 4 #define PROP_INT 15 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 void15 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 } else21 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);22 }23 24 static void25 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 else31 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);32 }33 34 static void35 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 } else84 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 } else91 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
1.
t_int_init()函数的声明。2.
t_int_get_type()函数的定义。3.
定义指向父类的静态变量t_int_parent_class。TDoubleicloud对象由TDouble .h和TDouble .c定义。它的定义与TInt非常相似。因此,这个小节只显示文件的内容。
/* filename: tdouble.h */1 #ifndef __T_DOUBLE_H__2 #define __T_DOUBLE_H__3 4 #include 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 15 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 void15 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 } else20 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);21 }22 23 static void24 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 else30 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);31 }32 33 static void34 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 } else83 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 } else90 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 2 #include "tnumber.h"3 #include "tint.h"4 #include "tdouble.h"5 6 static void7 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
下图显示了这个过程。
下图显示了这个过程。
翻译自:GObject tutorial
下一篇:[JavaEE]线程的状态与安全