定义 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,