sec6-可派生类型和抽象类型

可派生类型

有两种类型,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:测试除零信号。

类初始化过程

  1. GObjectClass在main函数之前已经被初始化(这个和GCC编译器有关,GCC编译器已经给初始化)
  2. 第一次调用g_object_new (T_TYPE_INT,…)或g_object_new (T_TYPE_DOUBLE,…)初始化TNumberClass。因为TNumber是一个抽象对象,所以不能实例化它。相反,它的子对象TInt或TDouble可以被实例化。当子类第一次被实例化时,TNumberClass会在子类初始化之前被初始化。初始化过程如下。
  3. 给TNumberClass类分配内存。
  4. 拷贝父类部分(GObjectClass)。
  5. t_number_class_init被调用去初始化TNumberClass。这包括初始化指向类方法处理程序的指针和默认信号处理程序。

下图显示了这个过程。
在这里插入图片描述

TIntClass的初始化过程

  1. GNumberClass在开始初始化GIntClass之前已经初始化。
  2. 第一次调用g_object_new (T_TYPE_INT,…)初始化TIntClass。初始化过程如下。
  3. 内存被分配给TIntClass。TIntClass没有自己的区域。因此,它的结构与其父类(TNumberClass)相同。
  4. 类的父类(TNumberClass)部分(这与整个TIntClass相同)是从TNumberClass复制的。
  5. 调用t_int_class_init来初始化TIntClass。这包括重写类方法set_property和get_property。

下图显示了这个过程。
在这里插入图片描述
翻译自:GObject tutorial

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值