初探GObject中的interface'接口'问题

本文内容完全参考自http://garfileo.is-programmer.com/posts/25338.html,感谢作者的无私奉献。


说道接口,我这种不懂OO的人,顶多也就理解到虚函数了,对于纯虚的理解甚至都不到位。从我目前的观点来看,这个接口,就是提供了一个类,然后一堆的函数指针。用到这个接口的类呢,就有了这些函数指针,然后具体的类去填充这些指针就好了。共性~抽象~。

好吧,这里依然有很多的不知道具体细节的宏定义,不过当然是可以查的了,只是目前还没有查过罢了。

这次的文件分了好几个:

my-iusb.h

#ifndef MY_IUSB_H
#define MY_IUSB_H

#include<glib-object.h>

#define MY_TYPE_IUSB (my_iusb_get_type())
#define MY_IUSB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), MY_TYPE_IUSB, MyIUsb))
#define MY_IS_IUSB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), MY_TYPE_IUSB))
#define MY_IUSB_GET_INTERFACE(obj) (\
	G_TYPE_INSTANCE_GET_INTERFACE((obj), MY_TYPE_IUSB, MyIUsbInterface))

typedef struct _MyIUsb MyIUsb;
typedef struct _MyIUsbInterface MyIUsbInterface;

struct _MyIUsbInterface {
	GTypeInterface parent_interface;

	gchar * (*read) (MyIUsb *self);
	void (*write)(MyIUsb *self, const gchar *str);
	// 这组指针就是接口协议
};

GType my_iusb_get_type(void);

// 声明接口
gchar *my_iusb_read(MyIUsb *self);
void my_iusb_write(MyIUsb *self, const gchar *str);

// 这是一个usb接口
// 这个接口既可以read又可以write,read只能返回字符串,write只能接受字符串
#endif

my-iusb.c

#include"my-udisk.h"

static void my_iusb_interface_init(MyIUsbInterface *iface);

G_DEFINE_TYPE_WITH_CODE(MyUdisk, my_udisk, G_TYPE_OBJECT,
		G_IMPLEMENT_INTERFACE(MY_TYPE_IUSB, my_iusb_interface_init));

static gchar *my_udisk_read(MyIUsb *iusb)
{
	g_printf("%s %i.\n",__func__, __LINE__);
	MyUdisk *udisk = MY_UDISK(iusb);
	return udisk->data->str;
}

static void my_udisk_write(MyIUsb *iusb, const gchar *str)
{
	MyUdisk *udisk = MY_UDISK(iusb);
	g_string_assign(udisk->data, str);
	g_printf("%s %i.\n",__func__, __LINE__);
}

static void my_udisk_init(MyUdisk *self)
{
	self->data = g_string_new(NULL);
	g_printf("%s %i.\n",__func__, __LINE__);
}

static void my_udisk_class_init(MyUdiskClass *self)
{
	g_printf("%s %i.\n",__func__, __LINE__);
}

static void my_iusb_interface_init(MyIUsbInterface *iface)
{
	iface->read = my_udisk_read;
	iface->write = my_udisk_write;
	g_printf("%s %i.\n",__func__, __LINE__);
}

上面的文件构成了接口,下面的文件是具体的使用者

my-udisk.h

#ifndef MY_UDISK_H
#define MY_UDISK_H

#include "my-iusb.h"

#define MY_TYPE_UDISK (my_udisk_get_type())
#define MY_UDISK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), MY_TYPE_UDISK, MyUdisk))
#define MY_IS_UDISK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), MY_TYPE_UDISK))
#define MY_UDISK_CLASS(klass) \
	(G_TYPE_CHECK_CLASS_CAST((klass), MY_TYPE_UDISK, MyUdiskClass))
#define MY_IS_UDISK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),MY_TYPE_UDISK))
#define MY_UDISK_GET_CLASS(obj) \
	(G_TYPE_INSTANCE_GET_CLASS((obj), MY_TYPE_UDISK, MyUdiskClass))

typedef struct _MyUdisk MyUdisk;
typedef struct _MyUdiskClass MyUdiskClass;

struct _MyUdisk {
	GObject parent;
	GString *data;
};
struct _MyUdiskClass {
	GObjectClass parent_class;
};

GType my_udisk_get_type(void);

#endif

u-disk.c

#include "my-iusb.h"

G_DEFINE_INTERFACE (MyIUsb, my_iusb, G_TYPE_INVALID);

static void my_iusb_default_init(MyIUsbInterface *iface)
{ // 这是函数是宏G_DEFINE_INTERFACE展开后的一个函数
}

gchar *my_iusb_read(MyIUsb *self)
{
	g_printf("%s %i.\n",__func__, __LINE__);
	g_return_if_fail(MY_IS_IUSB(self));
	MY_IUSB_GET_INTERFACE(self)->read(self);
}

void my_iusb_write(MyIUsb *self, const gchar *str)
{
	g_printf("%s %i.\n",__func__, __LINE__);
	g_return_if_fail(MY_IS_IUSB(self));
	MY_IUSB_GET_INTERFACE(self)->write(self, str);
}

上述代码中,有几处需要留意的地方:

  • my_iusb_interface_init 函数声明必须要放在 G_DEFINE_TYPE_WITH_CODE 宏之前,因为这个宏的展开代码中需要使用这个函数;
  • G_DEFINE_TYPE_WITH_CODE 是文档 [2-5] 中出现过的 G_DEFINE_TYPE 宏的“扩展版本”,在本例中可以向 my_udisk_get_type 函数(即 MY_TYPE_UDISK 宏展开的那个函数)中插入 C 代码。在本例中,这个宏所插入的 C 代码是“G_IMPLEMENT_INTERFACE(MY_TYPE_IUSB,my_iusb_interface_init)”,其中 G_IMPLEMENT_INTERFACE 宏的作用是将接口添加到  MyUdisk 类中;
  • my_iusb_interface_init 函数的作用是表明 MyUdisk 类实现了 MyIUsb 所规定的接口。

接下来是main.c

#include "my-udisk.h"

int main(void)
{
	g_type_init();

	MyUdisk *udisk = g_object_new(MY_TYPE_UDISK, NULL);

	my_iusb_write(MY_IUSB(udisk), "I am u-disk!");
	gchar *data = my_iusb_read(MY_IUSB(udisk));

	g_printf("%s\n\n",data);

	g_printf("Is udisk a MyIUsb object?\n");

	if(MY_IS_IUSB(udisk)) {
		g_printf("Yes!\n");
	} else {
		g_printf("No!\n");
	}

	g_printf("\nIs udisk a MyUdisk object?\n");

	if (MY_IS_UDISK(udisk)) {
		g_printf("Yes!\n");
	} else {
		g_printf("No!\n");
	}

	return 0;
}

最后放上MAKEFILE

all:
	gcc -g `pkg-config --cflags --libs gobject-2.0` my-iusb.c my-udisk.c main.c -o test

输入结果如下:

my_udisk_class_init 30.
my_iusb_interface_init 37.
my_udisk_init 25.
my_iusb_write 18.
my_udisk_write 19.
my_iusb_read 11.
my_udisk_read 10.
I am u-disk!

Is udisk a MyIUsb object?
Yes!

Is udisk a MyUdisk object?
Yes!




下面我要粘贴的是原作者写的: 经常要用到并且需要自己定义的宏

对于 GObject 的子类化,那么在声明类的时候,在头文件中直接插入类似下面的一组宏定义:

#define P_TYPE_T (p_t_get_type ())
#define P_T(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), P_TYPE_T, PT))
#define P_IS_T(obj) G_TYPE_CHECK_INSTANCE_TYPE ((obj), P_TYPE_T))
#define P_T_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), P_TYPE_T, PTClass))
#define P_IS_T_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), P_TYPE_T))
#define P_T_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), P_TYPE_T, PTClass))

这些宏的用法总结如下:

  • P_TYPE_T:仅在使用 g_object_new 进行对象实例化的时候使用一次,用于向 GObject 库的类型系统注册 PT 类;
  • P_T (obj):用于将 obj 对象的类型强制转换为 P_T 类的实例结构体类型;
  • P_IS_T (obj):用于判断 obj 对象的类型是否为 P_T 类的实例结构体类型;
  • P_T_CLASS(klass):用于将 klass 类结构体的类型强制转换为 P_T 类的类结构体类型;
  • P_IS_T_CLASS(klass):用于判断 klass 类结构体的类型是否为 P_T 类的类结构体类型;
  • P_T_GET_CLASS(obj):获取 obj 对象对应的类结构体类型。

对于 GTypeInterface 的子类化,在声明类的时候,在头文件中直接插入类似下面的一组宏定义:


#define P_TYPE_IT (p_t_get_type ())
#define P_IT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), P_TYPE_IT, PIt))
#define P_IS_IT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), P_TYPE_IT))
#define P_IT_GET_INTERFACE(obj) \
        (G_TYPE_INSTANCE_GET_INTERFACE ((obj), P_TYPE_IT, PItInterface))

  • P_TYPE_IT:仅在接口实现时使用一次,用于向 GObject 库的类型系统注册 PIT 接口;
  • P_IT (obj):用于将 obj 对象的类型强制转换为 P_IT 接口的实例结构体类型;
  • P_IS_IT (obj):用于判断 obj 对象的类型是否为 P_IT 接口的实例结构体类型;
  • P_IT_GET_INTERFACE(obj):获取 obj 对象对应的 P_IT 接口的类结构体类型。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值