Gobject C语言库 I 对象与它的类定义

Gobject 时一个为C语言提供面向对象编程的基础库。 作为一门基础语言,C语言在操作系统层面有着绝对统治的应用,但是它是一门过程语言,在面对业务处理上,由于缺乏足够的抽象,编写起来非常费力。为了减少这些缺陷,C语言生态圈也出现了不同的基础库,帮助想使用面向对象进行C语言开发的工程师进行开发,Gobject就是其中之一。
在面向对象的语言里,每一个事物或者业务会被抽象为一种类型,每一个具体的事物都是这个类的实例。在声明和创建一个方法通常用下面的格式:
VcamSource source=new VcamSouce(......);
在Gobject中,通常会这样写:
VcamSource *source;
source=g_object_new(VCAM_TYPE_SOURCE, NULL);
VCAM_TYPE_SOURCE 是一个宏定义,用来返回系统中注册的VcamSource类型。

在面向对象的语言里因为有复杂的对象与类继承管理,所以通常只需要声明VcamSource 类就可以了:
Class VcamSource{
public:
....
private:
.....

}
在C语言中是缺乏这些的,所以Gobject提供类自己的继承链和类型注册系统,在Gobject中,我们通常需要声明一个抽象类型和它的类型描述类:

#ifndef VCAM_SOURCE_H
#define VCAM_SOURCE_H

#include <glib-object.h>

#define VCAM_TYPE_SOURCE (vcam_source_get_type ())
//抽象类型
typedef struct _VcamSoure VcamSource;   
struct  _VcamSoure {
    GObject parent_instance;
};

//抽象类型的类
typedef struct _VcamSoureClass VcamSourceClass;
struct _VcamSoureClass {
    GObjectClass parent_class;
};

GType vcam_source_get_type(void);

#endif

可以看出VcamSource抽象类型其实就是一个struct 结构体, 它包含至少一个属性GObject parent_instance;, 这表示的是一个继承关系: VcamSource继承自 GObject (这个属性必须为第一个元素)。
_VcamSoureClass 是VcamSource的类型,它用来描述VcamSource和包含这一个类事务的通用属性或方法。它的第一个属性是GObjectClass,也表示的是继承关系,且 GObjectClass正是GObject的类。
在这个定义中,宏定义VCAM_TYPE_SOURCE对应的是一个返回GType 类型的方法,他正对应Gobject创建实例的第一个参数:
source=g_object_new(VCAM_TYPE_SOURCE, NULL);
VCAM_TYPE_SOURCE实际上是vcam_source_get_type()方法的调用; 这个方法主要做两件事情:声明一个VcamSource的Gtype类型;把这个类型发注册到Gobject的类型系统里,这样才可以通过g_object_new来初始化。它的具体实现是在VcamSource.c文件里;vcam_source_get_type的实现内容大概如下:

GType vcam_source_get_type(void)
{
  static GType source_type = 0;

  if (!media_type)
  {
   //声明一个GTypeInfo类型
     static const GTypeInfo source_info = {
        sizeof(VcamSourceClass),                    /* class structure size */
        NULL,                                                    /* base class initializer */
        NULL,                                                   /* base class finalizer */
        (GClassInitFunc)VcamSource_class_init,  /* class initializer */
        NULL,                                                  /* class finalizer */
        NULL,                                               /* class data */
        sizeof(VcamSource),                       /* instance structure size */
        16,                                                  /* preallocated instances */
        NULL,                                             /* instance initializer */
        NULL                                             /* function table */
     };
    //将GTypeInfo info注册到Gobject的type系统里
     media_type = g_type_register_static(
            G_TYPE_OBJECT,                 /* parent class */
            "Media",                       /* type name */
            &media_info,                   /* GTypeInfo struct (above) */
            0);                            /* flags */
  }

  return source_type ;
}

g_type_register_static(parent_id, name, type_info, options) 用于类型的注册,他的参数如下:
parent_id: 父类标识,Object类的标识就是通过G_TYPE_OBJECT宏获取
name: 类型名称
typeinfo: GTypeInfo结构,里面包含了对新类型的描述
options: 标识符,例如标准虚类等。
在看一下,source_info的声明,里面包含了很多内容,我们需要了解的包含基础类的初始化,class类型的初始化,实例的初始化等等。这些方法的声明如下:
typedef void (GBaseInitFunc) (gpointer g_class);
typedef void (
GBaseFinalizeFunc) (gpointer g_class);
typedef void (GClassInitFunc) (gpointer g_class, gpointer class_data);
typedef void (
GClassFinalizeFunc) (gpointer g_class, gpointer class_data);
typedef void (*GInstanceInitFunc) (GTypeInstance *instance, gpointer g_class);
如果要一个一个实现,确实也是很费劲的事情,GObject也考虑了这一点,所以提供了一个新的宏定义,它是声明在.c文件里:

#include "VcamSource.h"

G_DEFINE_TYPE(VcamSource, vcam_source, G_TYPE_OBJECT)   

static void
vcam_source_class_init(VcamSourceClass* class) {   //类初始化方法

}

 static void
 vcam_source_init(VcamSource* d) {   //实例初始化方法

}

 int  main(int argc, char** argv) {
     GType dtype;
     VcamSource* d;
     
          dtype = vcam_source_get_type(); /* or d = T_TYPE_DOUBLE */
        if (dtype)
             g_print("Registration was a success. The type is %lx.\n", dtype);
        else
              g_print("Registration failed.\n");
     return 0;
 }

G_DEFINE_TYPE是在.c文件里出现的,他做了以下的工作:

  • 声明了一个新类型的类的初始化函数,格式为<name space>_<name>_class_init 我们通常需要这个方法来注册属性、挂载虚函数。
  • 声明了一个新类型的初始化函数,格式为 <name space>_<name>_init,我们通常在这个函数中初始化具体实例的信息。
  • 声明了一个静态变量,让它指向新类型的类的父类。 格式为 <name space>_<name>_parent_class,可用于访问父类中的方法。
  • 定义了获取类ing的函数,格式为<name space>_<name>_get_type (),这个正是我们注册类型需要的,所以GType vcam_source_get_type(void);这一行在头文件中就可以省略了。

G_DEFINE_TYPE很显然简化了我们的大量工作,但是要注意遵循对初始化函数的命名规范。
在面向对象的语言里,通常我们需要类型映射,需要检查某个实例是否试我们想要的类型,类似于:
source2 =VcamSoure(obj);
obj instanceof VcamSoure;
在Object里,同样使用宏定义来实现前两项:
#defind VCAM_SOURCE(obj) ....
#defind VCAM_IS_SOURCE(obj) ....
这有需要在.h加入很多行,于是为了更简洁, Gobject 提供了一个新的宏 G_DECLARE_FINAL_TYPE, 它可以做下面这些事情:

  • 声明了一个<name space>_<name>_get_type ()方法,而G_DEFINE_TYPE包含了对它的定义,所以我们实际上跟本不需要写这个方法。
  • 定义了一个有用的宏<NAME SPACE>_<NAME>,用来进行对象的映射。例如 VCAM_SOURCE(object)可以把普通对象类映射成我们需要的VcamSource类。
  • 定义了一个<NAME SPACE>IS<NAME>, 用来判断是否一个实例来自于我们想要的类型。例如,VCAM_IS_SOURCE(obj), 可以判断 obj是否是VcamSource的实例。
    于是,引入这个宏后,我们的.h文件就更简洁了:
#ifndef VCAM_SOURCE_H
#define VCAM_SOURCE_H

#include <glib-object.h>

#define VCAM_TYPE_SOURCE (vcam_source_get_type())
G_DECLARE_FINAL_TYPE(VcamSource, vcam_source, VCAM, SOURCE, GObject)

struct  _VcamSoure {
    GObject parent_instance;
};


struct _VcamSoureClass {
    GObjectClass parent_class;
};

#endif /* __VCAM_SOURCE_H__ */

但是宏G_DECLARE_FINAL_TYPE有个缺陷,它不允许有任何子对象,相当于用Final修饰了VcamSoure 。如果需要有子对象,就需要使用另外一个宏G_DECLARE_DERIVABLE_TYPE 。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容