888974111 发表于 2025-2-7 03:05:02

GObject学习笔记(一)类和实例

前言

最近阅读Aravis源码,其中大量运用了GObject,于是打算学习一下。
此系列笔记仅主要面向初学者,不会很深入探讨源码的细节,专注于介绍GObject的基本用法。
此系列笔记参考GObject Tutorial for beginners
本文可在个人博客中阅读,体验更加
套个盾:文中定义的名词只是为了更好地理解GObject,不具备权威性。
类和实例

在GObject中,每个可实例化类类型都与两个结构体相关联:一个是类结构体,一个是实例结构体。

[*]类结构体会被注册到类型系统中(具体注册方式在下一节讨论),在g_object_new首次调用时,类型系统会检查相应的类结构体是否已经被初始化为一个类变量,没有则创建并初始化。此后所有该类的实例变量都将共享这个已初始化的类变量。每个类变量只会被创建一次。
[*]每次调用g_object_new时都会创建实例变量。
在GObject系统中,类结构体和实例结构体都会被实例化,在内存中占有特定的空间。为了便于描述,我们将分配给类结构体的实例称为“类变量”,而分配给实例结构体的实例称为“实例变量”。
GObject实例的结构体定义如下
//file: gobject.htypedef struct _GObjectGObject;struct_GObject{GTypeInstanceg_type_instance;    /*< private >*/guint          ref_count;/* (atomic) */GData         *qdata;};GObject类的结构体定义如下(我们可以先不用了解结构的细节):
//file: gobject.htypedef struct _GObjectClass             GObjectClass;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;};下面使用一个简单示例,来演示GObject的类和实例的使用
//file: example01.c#include <glib-object.h>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;}其中:

[*]g_object_new函数创建实例变量并返回指向它的指针。在实例变量第一次被创建之前,它对应的类变量也会被创建并初始化。
[*]参数G_TYPE_OBJECT是GObject基类的类型标识符,这是GObject类型系统的核心,所有其他GObject类型都从这个基类型派生。
[*]宏G_OBJECT_GET_CLASS返回指向参数所属类变量的指针
[*]g_object_unref会销毁实例变量并释放内存。
输出:
The address of instance1 is 0x55d3ddc05600The address of instance2 is 0x55d3ddc05620The address of the class of instance1 is 0x55d3ddc05370The address of the class of instance2 is 0x55d3ddc05370可以发现,两个实例变量的地址不同,但两个实例变量对应的类变量的地址相同,因为两个实例变量共享一个类变量
引用计数

引用计数机制的概念在此不做介绍
在GObject中,GObject实例具有引用计数机制:
//file: example02.c#include <glib-object.h> static void show_ref_count (GObject* instance) {    if (G_IS_OBJECT (instance))      /* Users should not use ref_count member in their program. */      /* This is only for demonstration. */      g_print ("Reference count is %d.\n", instance->ref_count);    else      g_print ("Instance is not GObject.\n");} int main (int argc, char **argv) {    GObject* instance;    instance = g_object_new (G_TYPE_OBJECT, NULL);    g_print ("Call g_object_new.\n");    show_ref_count (instance);    g_object_ref (instance);    g_print ("Call g_object_ref.\n");    show_ref_count (instance);    g_object_unref (instance);    g_print ("Call g_object_unref.\n");    show_ref_count (instance);    g_object_unref (instance);    g_print ("Call g_object_unref.\n");    g_print ("Now the reference count is zero and the instance is destroyed.\n");    g_print ("The instance memories are possibly returned to the system.\n");    g_print ("Therefore, the access to the same address may cause a segmentation error.\n");    return 0;}其中:

[*]g_object_new创建一个实例变量,然后将变量的引用计数置为1
[*]g_object_ref将其引用计数加1
[*]g_object_unref将引用计数减1,如果此时引用计数为0,则析构变量。
输出:
Call g_object_new.Reference count is 1.Call g_object_ref.Reference count is 2.Call g_object_unref.Reference count is 1.Call g_object_unref.Now the reference count is zero and the instance is destroyed.The instance memories are possibly returned to the system.Therefore, the access to the same address may cause a segmentation error.初始化和析构过程

GObject初始化和销毁的实际过程比较复杂。以下是简单的描述,不做详细说明.
初始化

1.用类型系统注册GObject类型。这是在调用main函数之前的GLib的初始化过程中完成的。(如果编译器是gcc,则__attribute__ ((constructor))用于限定初始化函数。)
2.为GObjectClass和GObject结构分配内存
3.初始化GObjectClass结构内存。这个内存将是GObject的类变量。
4.初始化GObject结构内存。这个内存将是GObject的实例变量。
上述初始化过程在第一次调用g_object_new函数时执行。在第二次及后续调用g_object_new时,它只执行两个过程:①为GObject结构分配内存②初始化内存。
析构

1.销毁GObject实例。释放实例的内存
GObject变量类型是静态类型。静态类型永远不会破坏它的类。因此,即使被销毁的实例变量是最后一个,类变量仍然存在,直到程序终止。
参考文章

1.GObject Tutorial for beginners
推荐

下一篇:GObject学习笔记(二)类型创建与注册
页: [1]
查看完整版本: GObject学习笔记(一)类和实例