Gobject编程实现

来源:互联网 发布:python 财经数据接口 编辑:程序博客网 时间:2024/06/02 06:46

GObject 是一个程序库,它可以帮助我们使用 C 语言编写面向对象程序。

GObject实现有一套固有的格式,可以理解为C++语言的语法一样,如果要使用GObject就必须按格式实现。

GObject的对象系统提供了一种灵活的、可扩展的、并容易映射(到其它语言)的单根继承面向对象的C语言框架。

animal-base.h的实现如下:

#ifndef _BASE_H_#define _BASE_H_#include <glib-object.h>#include <stdio.h>typedef struct _AnimalBase  AnimalBase;typedef struct _AnimalBaseClass AnimalBaseClass;#define ANIMAL_TYPE_BASE    (animal_base_get_type())//实例类型转换#define ANIMAL_BASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANIMAL_TYPE_BASE, AnimalBase))//实例类型判定#define ANIMAL_IS_BASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANIMAL_TYPE_BASE))//类结构转换#define ANIMAL_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANIMAL_TYPE_BASE, AnimalBaseClass))//类结构判定#define ANIMAL_IS_BASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANIMAL_TYPE_BASE))//获取类结构#define ANIMAL_BASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANIMAL_TYPE_BASE, AnimalBaseClass))struct _AnimalBase{GObject parent;char szName[32];//名称intiEye;//眼睛个数intiNose;//鼻子个数intiMouth;   //嘴巴intiLeg;   //腿intiTail;   //尾巴};struct _AnimalBaseClass{GObjectClass classparent;void (*drinkwater)(AnimalBase *obj);void (*eat)(AnimalBase *obj);void (*run)(AnimalBase *obj);};void send_base_drink_signal(AnimalBase *pBase);#endif

animal-base.c的实现如下:

#include "animal-base.h"#include <string.h>typedef enum{DRINK_BASE_SIGNAL = 0,EAT_BASE_SIGNAL = 1,RUN_BASE_SIGNAL = 2,LAST_BASE_SIGNAL};static int basesignals[LAST_BASE_SIGNAL];G_DEFINE_TYPE(AnimalBase,animal_base,G_TYPE_OBJECT);static void animal_base_init(AnimalBase *pBase){printf("animal_base_init.\n");}static void animal_base_class_destroy(GObject *object){printf("animal_base_class_destroy.\n");}static void animal_base_class_finalize(GObject *object){printf("animal_base_class_finalize.\n");}static void animal_base_drink(AnimalBase *pBase){printf("animal_base_drink[%p] class[%p].\n",pBase,ANIMAL_BASE_GET_CLASS(pBase));}static void animal_base_eat(AnimalBase *pBase){printf("animal_base_eat[%p].\n",pBase);}static void animal_base_run(AnimalBase *pBase){printf("animal_base_run[%p].\n",pBase);}static void animal_base_class_init(AnimalBaseClass *pBaseClass){G_OBJECT_CLASS(pBaseClass)->finalize = animal_base_class_finalize;G_OBJECT_CLASS(pBaseClass)->dispose  = animal_base_class_destroy;pBaseClass->drinkwater   = animal_base_drink;pBaseClass->eat    = animal_base_eat;pBaseClass->run    = animal_base_run;basesignals[DRINK_BASE_SIGNAL] = g_signal_new ("basedrink",                      G_TYPE_FROM_CLASS (pBaseClass),                      G_SIGNAL_RUN_LAST,  G_STRUCT_OFFSET (AnimalBaseClass, drinkwater),                      NULL,                      NULL,                      g_cclosure_marshal_VOID__VOID,                      G_TYPE_NONE, 0);printf("animal_base_class_init.\n");}void send_base_drink_signal(AnimalBase *pBase){g_signal_emit (pBase, basesignals[DRINK_BASE_SIGNAL], 0);}

在GObject系统中,对象由三个部分组成:

  1. 对象的ID标识(唯一,无符号长整型,所有此类对象共同的标识);
  2. 对象的类结构(唯一,结构型,由对象的所有实例共同拥有);
  3. 对象的实例(多个,结构型,对象的具体实现)。

在Gobject中每个对象需要使用两个结构体描述,一个类结构体AnimalBaseClass,一个实例结构体AnimalBase。创建多个对象时类结构体只会有一个,实例结构体则有多少个对象则有多少个实例。当第一次创建对象时,没有新建类结构体则会先新建类结构体并调用类结构体的初始化函数animal_base_class_init再新建实例结构体调用实例结构体的初始化函数animal_base_init,如果已经之前已经新建过类结构体则不再新建类结构体直接新建实例结构体。


对于 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 对象对应的类结构体类型。
在.c文件中我们使用Gobject提供的G_DEFINE_TYPE 宏,该宏的作用是向Gobject系统注册将用户自己定义的类型G_DEFINE_TYPE 宏会声明一些函数, 并且实现了animal_base_get_type(void),所以才需要在对应的.h头文件中声明animal_base_get_type这个函数。这个宏展开之后会调用g_type_register_static_simple函数实现注册并调用类和实例的初始化函数animal_base_class_init和animal_base_init,第一个函数在每个对象创建的时候都会被调用, 第二个函数只有在第一次创建对象的时候才会被调用。
以上代码实现之后,Gobject的对象已经实现了,接下来就是在代码中需要的时候如何new出一个对象,调用函数g_object_new
#include "animal-base.h"  int main (void)  {  AnimalBase *P0 = NULL;AnimalBase *P1 = NULL;AnimalBase *P2 = NULL;    g_type_init ();    P0 = g_object_new (ANIMAL_TYPE_BASE, NULL);      P1 = g_object_new (ANIMAL_TYPE_BASE, NULL);  P2 = g_object_new (ANIMAL_TYPE_BASE, NULL);printf("start send signal.\n");    send_base_drink_signal(P0);    send_base_drink_signal(P1);    send_base_drink_signal(P2);printf("end send signal.\n");g_object_unref(P0);g_object_unref(P1);g_object_unref(P2);    return 0;  }  

gpointer

g_object_new (GType      object_type,
            const gchar *first_property_name,
            ...)
这个函数是个可变参数的函数, 第一个参数是需要创建的对象的类型, 当使用 g_object_new 来创建对象的时候, 这个参数是必须的, 同时它还要求这个函数所创建 的对象必须是GObject的子对象. 在我们定义自己的对象时, 必须要在系统中注册自己的 类型, 这里的系统指的是 glib 的系统。
编译命令为:gcc -Wall Base.c main.c -o test $(pkg-config --cflags --libs gobject-2.0)
上面main函数运行的结果如下:



0 0
原创粉丝点击