接口及.h文件
在面向对象语言里,接口是一个重要的概念。接口声明了一套函数(对应相应的行为要求),但是并不实现它们,而是让继承这个接口的类型来实现它。这样继承这个接口的类型就将具有相似的行为表现(输入相同类型的参数,返回相同类型的结果)。
Interface iMediaType{
Format getFormat();
}
在gobject中,同样也实现了接口的机制,它的定义稍显复杂一些, 它的头文件如下:
#ifndef VCAME_IMEDIATYPE_H
#define VCAME_IMEDIATYPE_H
#include <glib-object.h>
#define VCAME_IMEDIATYPE (vcam_imediatype_get_type ())
G_DECLARE_INTERFACE(VcamIMediaType, vcam_imediatype, VCAM, IMEDIATYPE, GObject)
struct _VcamIMediaTypeInterface
{
GTypeInterface parent_iface;
void (*get) (VcamIMediaType *self, Format * formatprt);
};
void vcam_imediatype_get(VcamIMediaType* self, Format* formatprt);
#endif
如果参考普通类型的定义,这里无非是做了一些修改:
G_DECLARE_INTERFACE 替代G_DECLARE_DERIVABLE_TYPE或G_DECLARE_FINAL_TYPE, 有了这个宏,可以:
a. 省略typedef struct _VcamIMediaType VcamIMediaType 和 typedef struct _VcamIMediaTypeInterface VcamIMediaTypeInterface的定义。
b. 省略 gtype vcam_imediatype_get_type (void)的定义。
c. 自动增加其它一些宏定义: VCAM_IMEDIATYPE(object), VCAM_IS_DEDIATYPE(obj) ...省略了类型的定义, 可以看到没有 struct _VcamIMediaType, 因为作为接口是不应该有实现的。
用_VcamIMediaTypeInterface 替代 _VcamIMediaTypeClass, 并且第一个元素必须为GTypeInterface
从头文件来说, 接口的定义还是非常类似于普通对象的定义,所以虽繁麻烦了写,但还算容易写。 接口的一个作用就是定义一套标准行为(方法), 这个工作需要在 _VcamIMediaTypeInterface来完成,在.h文件中需要在类型的接口中声明所有的方法,这里我们声明了一个方法void (get) (VcamIMediaType self, Format * formatprt);, 同时提供了一个满足Gobject风格的帮助方法的定义void vcam_imediatype_get(VcamIMediaType self, Format formatprt)**。
接口的.c文件
在面向对象语言中,一般定义了接口的形式(如.h文件内容),就不需要在做额外的工作。但是在Gobject,为了让接口工作我们还需要完成.c文件:
#include "IMediaType.h"
G_DEFINE_INTERFACE(VcamIMediaType, vcam_imediatype, G_TYPE_OBJECT)
static void
vcam_imediatype_default_init(VcamIMediaTypeInterface* iface)
{
/* add properties and signals to the interface here */
}
void vcam_imediatype_get(VcamIMediaType* self, Format* formatprt) {
VcamIMediaTypeInterface* iface;
g_return_if_fail(VCAM_IS_IMEDIATYPE(self));
iface = VCAM_IMEDIATYPE_GET_IFACE(self);
g_return_if_fail(iface->get != NULL);
iface->get(self, formatprt);
}
接口的.c文件与普通对象的.c文件也是很相似的:
G_DEFINE_INTERFACE 替代了 G_DEFINE_TYPE
由于没有类型的结构体,所以也省略了类型的初始化函数。
仍旧需要定义 类的初始化函数, G_DEFINE_INTERFACE有它的声明, 在类的初始化函数里可以添加属性和信号,如果没有需要,可以省略为空。
提供帮助函数的实现 vcam_imediatype_get。
继承接口
一个具体的类型继承接口,就是要实现接口声明的所有函数,从而具有接口表述的行为特征:
#include "VedioMedia.h"
#include "IMediaType.h"
G_DEFINE_TYPE_WITH_CODE(VcamVedioMedia, vcam_vediomedia, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(VCAME_IMEDIATYPE,
vcam_media_interface_init))
#define VCAM_SOURCE_GET_PRIVATE(obj) (\
G_TYPE_INSTANCE_GET_PRIVATE((obj), VCAM_TYPE_VEDIOMEDIA, VcamVedioMediaPriv))
enum _VCAM_MEDIA_PROPERTY {
VCAM_MEDIA_PROPERTY0,
VCAM_MEDIA_FORMAT
};
struct _VcamVedioMediaPriv {
GObject * format;
};
static void
vcam_vediomedia_init(VcamVedioMedia* d) {
}
static void
vcam_vediomedia_class_init(VcamVedioMediaClass * kclass) {
//注册私有属性
g_type_class_add_private(kclass, sizeof(VcamVedioMediaPriv));
/* override base object methods */
GObjectClass* base_class = G_OBJECT_CLASS(kclass);
base_class->set_property = vcam_vediomedia_set_property;
base_class->get_property = vcam_vediomedia_get_property;
/* install properties */
g_object_class_install_property(base_class, VCAM_MEDIA_FORMAT,
g_param_spec_object("format", "vedio format", "desscribe the vedio format", VCAM_TYPE_VEDIOMEDIA,G_PARAM_READWRITE));
}
static void
vcam_vediomedia_set_property(GObject* object, guint property_id,
const GValue* value, GParamSpec* pspec)
{
VcamVedioMedia* self = VCAM_VEDIOMEDIA(object);
VcamVedioMediaPriv * priv = VCAM_VEDIOMEDIA_GET_PRIVATE(self);
switch (property_id) {
case VCAM_MEDIA_FORMAT:
priv->format = g_value_get_object(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
vcam_vediomedia_get_property(GObject* object, guint property_id,
GValue* value, GParamSpec* pspec)
{
VcamVedioMedia* self = VCAM_VEDIOMEDIA(object);
VcamVedioMediaPriv* priv = VCAM_VEDIOMEDIA_GET_PRIVATE(self);
switch (property_id) {
case VCAM_MEDIA_FORMAT:
g_value_set_object(value, priv->format);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void
vcam_media_interface_init(VcamIMediaTypeInterface * iface){
iface->get = vediomedia_get;
}
void vediomedia_get(VcamIMediaType* self, Format* formatprt) {
//implement here
}
如上面的代码,继承一个接口可以按下面的顺序来做:
- 正常的创建和声明一个Gobject子类型,不需要修改头文件
- 在.c文件中,使用 G_DEFINE_TYPE_WITH_CODE 替换G_DEFINE_TYPE,如下:
G_DEFINE_TYPE_WITH_CODE(VcamVedioMedia, vcam_vediomedia, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(VCAME_IMEDIATYPE,
vcam_media_interface_init))
在上面的宏定义中,增加一个参数G_IMPLEMENT_INTERFACE宏参数,这个红参数正式用来声明接口的,第一个参数为接口类型,第二个参数为接口的绑定函数。所以我们需要在增加一个绑定函数 vcam_media_interface_init:
tatic void
vcam_media_interface_init(VcamIMediaTypeInterface * iface){
iface->get = vediomedia_get; //将接口定义的方法绑定到具体子类的实现方法上。
}
有了这个绑定后,当调用接口的帮助方式vcam_imediatype_get时,具体子类的方法将被会调用。最后,按照接口定义,实现绑定函数:
void vediomedia_get(VcamIMediaType* self, Format* formatprt) {
//implement here
}
到这里,一个接口从声明到定义,最后到实现就完成了。