linux - gobject使用

简介

  1. Gobject 系统提供了一个灵活的、可扩展的、并且容易映射到其他语言的面向对象的 C 语言框架.
    (1)是Glib库的动态类型系统实现,它实现了:
      [1] 基于引用计数的内存管理
      [2] 实例的构造和析构
      [3] 通用的set/get的属性获取方法
      [4] 简单易用的信号机制
  2. GObject 的动态类型系统允许程序在运行时进行类型注册,主要目的有两个:
    (1)使用面向对象的设计方法来编程,GObject 仅依赖于 GLib 和 libc , 通过它可使用纯 C 语言设计一整套面向对象的软件模块。
    (2)多语言交互,GObject 框架很容易连结其它语言,包括 C++ 、 Java 、 Ruby 、 Python 和 .NET/Mono 等。
  3. GObject世界里,类是两个结构体的组合:实例结构体,类结构体。
    (1)类结构体初始化函数一般被调用一次,而实例结构体的初始化函数的调用次数等于对象实例化的次数。
    (2)所有实例共享的数据,可保存在类结构体中,而所有对象私有的数据,则保存在实例结构体中。
  4. Gtype 类型系统是 Glib 运行时类型认证和管理系统。
    (1)Gtype API 是 Gobject 系统的 基础 ,它提供注册和管理所有基本数据、用户定义对象和接口类型的技术实现。
      [1] G_DEFINE_TYPE 宏、 G_DEFINE_INTERFACE 宏、 g_type_register_static 函数等都在 GType 实现。
      [2] G_DEFINE_TYPE 宏 主要用于实现用户定义类型 ,包括:
        a. 声明类初始化函数、声明实例初始化函数、声明父类的一些信息
        b. 用于获取分配类型 ID 的 xx_xx_get_type () 函数
  5. 对象实例化
    (1)g_object_new的功能家族:用于实例化从GObject的基类型,继承的任何的GType。
      [1] 确保类和实例结构已经被GLib的类型系统正确地初始化,然后在其它地方调用构造函数类方法:
        a. 调用g_type_create_instance分配并清空内存
        b. 根据构造参数初始化对象实例

GTYPE实现基本类型

编译命令:gcc gtype.c $(pkg-config --cflags --libs gobject-2.0) -o gtype

*.h

#include <glib-object.h>

// a. 用struct来创建实例对象和类对象,实现“C风格”的对象 
typedef struct _SomeObject SomeObject;
struct _SomeObject {
    GTypeInstance   gtype;
    gint            m_a;
    gchar*          m_b;
    gfloat          m_c;
};

// “类结构体”定义所有的方法函数,类对象将是共享的
typedef struct _SomeObjectClass SomeObjectClass;
struct _SomeObjectClass {
    GTypeClass  gtypeclass;
    void  (*method1) (SomeObject *self, gint);
    void  (*method2) (SomeObject *self, gchar*);
};

// b. 声明一个"get_type"函数,第一次调用该函数时,负责向系统注册对象的类型,返回GType类型值,此后的调用会直接返回该GType值。
//    该值实际上是系统用来区别已注册类型的整型数字。
GType   some_object_get_type (void);

// c. 声明一些用来管理对象生命期的函数:初始化时创建对象的函数,结束时销毁对象的函数。
void some_object_class_init     (gpointer g_class, gpointer class_data);
void some_object_class_final    (gpointer g_class, gpointer class_data);
void some_object_instance_init  (GTypeInstance *instance, gpointer g_class);

// d. 用上面我们约定的方式来命名成员方法函数。
void  some_object_method1 (SomeObject *self, gint);   /* virtual */
void  some_object_method2 (SomeObject *self, gchar*); /* virtual */
void  some_object_method3 (SomeObject *self, gfloat); /* non-virtual */

// e. 创建一些样板式代码,符合规则的同时也让事情更简单一些
#define SOME_OBJECT_TYPE          (some_object_get_type ())
#define SOME_OBJECT(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOME_OBJECT_TYPE, SomeObject))
#define SOME_OBJECT_CLASS(c)      (G_TYPE_CHECK_CLASS_CAST ((c), SOME_OBJECT_TYPE, SomeObjectClass))
#define SOME_IS_OBJECT(obj)       (G_TYPE_CHECK_TYPE ((obj), SOME_OBJECT_TYPE))
#define SOME_IS_OBJECT_CLASS(c)   (G_TYPE_CHECK_CLASS_TYPE ((c), SOME_OBJECT_TYPE))
#define SOME_OBJECT_GET_CLASS(obj)(G_TYPE_INSTANCE_GET_CLASS ((obj), SOME_OBJECT_TYPE, SomeObjectClass))

*.c

#include "gtype.h"

// a. 实现虚方法。
void some_object_method1_impl (SomeObject *self, gint a)
{
        self->m_a = a;
        g_print ("Method1: %i.\n", self->m_a);
}
void some_object_method2_impl (SomeObject *self, gchar* b)
{
        self->m_b = b;
        g_print ("Method2: %s.\n", self->m_b);
}

// b. 实现所有公有方法。,我们。

// 实现虚方法,必须使用“GET_CLASS”宏来从类型系统中获取到类对象,用以调用虚函数表中的虚方法
void some_object_method1 (SomeObject *self, gint a) {
    SOME_OBJECT_GET_CLASS (self)->method1 (self, a);
}
void some_object_method2 (SomeObject *self, gchar* b) { 
   SOME_OBJECT_GET_CLASS (self)->method2 (self, b);
}
// 非虚方法,直接写实现代码即可。
void some_object_method3 (SomeObject *self, gfloat c) {
        self->m_c = c;
        g_print ("Method3: %f\n", self->m_c);
}

// c. 实现初始化/销毁方法
// 该函数将在类对象创建时被调用,传入的参数是指向该对象的泛型指针,使用它前须转型为合适的类型
void  some_object_class_init(gpointer g_class, gpointer class_data) {
    g_print ("some_object_class_init start.\n");
    SomeObjectClass *this_class = SOME_OBJECT_CLASS (g_class);
    /* 填写类结构体的方法成员 (本例只存在一个虚函数表) */
    this_class->method1 = &some_object_method1_impl;
    this_class->method2 = &some_object_method2_impl;
    g_print ("some_object_class_init end.\n\n");
}

/* 该函数在类对象不再被使用时调用 */
void some_object_class_final (gpointer g_class, gpointer class_data) {
    g_print ("some_object_class_final end.\n\n");
}

/* 该函数在实例对象被创建时调用。系统通过g_class实例的类来传递该实例的类。 */
void some_object_instance_init (GTypeInstance *instance, gpointer g_class) {
    g_print ("some_object_instance_init start.\n");
    SomeObject *this_object = SOME_OBJECT (instance);
    /* 填写实例结构体中的成员变量 */
    this_object->m_a = 123;
    this_object->m_b = NULL;
    this_object->m_c = 4.56;
    g_print ("some_object_instance_init end.\n\n");
}

// d. 实现能够返回给调用者SomeObject的GType的函数。第一次运行时向系统注册SomeObject来获取GType,GType保存在静态变量中
// 虽然可以使用一个独立的函数来注册该类型,但这样的实现可以保证类在使用前是注册过的,该函数通常在实例化第一个对象时被调用。

// 因为该类没有父类,所以父类函数是空的
GType some_object_get_type (void) {
    g_print ("some_object_get_type start.\n");
    static GType type = 0;

    if (type == 0) {
        /* 这是系统用来完整描述要注册的类型是如何被创建、初始化和销毁的结构体。 */
        static const GTypeInfo type_info = {
            sizeof (SomeObjectClass),
            NULL,                           /* 父类初始化函数 */
            NULL,                           /* 父类销毁函数 */
            some_object_class_init,         /* 类对象初始化函数 */
            some_object_class_final,        /* 类对象销毁函数 */
            NULL,                           /* 类数据 */
            sizeof (SomeObject),
            0,                              /* 预分配的字节数 */
            some_object_instance_init       /* 实例对象初始化函数 */
        };

        /* 因为我们的类没有父类,所以它将被认为是“基础类(fundamental)”,
           因此必须要告诉系统,该类既是一个复合结构的类(与浮点型,整型,
           或者指针不同),而且是可以被实例化的(系统可以创建实例对象,相反如接口
           或者抽象类则不能被实例化) */
        static const GTypeFundamentalInfo fundamental_info = { G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE };      

        type = g_type_register_fundamental(
            g_type_fundamental_next (),     /* 下一个可用的GType */
            "SomeObjectType",               /* 类型的名称 */
            &type_info,                     /* 上面定义的type_info */
            &fundamental_info,              /* 上面定义的fundamental_info */
            0);                             /* 类型不是抽象的 */
    }
    g_print ("some_object_get_type stop: type=%ld.\n\n", type);
    return  type;
}

int main()
{
    // 让系统创建实例对象, g_type_create_instance的使用仅保留给基本类型的实现者,否则不建议使用
    // GObject层次结构的实例应该通过g_object_new创建
    GTypeInstance *g_instance = g_type_create_instance (some_object_get_type());
    SomeObject *testobj = SOME_OBJECT (g_instance);

    /* 调用我们定义了的方法 */
    if (testobj) {
        g_print ("init value: m_a=%d\n", testobj->m_a);
        some_object_method1 (testobj, 32);
        g_print ("init value: m_b=%s\n", testobj->m_b);
        some_object_method2 (testobj, "Hello world.");
        g_print ("init value: m_c=%.2f\n", testobj->m_c);
        some_object_method3 (testobj, 6.9);
    }

    g_type_free_instance(g_instance);
    g_print ("some_object_get_type stop: .\n\n");
    return  0;
}

gobject使用 sample

流程解析

  1. PMDList *list = g_object_new (PM_TYPE_DLIST, NULL);
    (1)GType pm_dlist_get_type (void);
    (2)#define PM_TYPE_DLIST (pm_dlist_get_type ())
  2. G_DEFINE_TYPE (PMDList, pm_dlist, G_TYPE_OBJECT);
    (1)GObject 库所提供的 G_DEFINE_TYPE 宏可以帮助生成 pm_dlist_get_type 函数的实现代码。
    (2)可以让 GObject 库的数据类型系统能够识别我们所定义的 PMDList 类类型
    (3)三个参数: 1. 类名,即 PMDList;2. 类的成员函数名称的前缀,例如 pm_dlist_*;3. PMDList 类类型的父类型
  3. G_TYPE_OBJECT
    (1)PT 格式,P 是项目名称缩写,T 是数据类型的名称:
    (2)g_object_get_type 形式的函数 统称为 p_t_get_type 函数
    (3)PM_TYPE_DLIST 和 G_TYPE_OBJECT 形式的宏 统称为 P_TYPE_T 宏

simple code

*.h

#ifndef PM_DLIST_H
#define PM_DLIST_H
 
#include <glib-object.h>

#define PM_TYPE_DLIST (pm_dlist_get_type ())

typedef struct _PMDListNode PMDListNode;
struct  _PMDListNode {
        PMDListNode *prev;
        PMDListNode *next;
        void *data;
};

typedef struct _PMDList PMDList;
struct  _PMDList {
        GObject parent_instance;
        PMDListNode *head;
        PMDListNode *tail;
};

typedef struct _PMDListClass PMDListClass;
struct _PMDListClass {
        GObjectClass parent_class;
};

GType pm_dlist_get_type (void);

#endif

*.c

#include "pm-dlist.h"

G_DEFINE_TYPE (PMDList, pm_dlist, G_TYPE_OBJECT);

static void pm_dlist_init (PMDList *self) {
    g_print ("\tpm_dlist_init.\n");

    self->head = NULL;
    self->tail = NULL;
}
static void pm_dlist_class_init (PMDListClass *klass) {
    g_print ("pm_dlist_class_init.\n");
}

int main (void)
{
    PMDList *list = g_object_new (PM_TYPE_DLIST, NULL);
    if (G_IS_OBJECT (list)) // 检查实例是否为 GObject 对象
        g_print ("\tthis is a GObject.\n");

    g_object_unref (list);

    return 0;
}

GObject 子类对象的私有属性(隐藏数据)

*.h

#ifndef PM_DLIST_H
#define PM_DLIST_H
 
#include <glib-object.h>

#define PM_TYPE_DLIST (pm_dlist_get_type ())

typedef struct _PMDList PMDList;
struct  _PMDList {
    GObject parent_instance;
};

typedef struct _PMDListClass PMDListClass;
struct _PMDListClass {
    GObjectClass parent_class;
};

GType pm_dlist_get_type (void);

#endif

*.c

#include "pm-dlist.h"

G_DEFINE_TYPE (PMDList, pm_dlist, G_TYPE_OBJECT);
#define PM_DLIST_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PM_TYPE_DLIST, PMDListPrivate))

typedef struct _PMDListNode PMDListNode;
struct  _PMDListNode {
    PMDListNode *prev;
    PMDListNode *next;
    void *data;
};

typedef struct _PMDListPrivate PMDListPrivate;
struct  _PMDListPrivate {
    PMDListNode *head;
    PMDListNode *tail;
};

static void pm_dlist_init (PMDList *self) {
    g_print ("\tpm_dlist_init.\n");

    PMDListPrivate *priv = PM_DLIST_GET_PRIVATE (self);
    priv->head = NULL;
    priv->tail = NULL;
}
static void pm_dlist_class_init (PMDListClass *klass) {
    g_print ("pm_dlist_class_init.\n");
    g_type_class_add_private (klass, sizeof (PMDListPrivate));
}

int main (void)
{
    PMDList *list = g_object_new (PM_TYPE_DLIST, NULL);
    g_object_unref (list);
    return 0;
}

GObject 属性设置

*.h

#ifndef PM_DLIST_H
#define PM_DLIST_H
 
#include <glib-object.h>
#include <glib/gstdio.h>

#define PM_TYPE_DLIST (pm_dlist_get_type ())

typedef struct _PMDList PMDList;
struct  _PMDList {
        GObject parent_instance;
};

typedef struct _PMDListClass PMDListClass;
struct _PMDListClass {
        GObjectClass parent_class;
};

GType pm_dlist_get_type (void);

#endif

*.c

#include "pm-dlist.h"

G_DEFINE_TYPE (PMDList, pm_dlist, G_TYPE_OBJECT);
#define PM_DLIST_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PM_TYPE_DLIST, PMDListPrivate))

typedef struct _PMDListNode PMDListNode;
struct  _PMDListNode {
    PMDListNode *prev;
    PMDListNode *next;
    void *data;
};

typedef struct _PMDListPrivate PMDListPrivate;
struct  _PMDListPrivate {
    PMDListNode *head;
    PMDListNode *tail;
};

static void pm_dlist_init (PMDList *self) {
    g_print ("\tpm_dlist_init.\n");

    PMDListPrivate *priv = PM_DLIST_GET_PRIVATE (self);

    priv->head = NULL;
    priv->tail = NULL;
}

enum PropertyDList {
    PROP_0,
    PROP_DLIST_ENABLE,
    PROP_DLIST_TEXT,
    PROP_DLIST_PRMS,
    PROP_DLIST_PRMS_ARRAY,
    PROP_DLIST_PRMS_STR
};

static void pm_dlist_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
    switch (prop_id) {
        case PROP_DLIST_ENABLE:
            g_print("enable: %d.\n", g_value_get_boolean(value));
            break;
        case PROP_DLIST_TEXT:
            g_value_get_string(value);
            break;
        case PROP_DLIST_PRMS_ARRAY: {
            GArray *array = g_value_get_boxed (value);
            guint element_size = g_array_get_element_size (array);
            for (guint i=0; i < array->len; i++) {
            	guint my_int = g_array_index (array, guint, i);
                g_print("g_array_index: element_size=%u, %uth=%u.\n", element_size, i, my_int);
                g_assert (my_int == i);
            }
            break;
        }
        case PROP_DLIST_PRMS_STR: {
            GString *str_get = g_value_get_boxed (value);
            g_print("GString: %s.\n", str_get->str);
            break;
        }

        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
            break;
    }
}

static void pm_dlist_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{

    switch (prop_id) {
        case PROP_DLIST_ENABLE:
            g_value_set_boolean(value, 1);
            break;
        case PROP_DLIST_TEXT:
            g_value_set_string(value, "test");
            break;

        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
            break;
    }
}

static void pm_dlist_class_init (PMDListClass *klass) {
    g_print ("pm_dlist_class_init.\n");
    g_type_class_add_private (klass, sizeof (PMDListPrivate));

    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
    gobject_class->set_property = pm_dlist_set_property;
    gobject_class->get_property = pm_dlist_get_property;

    g_object_class_install_property(gobject_class, PROP_DLIST_ENABLE,
               g_param_spec_boolean("dlist-enable", "dlist enable", "dlist enable",
                                    FALSE, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));

    g_object_class_install_property(gobject_class, PROP_DLIST_TEXT,
               g_param_spec_string("dlist-text", "DLIST text", "text",
                                   NULL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));

    g_object_class_install_property(gobject_class, PROP_DLIST_PRMS_ARRAY,
               g_param_spec_boxed("dlist-prms-array", "dlist prms", "dlist prms",
                                 G_TYPE_ARRAY, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));

    g_object_class_install_property(gobject_class, PROP_DLIST_PRMS_STR,
               g_param_spec_boxed("dlist-prms-str", "dlist prms", "dlist prms",
                                 G_TYPE_GSTRING, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));

}

//  settings = g_settings_new ("org.gtk.test.binding");
//  g_settings_set_boolean (settings, "bool", FALSE);
int main (void)
{
    PMDList *list = g_object_new (PM_TYPE_DLIST, NULL);
    g_assert (G_IS_OBJECT (list));

    g_object_set(G_OBJECT(list), "dlist-enable", FALSE, NULL);

    // g_value_get_boxed GString
    GValue value_str = G_VALUE_INIT;
    g_value_init (&value_str, G_TYPE_GSTRING);
    g_assert (G_VALUE_HOLDS_BOXED (&value_str));

    GString *str = g_string_new ("bla");
    g_value_take_boxed (&value_str, str);

    g_object_set_property(G_OBJECT(list), "dlist-prms-str", &value_str);

    g_value_unset (&value_str); // 不需要释放,否则段错误。g_string_free (str, TRUE);

    // g_value_get_boxed GArray
    GValue value_array = G_VALUE_INIT;
    g_value_init (&value_array, G_TYPE_ARRAY);
    g_assert (G_VALUE_HOLDS_BOXED (&value_array));

    GArray *int_array = g_array_new (TRUE, FALSE, sizeof (guint));
    for (guint i = 0; i < 5; i++)
        g_array_append_val (int_array, i);

    g_value_take_boxed (&value_array, int_array);

    g_object_set_property(G_OBJECT(list), "dlist-prms-array", &value_array);

    g_array_unref (int_array);    // 是否不需要?
    g_value_unset (&value_array);

    g_object_unref (list);

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值