Gobject tutorial 五

参考:GObject – 2.0: Type System Concepts

Type System Concepts

The GLib Dynamic Type System

在GLib中,类型的概念比通常所理解的Ojbect type更宽泛。我们将对新类型注册到类型系统时使用的函数及数据结构进行了解,来对此进行说明。

typedef struct _GTypeInfo               GTypeInfo;
struct _GTypeInfo
{
  /* interface types, classed types, instantiated types */
  guint16                class_size;

  GBaseInitFunc          base_init;
  GBaseFinalizeFunc      base_finalize;

  /* classed types, instantiated types */
  GClassInitFunc         class_init;
  GClassFinalizeFunc     class_finalize;
  gconstpointer          class_data;

  /* instantiated types */
  guint16                instance_size;
  guint16                n_preallocs;
  GInstanceInitFunc      instance_init;

  /* value handling */
  const GTypeValueTable *value_table;
};

GType
g_type_register_static (GType            parent_type,
                        const gchar     *type_name,
                        const GTypeInfo *info,
                        GTypeFlags       flags);

GType
g_type_register_fundamental (GType                       type_id,
                             const gchar                *type_name,
                             const GTypeInfo            *info,
                             const GTypeFundamentalInfo *finfo,
                             GTypeFlags                  flags);

 上面的函数用于将新的类型(GType)注册到类型系统。通常,我们使用的是g_type_register_static。基础类型属于最顶层的类型,他们不由任何类型衍生而来,这意味着非基础类型都是由其他类型衍生而来。

不管是基础类型还是非基础类型,它们都是由GTypeInfo来定义的。这也说明了类型概念在GLiib中是要比GObject type更宽。

下面将对GTypeInfo的成员进行说明。

  • class_size:类所占空间大小,对于GOjbect来说,此值就是sizeof(GObjectClass)
  • base_init、class_init:类初始化函数,相当于C++中的构造函数。
  • base_finalize、class_finalize:类销毁函数。相当于C++中的析构函数。
  • instance_size:实例所占空间大小,对于GObject来说,此值就是sizeof(GObject).
  • n_preallocs:initialization policy, 相当于C++ type of new opeartor.
  • value_table: 复制函数,相当于C++ copy opeartors.

Copy functions

对于GLib的所有类型来说,它们的主要的共同点是,它们都能通过简单的API来进行复制。

比如说,GValue做为所有类型的一个抽象容器。它的简单函数g_value_cope能够获取到类型的value_table,并进行GVaule到GValue的内容复制。

下面举例说明:

static void test_int (void)
{
  GValue a_value = G_VALUE_INIT;
  GValue b_value = G_VALUE_INIT;
  guint64 a, b;

  a = 0xdeadbeef;

  g_value_init (&a_value, G_TYPE_UINT64);
  g_value_set_uint64 (&a_value, a);

  g_value_init (&b_value, G_TYPE_UINT64);
  g_value_copy (&a_value, &b_value);

  b = g_value_get_uint64 (&b_value);

  if (a == b) {
    g_print ("Yay !! 10 lines of code to copy around a uint64.\n");
  } else {
    g_print ("Are you sure this is not a Z80 ?\n");
  }
}

static void test_object (void)
{
  GObject *obj;
  GValue obj_vala = G_VALUE_INIT;
  GValue obj_valb = G_VALUE_INIT;
  obj = g_object_new (VIEWER_TYPE_FILE, NULL);

  g_value_init (&obj_vala, VIEWER_TYPE_FILE);
  g_value_set_object (&obj_vala, obj);

  g_value_init (&obj_valb, G_TYPE_OBJECT);

  /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference.
   * This function thus calls g_object_ref.
   * It is interesting to note that the assignment works here because
   * VIEWER_TYPE_FILE is a G_TYPE_OBJECT.
   */
  g_value_copy (&obj_vala, &obj_valb);

  g_object_unref (G_OBJECT (obj));
  g_object_unref (G_OBJECT (obj));
}

Conventions

下面我们介绍几个常用宏及其作用:

  • PREFIX_TYPE_OBJECT:返回相关对象的GType。例如,GTK_TYPE_WIDGET。
  • PREFIX_OBJECT(obj):将obj转换为PrefixObject.例如,GTK_WIDGET(widget)。
  • PREFIX_OBJECT_CLASS(klass):将klass转换为PrefixObjectClass。例如,GTK_WIDGET_CLASS。
  • PREFIX_IS_OBJECT(obj):判断obj是否为OBJECT类型,并返回一个布尔值。例如,GTK_IS_WIDGE。
  • PREFIX_IS_OBJECT_CLASS(klass):判断klass是否是OBJECT类型的类。并返回一个布尔值。例如,GTK_IS_WIDGE_CLASS。
  • PREFIX_OBJECT_GET_CLASS(obj):返回obj实例所对应 的类指针。

Non-instantiatable non-classed fundamental types

很多类型既不能被类型系统实例化也没有所属的类。它们中大部分都是基础类型,比如说gchar.它们由GLib注册。

那,如果我们要生成一个这样的类型,咋办呢?我们先来看看glib中gchar是怎么注册的。

/* --- type initialization --- */
void
_g_value_types_init (void)
{
  GTypeInfo info = {
    0,				/* class_size */
    NULL,			/* base_init */
    NULL,			/* base_destroy */
    NULL,			/* class_init */
    NULL,			/* class_destroy */
    NULL,			/* class_data */
    0,				/* instance_size */
    0,				/* n_preallocs */
    NULL,			/* instance_init */
    NULL,			/* value_table */
  };
  const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };
  GType type G_GNUC_UNUSED  /* when compiling with G_DISABLE_ASSERT */;
  
  /* G_TYPE_CHAR / G_TYPE_UCHAR
   */
  {
    static const GTypeValueTable value_table = {
      value_init_long0,		/* value_init */
      NULL,			/* value_free */
      value_copy_long0,		/* value_copy */
      NULL,			/* value_peek_pointer */
      "i",			/* collect_format */
      value_collect_int,	/* collect_value */
      "p",			/* lcopy_format */
      value_lcopy_char,		/* lcopy_value */
    };
    info.value_table = &value_table;
    type = g_type_register_fundamental (G_TYPE_CHAR, g_intern_static_string ("gchar"), &info, &finfo, 0);
    g_assert (type == G_TYPE_CHAR);
    type = g_type_register_fundamental (G_TYPE_UCHAR, g_intern_static_string ("guchar"), &info, &finfo, 0);
    g_assert (type == G_TYPE_UCHAR);
  }
...
}

问题来了,不能实例化的类型有啥用?通常,它们需要与GValue一起使用。GValue在初始化时,通常都需要整数或者字符串。这点可以从GValue的定义看出来。

struct _GValue
{
  /*< private >*/
  GType		g_type;

  /* public for GTypeValueTable methods */
  union {
    gint	v_int;
    guint	v_uint;
    glong	v_long;
    gulong	v_ulong;
    gint64      v_int64;
    guint64     v_uint64;
    gfloat	v_float;
    gdouble	v_double;
    gpointer	v_pointer;
  } data[2];
};

Instantiatable classed types: objects

通过类进行注册并能被实例化的类型,看起来最像是一个对象。尽管GObject是其中最为人所知的,然而,其他类似的,能用作继承结构基类的对象,也已经在Glib库外被开发出来。这里我们所说的可以作为基类的意思是,其他类能继承自此类,并不是说,我们以下面这种方式生成的类与GObject的地位完全相同。GObject的功能更宽,我们现在所说的这些对象都继承自基类。这种类型也是GLib的使用者大部分情况下都会使用的。

下面举例说明如何注册此类的对象类型。

typedef struct {
  GObject parent_instance;

  /* instance members */
  char *filename;
} ViewerFile;

typedef struct {
  GObjectClass parent_class;

  /* class members */

  /* the first is public, pure and virtual */
  void (*open)  (ViewerFile  *self,
                 GError     **error);

  /* the second is public and virtual */
  void (*close) (ViewerFile  *self,
                 GError     **error);
} ViewerFileClass;

#define VIEWER_TYPE_FILE (viewer_file_get_type ())

GType
viewer_file_get_type (void)
{
  static GType type = 0;
  if (type == 0) {
    const GTypeInfo info = {
      .class_size = sizeof (ViewerFileClass),
      .base_init = NULL,
      .base_finalize = NULL,
      .class_init = (GClassInitFunc) viewer_file_class_init,
      .class_finalize = NULL,
      .class_data = NULL,
      .instance_size = sizeof (ViewerFile),
      .n_preallocs = 0,
      .instance_init = (GInstanceInitFunc) viewer_file_init,
    };
    type = g_type_register_static (G_TYPE_OBJECT,
                                   "ViewerFile",
                                   &info, 0);
  }
  return type;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值