一个面向对象的C语言框架

GObject是Glib库的一部分,提供了一个灵活的、可扩展的、并且容易映射到其他语言的面向对象的C语言框架。以下是GObject的一些核心概念和使用方法。

源码:https://gitlab.gnome.org/GNOME/glib/

教程:https://docs.gtk.org/gobject/index.html

1. GObject的核心概念

  • 动态类型系统:GObject允许程序在运行时进行类型注册,这意味着可以使用纯C语言设计一整套面向对象的软件模块。
  • 内存管理:GObject实现了基于引用计数的内存管理,这简化了内存管理的复杂性。
  • 属性系统:GObject提供了通用的set/get属性获取方法,使得属性管理变得更加简单。
  • 信号机制:GObject内置了简单易用的信号机制,允许对象之间进行通信。

2. GObject的使用示例

在GObject中,类和实例是两个结构体的组合。类结构体初始化函数一般被调用一次,而实例结构体的初始化函数的调用次数等于对象实例化的次数。所有实例共享的数据保存在类结构体中,而对象私有的数据保存在实例结构体中。

GObject实例的结构体定义如下:

typedef struct _GObject  GObject;
struct  _GObject
{
  GTypeInstance  g_type_instance;
  
  /*< private >*/
  guint          ref_count;  /* (atomic) */
  GData         *qdata;
};

GObject类的结构体定义如下:

struct  _GObjectClass
{
  GTypeClass   g_type_class;

  /*< private >*/
  GSList      *construct_properties;

  /*< public >*/
  /* seldom overridden */
  GObject*   (*constructor)     (GType                  type,
                                 guint                  n_construct_properties,
                                 GObjectConstructParam *construct_properties);
  /* overridable methods */
  void       (*set_property)        (GObject        *object,
                                         guint           property_id,
                                         const GValue   *value,
                                         GParamSpec     *pspec);
  void       (*get_property)        (GObject        *object,
                                         guint           property_id,
                                         GValue         *value,
                                         GParamSpec     *pspec);
  void       (*dispose)         (GObject        *object);
  void       (*finalize)        (GObject        *object);
  /* seldom overridden */
  void       (*dispatch_properties_changed) (GObject      *object,
                         guint     n_pspecs,
                         GParamSpec  **pspecs);
  /* signals */
  void       (*notify)          (GObject    *object,
                     GParamSpec *pspec);

  /* called when done constructing */
  void       (*constructed)     (GObject    *object);

  /*< private >*/
  gsize     flags;

  gsize         n_construct_properties;

  gpointer pspecs;
  gsize n_pspecs;

  /* padding */
  gpointer  pdummy[3];
};

以下是一个简单的示例,展示了如何创建和使用GObject实例:

#include 

int main (int argc, char **argv) {
    GObject* instance1, *instance2; // 指向实例的指针
    GObjectClass* class1, *class2;  // 指向类的指针

    instance1 = g_object_new (G_TYPE_OBJECT, NULL);
    instance2 = g_object_new (G_TYPE_OBJECT, NULL);

    g_print ("The address of instance1 is %p\n", instance1);
    g_print ("The address of instance2 is %p\n", instance2);

    class1 = G_OBJECT_GET_CLASS (instance1);
    class2 = G_OBJECT_GET_CLASS (instance2);

    g_print ("The address of the class of instance1 is %p\n", class1);
    g_print ("The address of the class of instance2 is %p\n", class2);

    g_object_unref (instance1);
    g_object_unref (instance2);

    return 0;
}
The address of instance1 is 0x55fb9141ad20
The address of instance2 is 0x55fb9141ad40
The address of the class of instance1 is 0x55fb9141a350
The address of the class of instance2 is 0x55fb9141a350

在这个示例中,g_object_new 函数用于创建GObject实例,并返回指向它的指针。G_TYPE_OBJECT 是GObject基类的类型标识符,所有其他GObject类型都从这个基类型派生。宏 G_OBJECT_GET_CLASS 返回指向参数所属类变量的指针。g_object_unref 用于销毁实例变量并释放内存。

实例1与实例2的存储空间是不同的,每个实例都有自己的空间。两个类的存储空间是相同的,两个GObject实例共享同一个类。

3. GObject的信号机制

GObject允许定义和使用属性,以及发出和连接信号。这些特性使得GObject非常适合用于构建复杂的软件系统,尤其是在需要组件间通信和属性管理的场景中。

信号最基本的用途是实现事件通知。例如:创建一个信号,当调用文件写方法时,触发文件变化信号。

创建信号:

file_signals[CHANGED] = 
  g_signal_newv ("changed",
                 G_TYPE_FROM_CLASS (object_class),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 NULL /* closure */,
                 NULL /* accumulator */,
                 NULL /* accumulator data */,
                 NULL /* C marshaller */,
                 G_TYPE_NONE /* return_type */,
                 0     /* n_params */,
                 NULL  /* param_types */);

带信号机制的文件写方法:

void
viewer_file_write (ViewerFile   *self,
                   const guint8 *buffer,
                   gsize         size)
{
  g_return_if_fail (VIEWER_IS_FILE (self));
  g_return_if_fail (buffer != NULL || size == 0);

  /* First write data. */

  /* Then, notify user of data written. */
  g_signal_emit (self, file_signals[CHANGED], 0 /* details */);
}

用户回调处理函数连接到信号:

g_signal_connect (file, "changed", (GCallback) changed_event, NULL);

4. 跨语言互通性

GObject被设计为可以直接使用在C程序中,并且可以封装至其他语言,如C++、Java、Ruby、Python和.NET/Mono等,这使得GObject具有很好的跨语言互通性。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 4
收藏 5
关注 24
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧