> 文章列表 > 1. gobject 类型系统和注册过程

1. gobject 类型系统和注册过程

1. gobject 类型系统和注册过程

1. 手动注册:

#include <glib-object.h>#define M_TYPE_DATA (m_data_get_type())typedef struct _MData MData;
struct _MData {GObject parent;double value;
};typedef struct _MDataClass MDataClass;
struct _MDataClass {GObjectClass parent_class;
};static void
m_data_class_init (MDataClass *class)
{
}static void
m_data_init (MData *d)
{
}GType
m_data_get_type (void)
{static GType type = 0;GTypeInfo info;if (type == 0) {info.class_size = sizeof (MDataClass);info.base_init = NULL;info.base_finalize = NULL;info.class_init = (GClassInitFunc)  m_data_class_init;info.class_finalize = NULL;info.class_data = NULL;info.instance_size = sizeof (MData);info.n_preallocs = 0;info.instance_init = (GInstanceInitFunc)  m_data_init;info.value_table = NULL;type = g_type_register_static (G_TYPE_OBJECT, "MData", &info, 0);}return type;
}int
main (int argc, char **argv)
{GType dtype;MData *d;dtype = m_data_get_type();if (dtype)g_print ("Registration was a success. The type is %lx.\\n", dtype);elseg_print ("Registration failed.\\n");d = g_object_new (M_TYPE_DATA, NULL);if (d)g_print ("Instantiation was a success. The instance address is %p.\\n", d);elseg_print ("Instantiation failed.\\n");return 0;
}

2. G_DEFINE_TYPEZ宏注册

下面是用G_DEFINE_TYPE宏来自动注册,自动注册需要遵循命名约定。

G_DEFINE_TYPE执行以下操作:

  1. 声明类初始化函数 <name space>_<name>_class_init。(你需要定义它)
    • 例如,如果对象名称是MData,则为m_data_class_init
  2. 声明实例初始化函数 <name space>_<name>_init。(你需要定义它)
    • 例如,如果对象名称是MData,则为m_data_init()
    • 定义一个指向父亲的静态变量 <name space>_<name>_parent_class
    • 例如,如果对象名称是MData,则它是m_data_parent_class
  3. 定义一个<name space>_<name>_get_type ()函数
    • 例如,如果对象名称是MData,则它是m_data_get_type
    • 注册是在这个函数中完成的,就像上面手动注册的一样。
#include <glib-object.h>#define M_TYPE_DATA (m_data_get_type())
typedef struct _MData MData;
struct _MData {GObject parent;double value;
};typedef struct _MDataClass MDataClass;
struct _MDataClass {GObjectClass parent_class;
};G_DEFINE_TYPE (MData, m_data, G_TYPE_OBJECT)static void
m_data_class_init (MDataClass *class)
{
}static void
m_data_init (MData *d)
{
}int
main (int argc, char **argv)
{GType dtype;MData *d;dtype = m_data_get_type();if (dtype)g_print ("Registration was a success. The type is %lx.\\n", dtype);elseg_print ("Registration failed.\\n");d = g_object_new (M_TYPE_DATA, NULL);if (d)g_print ("Instantiation was a success. The instance address is %p.\\n", d);elseg_print ("Instantiation failed.\\n");return 0;
}

3. G_DECLARE_FINAL_TYPE和G_DECLARE_DERIVABLE_TYPE

如果要定义可派生类型对象,请改用G_DECLARE_DERIVABLE_TYPE。但是,在大多数情况下,您可能会编写最终类型对象。


首先,你需要手动定义宏

#define M_TYPE_DATA  (m_data_get_type ())

这应该在G_DECLARE_FINAL_TYPE之前完成。

然后,
G_DECLARE_FINAL_TYPE执行以下操作:

  1. 声明<name space>_<name>_get_type ()。(需要定义,你可以用G_DEFINE_TYPE来定义)
  2. 对象的typedef定义。
    • 例如,对象名称是MData,则typedef struct _MData MData。你需要在G_DEFINE_TYPE之前定义struct _MData
  3. <NAME SPACE>_<NAME>宏。
    • 例如对象是MData,则宏是M_DATA,它会扩展程一个函数,用于指针转换。
    • 例如,M_DATA(obj)obj的类型转换为MData
  4. <NAME SPACE>_IS_<NAME>宏。
    • 例如,对象名称是MData,则宏是M_IS_DATA。它将扩展为一个函数,检查参数是否是MData类型。
    • 如果参数指向MData及其后继,则返回true
  5. 定义了类结构,final类不需要有自己的类结构成员。(但是仍然要定义类结构初始化函数

#include <glib-object.h>#define M_TYPE_DATA (m_data_get_type())G_DECLARE_FINAL_TYPE (MData, m_data, M, DATA, GObject)struct _MData {GObject parent;double value;
};G_DEFINE_TYPE (MData, m_data, G_TYPE_OBJECT)static void
m_data_class_init (MDataClass *class)
{ }static void
m_data_init (MData *d)
{ }int
main (int argc, char **argv)
{{GType type = m_data_get_type();if (type != 0)g_print ("Registration was a success. The type is %lx.\\n", type);elseg_print ("Registration failed.\\n");}{MData *data = g_object_new (M_TYPE_DATA, NULL);if (data != NULL)g_print ("Instantiation was a success. The instance address is %p.\\n", data);elseg_print ("Instantiation failed.\\n");if (M_IS_DATA (data))g_print ("data is MData instance.\\n");elseg_print ("data is not MData instance.\\n");if (G_IS_OBJECT (data))g_print ("data is GOBject instance.\\n");elseg_print ("data is not GObjec instance.\\n");}return 0;
}

4. 将文件拆分

将内容拆分成三个文件:

  1. main.c
  2. mdata.h
  3. mdata.c

头文件的内容是公开的,即对任何文件开放。
头文件包括:

  1. 提供类型信息(如M_TYPE_DATA宏等)。
  2. 类型转换(如M_DATA()G_OBJECT()
  3. 类型检查(如M_IS_DATA()G_IS_OBJECT()
  4. 以及公共函数的宏。

mdata.h:

#ifndef MDATA_H
#define MDATA_H#include <glib-object.h>#define M_TYPE_DATA     (m_data_get_type())
G_DECLARE_FINAL_TYPE (MData, m_data, M, DATA, GObject)gboolean
m_data_get_value (MData *data, double *value);void
m_data_set_value (MData *data, double value);MData *
m_data_new (double value);#endif // MDATA_H

mdata.c:

#include "mdata.h"
#include <stdbool.h>struct _MData {GObject base;double value;
};G_DEFINE_TYPE (MData, m_data, G_TYPE_OBJECT)static void
m_data_class_init (MDataClass *d)
{ }static void
m_data_init (MData *d)
{ }gboolean
m_data_get_value (MData *data, double *value)
{g_return_val_if_fail (M_IS_DATA (data), false);*value = data->value;return true;
}void
m_data_set_value (MData *data, double value)
{g_return_if_fail (M_IS_DATA (data));data->value = value;
}MData *
m_data_new (double value)
{MData *data = g_object_new (M_TYPE_DATA, NULL);data->value = value;return data;
}

main.c:

#include "mdata.h"#include <glib-object.h>int
main (void)
{MData *data = m_data_new (10.0);double value;if (m_data_get_value (data, &value))g_print ("value : %lf\\n", value);elseg_print ("m_data_get_value() failed.\\n");m_data_set_value (data, -20.0);g_print ("Now, set data with %lf.\\n", -20.0);if (m_data_get_value (data, &value))g_print ("value : %lf.\\n", value);elseg_print ("m_data_get_value failed.\\n");return 0;
}

看下面一个例子:

MData *
m_data_add (MData *self, MData *other)
{g_return_val_if_fail (M_IS_DATA (self), NULL);g_return_val_if_fail (M_IS_DATA (other), NULL);double value;if (!m_data_get_value (other, &value))return NULL;return m_data_new (self->value + value);
}

函数对外是公开的,就像面向对象中的方法,但是不能用other->value来获取值,而是m_double_get_value

通常,对象的结构不对其他对象开放。
当一个对象A访问对象B时,A必须使用B提供的公共函数。

参考资料

有关更多公约惯例的信息,参阅GObject API 参考 - 约定