定义 GObject 的子类
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 的子类
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
实现 GObject 的子类
实现子类的过程其实就是实现 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,
转载于:https://blog.51cto.com/eminzhang/1587567