五、GObject对接口的模拟
1 USB接口
1.1 USB接口头文件
/* file name : 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))
/* 用于MyIUsb接口的实例结构体中取出类结构体指针,然后利用该指针访问接口对应方法 */
#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);
#endif
原文博客作者写道MyIUsb 接口的实例结构体,它只是个名字,并没有具体实现。这是因为,在 Java 那样的语言里谈到“接口”,那么则意味着它是无法实例化的。 MyIUsbIterface是MyIUsb接口的类结构体,它继承自GTypeInterface类结构体。 我的理解是:接口类的实例结构体只是名字,没有具体实现。因为接口只有特定的一个。接口的类结构体继承自GTypeInterface类结构体。我们在前几章可实例化为对象的类结构体继承GObjectClass。
宏总结
#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 对象对应的类结构体地址
1.2 接口函数实现
#include"my-iusb.h"
/* 该宏展开会生成my_iusb_default_init函数 */
G_DEFINE_INTERFACE(MyIUsb, my_iusb, G_TYPE_INVALID);
static void
my_iusb_default_init(MyIUsbInterface *iface)
{
}
gchar *
my_iusb_read(MyIUsb *self)
{
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_return_if_fail(MY_IS_IUSB(self));
MY_IUSB_GET_INTERFACE (self)->write(self, str);
}
分析 其中G_DEFINE_INTERFACE(MyIUsb, my_iusb, G_TYPE_INVALID); 宏展开会生成my_iusb_default_init()函数的声明。该初始化函数可以放置接口的一些初始化代码。如果没有这方面的需求,就让它表现为一个空函数即可。其次,该宏的作用和G_DEFINE_TYPE类似。
2 接口的实现-制造U盘
2.1 U盘类头文件
#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_INSTANCE_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
2.1 U盘函数实现
#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)
{
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);
}
static void
my_udisk_init (MyUdisk *self)
{
self->data = g_string_new (NULL);
}
static void
my_udisk_class_init (MyUdiskClass *self)
{
}
static void
my_iusb_interface_init (MyIUsbInterface *iface)
{
iface->read = my_udisk_read;
iface->write = my_udisk_write;
}
分析
- my_iusb_interface_init函数声明必须放在G_DEFINE_TYPE_WITH_CODE宏之前,因为这个宏展开代码中要使用这个函数
- G_DEFINE_TYPE_WITH_CODE 是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 所规定的接口。
3 主函数
#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;
}