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

news2024/9/22 21:26:11

可派生类型

有两种类型,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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/133612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python系列】第三章 基本数据类型

*该系列内容来自于&#xff1a;中国大学MOOC&#xff08;幕客&#xff09;-python语言程序设计 ​​​​​​Python语言程序设计_北京理工大学_中国大学MOOC(慕课) 第三章 基本数据类型 方法论&#xff1a;Python语言数字及字符串类型 实践能力&#xff1a;初步学会编程进行…

236. 二叉树的最近公共祖先 - 力扣[LeetCode]

目录 如果二叉树是二叉搜索树&#xff1a; 如果是普通的二叉树 【方法一】子树判断法 【方法二】路径确定 【方法三】递归 面对此类型的公共祖先问题&#xff0c;可以分为以下几类情况讨论 如果二叉树是二叉搜索树&#xff1a; a. 如果树是空&#xff0c;直接返回nullpt…

分布式存储系统 Ceph 介绍与环境部署

文章目录一、概述二、Ceph 架构三、Ceph核心组件介绍四、Ceph 三种存储类型1&#xff09;块存储服务(RBD)2&#xff09;文件系统存储服务(CephFS)3&#xff09;对象存储服务(RGW)五、Ceph版本发行生命周期六、Ceph 集群部署1&#xff09;集群部署规划2&#xff09;前期准备1、关…

Python--让我们秀翻算法中的二进制

我相信大家在leetcode刷题或者更好的国外天梯刷题的时候应该经常能看到 **<<,>>,|,&**在我们的if里面构成了一个判断的条件. 然后在大家看不懂情况下就莫名其妙的把题目作对了!!! 所以我们准备持续的更新一下,二进制的用法. 大家要明白一个道理.一切的工具它…

Excel聚光灯--双箭头指示

实例需求&#xff1a;在工作表中核对数据时&#xff0c;虽然行列标题都会高亮显示&#xff0c;但是似乎并不明显&#xff0c;因此添加两个列标到活动单元格的箭头&#xff0c;以便于更好的定位。 选中单个单元格效果如下图所示。 选中多个单元格的效果如下图所示。 示例代码如…

51单片机——输出可调PWM

PWM控制在很多地方都会用到&#xff0c;比如使用PWM来控制电机的速度&#xff0c;使用PWM来生成想要的波形。 一、PWM PWM即脉冲宽度调制&#xff0c;在具有惯性的系统中&#xff0c;可以通过对一系列脉冲的宽度进行调制&#xff0c;来等效的获得所需要的模拟参量&#xff1b…

[JavaEE]线程的状态与安全

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1. 线程状态 1.1 观察线程的所有状态 1.2 线程的…

k-means算法进行数据分析应用

简介 kmeans算法又名k均值算法,K-means算法中的k表示的是聚类为k个簇&#xff0c;means代表取每一个聚类中数据值的均值作为该簇的中心&#xff0c;或者称为质心&#xff0c;即用每一个的类的质心对该簇进行描述。 其算法思想大致为&#xff1a;先从样本集中随机选取 k…

【王道操作系统】2.3.3 实现临界区进程互斥的硬件实现方法

实现临界区进程互斥的硬件实现方法 文章目录实现临界区进程互斥的硬件实现方法1.中断隐藏方法2.TestAndSet指令3.Swap指令1.中断隐藏方法 2.TestAndSet指令 执行TSL指令时&#xff0c;它的内部运转逻辑&#xff1a;假设lock现在为false&#xff0c;代表临界资源A空闲&#xff…

AssertionError: Torch not compiled with CUDA enabled解決方案

在執行pytorch代碼的時候&#xff0c;突然看到報錯 AssertionError: Torch not compiled with CUDA enabled 這說明了 1. 你pytoch确实安装了 2. 你安装的是cpu版本 作为验证&#xff0c;你可以在python编辑器输入下列代码 解决方案 首先&#xff0c;安装Nvidia toolkit su…

(深度学习快速入门)第二章:从线性神经网络入手深度学习(波士顿房价案例)

文章目录一&#xff1a;波士顿房价预测数据集说明二&#xff1a;Pytorch搭建模型&#xff08;1&#xff09;数据处理&#xff08;2&#xff09;网络结构&#xff08;3&#xff09;损失函数&#xff08;4&#xff09;优化方法&#xff08;5&#xff09;训练预测&#xff08;6&am…

pytorch应用(入门4)MLP实现MNIST手写数字分类

深层神经网络 前面一章我们简要介绍了神经网络的一些基本知识&#xff0c;同时也是示范了如何用神经网络构建一个复杂的非线性二分类器&#xff0c;更多的情况神经网络适合使用在更加复杂的情况&#xff0c;比如图像分类的问题&#xff0c;下面我们用深度学习的入门级数据集 M…

MyBatisPlus ---- 条件构造器和常用接口

MyBatisPlus ---- 条件构造器和常用接口1. wapper介绍2. QueryWrappera>例1&#xff1a;组装查询条件b>例2&#xff1a;组装排序条件c>例3&#xff1a;组装删除条件d>例4&#xff1a;条件的优先级e>例5&#xff1a;组装select子句f>例6&#xff1a;实现子查询…

dubbo源码实践-SPI扩展-自适应扩展机制

目录 1 前提必备知识 2 术语定义 3 自适应扩展机制的特点 4 扩展点实践 4.1 用户自定义自适应扩展 4.2 dubbo生成自适应扩展 4 自适应扩展类的用途 1 前提必备知识 具体的使用和原理就不说了&#xff0c;网上有人写的挺好的了。 可以参考&#xff1a; Dubbo SPI之自适…

【北京理工大学-Python 数据分析-1.1】

数据维度 维度&#xff1a;一组数据的组织形式 一维数据&#xff1a;由对等关系的有序或无序数据构成&#xff0c;采用线性组织形式。包括列表、集合和数组&#xff08;python中不常见&#xff0c;但在C和Java中比较常见&#xff09;类型。 列表&#xff1a;数据类型可以不同…

讲座笔记:Representation Learning on Networks

1 传统机器学习 传统机器学习需要进行很多的特征工程 我们希望模型自动学习特征&#xff0c;而不是用人为特征工程的方式1.1 目标 1.2 难点 graph更复杂&#xff0c;CNN和RNN很难直接应用 ——>复杂的拓扑结构&#xff08;不像CNN有网格的概念&#xff09;——>没有固定…

国家队入场,中国数字资产交易市场或将迎来新一轮“洗牌”

‍‍数据智能产业创新服务媒体——聚焦数智 改变商业数字化已经成为中国文化产业的催化剂&#xff0c;一大批文化资源在数字技术的赋能下焕发了崭新的生机。随着数字化的升级与科技进步&#xff0c;数字经济正在成为改变全球竞争格局的关键力量&#xff0c;各国家都争先出台相…

【微服务】Nacos 健康检查机制

目录 一、前言 二、注册中心的健康检查机制 三、Nacos 健康检查机制 四、临时实例健康检查机制 五、永久实例健康检查机制 六、集群模式下的健康检查机制 七、小结 &#x1f496;微服务实战 &#x1f496; Spring家族及微服务系列文章 一、前言 在前文中&#xff0c;…

使用 Helm 安装 MQTT 服务器-EMQX

EMQX ℹ️ Info: 使用 EMQX 通过 Helm3 在 Kubernetes 上部署 EMQX 4.0 集群 | EMQ emqx/deploy/charts/emqx at main-v4.4 emqx/emqx (github.com) emqx/values.yaml at main-v4.4 emqx/emqx (github.com) emqx/emqx-operator: A Kubernetes Operator for EMQ X Broker (git…

Arch Linux/Manjaro安装pycharm

首先换清华源以加快速度 &#xff08;已经换源的小伙伴可以跳过这一步&#xff09; 首先安装vim&#xff0c;用来编辑文件&#xff0c;已经安装过的可以跳过这一步。 sudo pacman -S vim 然后使用vim编辑配置文件 sudo vim /etc/pacman.d/mirrorlist 打开文件以后按inser…