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);
	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执行以下操作:

  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);
	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执行以下操作:

  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);
		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. 将文件拆分

将内容拆分成三个文件:

  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);
	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 参考 - 约定

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

barbyQAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值