instance 结构:包含于类的实例相关的域,相当于 C++ 中的非静态公共成员。
class 结构:包含的域相当于 C++ 中的静态公共成员。
私有成员在哪里定义?
与 C++ 不同,私有成员不是直接定义在类的声明中的(你甚至找不到一个到私有数据的指针)。GObject 的私有数据是在 class 结构初始化的时候,通过调用 g_typ_class_add_private 函数来指定的,这个函数只是指定私有数据的大小,类型系统在分配 instance 的时候会预留指定大小的空间供类实现作为私有数据使用。
例子代码及注释(代码来自"Foundations of Gtk+ Development"一书第十一章)
G_BEGIN_DECLS _MyIPAddress MyIPAddress _MyIPAddressClass MyIPAddressClass _MyIPAddress GtkEntry entry _MyIPAddressClass GtkEntryClass parent_class ip_changed MyIPAddress ipaddress GType my_ip_address_get_type G_GNUC_CONST GtkWidget my_ip_address_new gchar my_ip_address_get_address MyIPAddress ipaddress my_ip_address_set_address MyIPAddress ipaddress, gint address G_END_DECLS
GObject 类型在使用之前必须在 GType 类型系统中注册,类型的注册工作在 xxx_get_type 函数中完成,例如上面例子中的 my_ip_address_get_type 函数。正如上面的例子所示,这个函数会在 new 一个该类的对象时被调用,如果该类型还没有被注册,则在第一次 new 这个类型的对象时注册。
GType my_ip_address_get_type GType entry_type entry_type GTypeInfo entry_info MyIPAddressClass, , , GClassInitFunc my_ip_address_class_init, , , MyIPAddress, , GInstanceInitFunc my_ip_address_init, entry_type g_type_register_static GTK_TYPE_ENTRY, , entry_info, entry_type
不过上面的代码不是线程安全的。在 gtype.h 中(只要包含了 glib-object.h 就会自动包含这个文件)定义了一个方便的宏,它是线程安全的。这个宏是 #define G_DEFINE_TYPE(TN, t_n, T_P),不过它的实现只使用了 g_type_register_static_simple 函数(见下面),不够灵活,如果需要自己完整定义 GTypeInfo 结构的话,可以参考这个宏的实现。
通过 GType API 在类型系统中注册一个类:
GType g_type_register_static GType parent_type, gchar type_name, GTypeInfo info, GTypeFlags flags GType g_type_register_static_simple GType parent_type, gchar type_name, guint class_size, GClassInitFunc class_init, guint instance_size, GInstanceInitFunc instance_init, GTypeFlags flags
类型的大部分信息保存在 GTypeInfo 数据结构中,
_GTypeInfo guint16 class_size GBaseInitFunc base_init GBaseFinalizeFunc base_finalize GClassInitFunc class_init GClassFinalizeFunc class_finalize gconstpointer class_data guint16 instance_size guint16 n_preallocs GInstanceInitFunc instance_init GTypeValueTable value_table
实现子类的过程其实就是实现 GTypeInfo 结构中各个函数指针以及该类的接口函数的过程,因此首先需要了解 GTypeInfo 各个域的作用,在GObject 类的实现以及对象属性中还会进一步介绍这些函数被调用的顺序。
GObject 子类的 GTypeInfo 各个函数的作用
base_init:对 class 结构中继承过来的域进行设置。由于继承的域都是直接拷贝父类的 class 结构的,所以有些域可能需要进行“深拷贝”,这些操作就在这个函数完成。需要注意的是,假如 B 继承 A,是将 B 的 class 结构指针传给 A 所定义的 base_init 函数,因为只有 A 自身知道如何恰当设置相关的域。
base_finalize:与 base_init 相反。
class_init:这个函数对每个类只会调用一次,class 结构对每个类来说也只有一个副本。这个函数有两个作用,一是对 class 结构中的域进行初始化,二是注册该类的属性、信号、私有数据。
class_finalize:与 class_init 相反。
instance_init:初始化实例对象。
例子代码及注释
my_ip_address_class_init MyIPAddressClass klass GObjectClass gobject_class G_OBJECT_CLASS klass gobject_classset_property my_ip_address_set_property gobject_classget_property my_ip_address_get_property g_type_class_add_private klass, MyIPAddressPrivate my_ip_address_signalsCHANGED_SIGNAL g_signal_new , G_TYPE_FROM_CLASS klass, G_SIGNAL_RUN_FIRST G_SIGNAL_ACTION, G_STRUCT_OFFSET MyIPAddressClass, ip_changed, , , g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, g_object_class_install_property gobject_class, PROP_IP1, g_param_spec_int , , , , , , G_PARAM_READWRITE g_object_class_install_property gobject_class, PROP_IP2, g_param_spec_int , , , , , , G_PARAM_READWRITE g_object_class_install_property gobject_class, PROP_IP3, g_param_spec_int , , , , , , G_PARAM_READWRITE g_object_class_install_property gobject_class, PROP_IP4, g_param_spec_int , , , , , , G_PARAM_READWRITE my_ip_address_init MyIPAddress ipaddress MyIPAddressPrivate priv MY_IP_ADDRESS_GET_PRIVATE ipaddress PangoFontDescription fd guint i i i i privaddressi fd pango_font_description_from_string gtk_widget_modify_font GTK_WIDGET ipaddress, fd my_ip_address_render ipaddress pango_font_description_free fd g_signal_connect G_OBJECT ipaddress, , G_CALLBACK my_ip_address_key_pressed, g_signal_connect G_OBJECT ipaddress, , G_CALLBACK my_ip_address_move_cursor,