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);
else
g_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);
else
g_print ("Instantiation failed.\n");
return 0;
}
2. G_DEFINE_TYPEZ宏注册
下面是用G_DEFINE_TYPE
宏来自动注册,自动注册需要遵循命名约定。
G_DEFINE_TYPE
执行以下操作:
- 声明类初始化函数
<name space>_<name>_class_init
。(你需要定义它)- 例如,如果对象名称是
MData
,则为m_data_class_init
。
- 例如,如果对象名称是
- 声明实例初始化函数
<name space>_<name>_init
。(你需要定义它)- 例如,如果对象名称是
MData
,则为m_data_init()
。
- 例如,如果对象名称是
-
- 定义一个指向父亲的静态变量
<name space>_<name>_parent_class
。 - 例如,如果对象名称是
MData
,则它是m_data_parent_class
- 定义一个指向父亲的静态变量
- 定义一个
<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);
else
g_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);
else
g_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
执行以下操作:
- 声明
<name space>_<name>_get_type ()
。(需要定义,你可以用G_DEFINE_TYPE
来定义) - 对象的
typedef
定义。- 例如,对象名称是
MData
,则typedef struct _MData MData
。你需要在G_DEFINE_TYPE之前
定义struct _MData
。
- 例如,对象名称是
<NAME SPACE>_<NAME>
宏。- 例如对象是
MData
,则宏是M_DATA
,它会扩展程一个函数,用于指针转换。 - 例如,
M_DATA(obj)
将obj
的类型转换为MData
。
- 例如对象是
<NAME SPACE>_IS_<NAME>
宏。- 例如,对象名称是
MData
,则宏是M_IS_DATA
。它将扩展为一个函数,检查参数是否是MData
类型。 - 如果参数指向
MData
及其后继,则返回true
。
- 例如,对象名称是
- 定义了类结构,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);
else
g_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);
else
g_print ("Instantiation failed.\n");
if (M_IS_DATA (data))
g_print ("data is MData instance.\n");
else
g_print ("data is not MData instance.\n");
if (G_IS_OBJECT (data))
g_print ("data is GOBject instance.\n");
else
g_print ("data is not GObjec instance.\n");
}
return 0;
}
4. 将文件拆分
将内容拆分成三个文件:
- main.c
- mdata.h
- mdata.c
头文件的内容是公开的,即对任何文件开放。
头文件包括:
- 提供类型信息(如
M_TYPE_DATA
宏等)。 - 类型转换(如
M_DATA()
,G_OBJECT()
) - 类型检查(如
M_IS_DATA()
,G_IS_OBJECT()
) - 以及公共函数的宏。
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);
else
g_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);
else
g_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 参考 - 约定