GObject学习教程---第十一章:GObject 子类对象的析构过程

GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed分析 在调试opencv程序的时候,对于新手来说,会有很多令人恶心的错误,这些错误编译器可能检查不出来,但是程序却运行不了。例如:(pic:6130): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed举个例子:int main() { while(1) { IplImage* 阅读详情

索引:https://blog.youkuaiyun.com/knowledgebao/article/details/84633798

本文是学习学习他人的博客的心得(具体详见“楼主见解”),如果源网站可访问的话,建议直接访问源网站:

楼主见解:

主要讲解析构为什么需要2个函数来实现。讲解了dispose和finalize的使用场景。析构函数末尾必须调用基类的对应析构函数。

James Henstridge 给出了一个方案,那就是将 GObject 类及其子类对象的析构过程分为 dispose 阶段与 finalize 阶段。在 dispose 阶段,只解除对象 A 对其所有属性的引用,而在 finalize 阶段释放对象 A 所占用的资源。dispose 阶段可被重复执行多次,而 finalize 阶段仅被执行一次。但是 James Henstridge 的约定,不仅仅是要保证 dispose 函数可被多次执行,还要保证在 dispose 函数执行之后并且在 finalize 函数执行之前,程序不会出错。这意味着 dispose 函数不能影响对象的行为(方法)。

所以要保证在dispose接触对其属性的接触时,要保证其他函数的正常执行,所以可能需要用到锁。


源博客网址:http://garfileo.is-programmer.com/categories/6934/posts

 

GObject 子类对象的析构过程

在“GObject 的信号机制”文中,谈到 GObject 子类对象的析构过程分为两个阶段,第一阶段是 dispose,第二阶段是 finalize。之所以划分成两个阶段而不是一步到位的内存释放,一切皆因尴尬现实之所迫。

引用计数与引用循环

现在,我们都知道了 GObject 类及其子类的对象,其内存管理基于引用计数机制而实现。所谓基于引用计数的内存管理,可大致描述为:

  • 使用 g_object_new 函数进行对象实例化的时候,对象的引用计数为 1;
  • 每次使用 g_object_ref函数引用对象时,对象的引用计数便会增 1;
  • 每次使用 g_object_unref 函数为对象解除引用时,对象的引用计数便会减 1;
  • 在 g_object_unref 函数中,如果发现对象的引用计数为 0,那么则调用对象的析构函数释放对象所占用的资源。

GObjec 类及其子类对象不仅存在继承的关系,还存在互相包含的关系,例如有一个 GObject 子类对象 A 包含(引用)了另一个 GObject 子类对象 B(也就是说对象 B 是对象 A 的属性),而对象 B 有可能反过来又引用了对象 A,这样便构成了引用循环。对于这种情况,对象 A 的析构函数不可能一步到位彻底释放它所占用的资源,可以论证一下:

  • 假设对象 A 的析构函数为 a_deconstruct。
  • a_deconstruct 函数只能在对象 A 的引用计数为 0 的时候被 g_object_unref 函数调用。
  • 在 g_object_new 对象 A 的时候,由于 A 所包含的对象 B 有可能反过来引用 A,那么 A 的引用计数就有可能不是 1 而是 2。
  • 在 g_object_unref 对象 A 的时候,由于此时对象 A 的引用计数可能为 2,所以 g_object_unref 只是将 A 的引用计数减掉 1,而不会调用 a_deconstruct 函数。
  • 对于对象 A 的使用者,在不清楚对象 A 的内部实现时,他会天真的认为 g_object_new 与 g_object_unref 的配对就可以回收 A 的资源,但事实则不然。
  • 对象 A 的使用者如果多次调用 g_object_unref 最终可以引发 a_deconstruct 函数工作,从而实现对象 A 的资源释放,但是使用者并不清楚究竟该运行几次 g_object_unref 才能有这种效果,并且在对象 A 已经被析构的情况下,再次 g_object_unref 对象 A,那么就会出现段错误。

James Henstridge 的方案

为解决引用循环的问题,James Henstridge 给出了一个方案,那就是将 GObject 类及其子类对象的析构过程分为 dispose 阶段与 finalize 阶段。在 dispose 阶段,只解除对象 A 对其所有属性的引用,而在 finalize 阶段释放对象 A 所占用的资源。dispose 阶段可被重复执行多次,而 finalize 阶段仅被执行一次。

但是,与其说 James Henstridge 给出了一个方案,不如说他给出了一种约定。因为这种方案在 C 语言中是不可能自动实现,它需要 GObject 库的使用者小心谨慎的保证在 dispose 与 finalize 阶段之间不会出现程序错误(通常是段错误)。

例如“GObject 的信号机制”文中的 MyFile 对象的 dispose 代码:

1

2

3

4

5

6

7

8

9

10

11

static void

my_file_dispose (GObject *gobject)

{

        MyFile *self        = MY_FILE (gobject);

        MyFilePrivate *priv = MY_FILE_GET_PRIVATE (self);

        if (priv->file){

                g_io_channel_unref (priv->file);

                priv->file = NULL;

        }

        G_OBJECT_CLASS (my_file_parent_class)->dispose (gobject);

}

MyFile 对象的私有属性 file 是一个指向 GIOChannel 类型变量的指针,它与 GObject 库没有丝毫关系,其内存释放实际上可在 finalize 阶段执行,之所以将其放在 dispose 阶段执行,主要是想揭示 James Henstridge 所给出的约定。这种约定就是必须保证 my_file_dispose 可被无限次的执行而不出错,所以在 my_file_dispose 函数中添加了file 指针有效性判断与野指针消除的代码。

在 GObject 手册中,也有一个 dispose 的示例:

1

2

3

4

5

6

7

8

9

10

11

12

static void

maman_bar_dispose (GObject *gobject)

{

        MamanBar *self = MAMAN_BAR (gobject);

        if (self->priv->an_object)

        {

                g_object_unref (self->priv->an_object);

                self->priv->an_object = NULL;

        }

         

        G_OBJECT_CLASS (maman_bar_parent_class)->dispose (gobject);

}

从上述代码中可看出,MamanBar 对象的私有属性 an_object 是一个 GObject 子类对象,也需要指针有效性判断与野指针消除的代码,因为我们必须要保证对象的 dispose 函数可被多次执行。

那么,多次执行对象的 dispose 函数的任务是由 g_object_unref 来完成吗?

肯定不是。因为 g_object_unref 也不知道该执行多少次 dispose 函数才可以将引用循环打破。

实际上,James Henstridge 所给出的这个约定,并非是让 GObject 自身可以智能的破解引用循环,而是认为 GObject 之外的程序能够分析出引用循环的存在,并由它多次执行对象的 dispose 函数。

例如,基于 GObject 的类型管理与引用计数机制,可在 GObject 库之上建立一个内存回收功能的程序库,GObject 库自身的内存管理机制仅仅是方便上层的内存回收库的实现而已。至于 GObject 库的使用者,依然要像 C 语言程序员那样,兢兢业业的处理好每一块内存的分配与回收。

析构需要向上回溯

在 GObject 子类对象的 dispose 与 finalize 函数中,末尾都有一行比较类似的代码。例如 MyFile 对象的 dispose 函数,有:

1

G_OBJECT_CLASS (my_file_parent_class)->dispose (gobject);

MyFile 对象的 finalize 函数,有:

1

G_OBJECT_CLASS (my_file_parent_class)->finalize (gobject);

这两行代码主要是“请求” MyFile 父类对象进行析构。

因为 C 语言不是内建支持面向对象,所以继承需要从上至下的进行结构体包含,那么析构就除了要释放自身资源还需要引发父类对象的析构过程,这样才可以彻底消除整条继承链所占用的资源。

向上回溯析构,这还倒好理解,但是 G_OBJECT_CLASS (my_file_parent_class) 是什么玩意?在 MyFile 类的实现中,我们从未声明与定义过 my_file_parent_class 这个变量或者宏。

不,其实我们既声明了它,也定义了它,其中的玄机就在 my-file.c 源文件开始部分的 G_DEFINE_TYPE 宏之中。如果我们使用命令

1

gcc -E -P my-file.c > my-file-extend.c

将 my-file.c 中所有的宏进行展开,可以发现:

1

G_DEFINE_TYPE (MyFile, my_file, G_TYPE_OBJECT);

的展开代码为:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

static void my_file_init (MyFile * self);

static void my_file_class_init (MyFileClass * klass);

static gpointer my_file_parent_class = ((void *) 0);

 

static void

my_file_class_intern_init (gpointer klass)

{

    my_file_parent_class = g_type_class_peek_parent (klass);

    my_file_class_init ((MyFileClass *) klass);

}

 

GType

my_file_get_type (void)

{

    static volatile gsize g_define_type_id__volatile = 0;

    if (g_once_init_enter (&g_define_type_id__volatile)) {

        GType g_define_type_id =

            g_type_register_static_simple (((GType) ((20) << (2))),

                           g_intern_static_string

                           ("MyFile"),

                           sizeof (MyFileClass),

                           (GClassInitFunc)

                           my_file_class_intern_init,

                           sizeof (MyFile),

                           (GInstanceInitFunc)

                           my_file_init,

                           (GTypeFlags) 0); { { {

        };

        }

        }

        g_once_init_leave (&g_define_type_id__volatile,

                   g_define_type_id);

    }

    return g_define_type_id__volatile;

};

可以看出 my_file_parent_class 是一个静态的全局指针,它在 my_file_class_intern_init 函数中指向 MyFile 类的父类结构体。另外,还可以看出 MyFile 类的类结构体初始化函数 my_file_class_init 是由 my_file_class_intern_init 函数调用的,而后者会被 g_object_new 函数调用。

在 my_file_class_init 函数调用之前,将 MyFile 类的父类结构体的地址保存为 my_file_parent_class 指针是有用的。因为我们在 MyFile 类的类结构体初始化函数 my_file_class_init 中覆盖了 MyFile 类所继承的父类结构体的 dispose 与 finaliz 方法:

1

2

3

4

5

6

7

8

9

10

11

static

void my_file_class_init (MyFileClass *klass)

{

        g_type_class_add_private (klass, sizeof (MyFilePrivate));

          

        GObjectClass *base_class = G_OBJECT_CLASS (klass);

        ... ... ...

        base_class->dispose      = my_file_dispose;

        base_class->finalize     = my_file_finalize;

        ... ... ...

}

而在 MyFile 对象的 dispose 与 finalize 函数中,我们需要将对象的析构向上回溯到其父类,这时如果直接从 MyFile 类的类结构体中提取父类结构体,那么就会出现 MyFile 对象的 dispose 与 finalize 函数的递归调用。由于预先保存了 MyFile 类的父类结构体地址,那么就可以保证回溯析构的顺利进行。

其实,我们做错了!?

但是 James Henstridge 的约定,不仅仅是要保证 dispose 函数可被多次执行,还要保证在 dispose 函数执行之后并且在 finalize 函数执行之前,程序不会出错。这意味着 dispose 函数不能影响对象的行为(方法)。

无论 MyFIle 类对象的 my_file_dispose 函数还是 GObject 手册中的 maman_bar_dispose 函数的实现,都不符合上述约定。

在 my_file_dispose 函数中,我们不仅释放了 GIOChannel 类型指针 file 所指向的内存区域,还消除了野指针。那么在执行 my_file_dispose 函数之后,显然所有要使用 file 指针的 MyFile 类对象的方法都会出现段错误。同理,maman_bar_dispose 函数也违背了 James Henstridge 的约定。

所以,在 MyFIle 类的设计中 my_file_dispose 函数应当是一个空函数,GObject 手册中的 maman_bar_dispose 函数也应当如此。

对于 GObject 子类对象的哪些属性应当在 dispose 函数中解除引用,哪些属性应当在 finalize 函数中进行资源释放,全面的判定准则就是:既要允许 dispose 函数可重复执行,还要不影响对象的方法。

因此,James Henstridge 的约定跟废话也差不了多少。因为在 dispose 函数中解除任何一个属性的引用都有可能破坏对象的方法!

转载时,希望不要链接文中图片,另外请保留本文原始出处:http://garfileo.is-programmer.com

GROMACS新手必看:从PDB文件到完整分子动力学模拟的保姆级教程 本文提供GROMACS分子动力学模拟的保姆级教程,从PDB文件处理到完整模拟流程全覆盖。详细讲解结构预处理、系统构建、能量最小化、生产模拟等关键步骤,并分享性能优化和结果分析技巧,帮助新手快速掌握分子动力学模拟的核心操作。 阅读详情

相关推荐

AMD显卡跑Ollama大模型?手把手教你搞定Windows下GPU识别与加速(以RX 9600XT为例)

本文详细指导如何在Windows系统下使用AMD显卡(如RX 9600XT)运行Ollama大模型,解决GPU识别与加速问题。通过获取非官方Ollama版本、替换ROCm库文件等步骤,实现高效的GPU加速推理,提升大语言模型的运行效率。

weixin_28707365的博客 481

GObject基本用法

GObject基本用法 GObject为C语言提供了面向对象支持 安装:sudo apt install libglib2.0-dev GObject模拟类的封装 为数据类型名称添加一些前缀(PT格式:P——Program,T——数据类型),模拟命名空间 所谓数据封装,就是将低层次的元素组合起来,形成新的、高层次实体的技术 纯C语言实现双向链表: #ifndef _PROGRAM_LINKEDLIST #define _PROGRAM_LINKEDLIST typedef struct _Program_

私のBookShelf 1233

企业微信群机器人配置全攻略:从零到消息推送的完整流程

本文详细介绍了企业微信群机器人的配置与使用全流程,从零开始指导如何创建机器人、获取Webhook地址,到通过HTTP请求发送文本、Markdown、图片及模板卡片等多种消息类型。内容涵盖核心的接口配置、安全实践及实战应用场景,帮助开发与运维团队快速构建自动化消息推送中枢,提升协作效率。

weixin_29231725的博客 842

GObject 学习笔记汇总---11

转自: http://garfileo.is-programmer.com/2011/3/22/gobject-deconstruction.25485.html GObject 子类对象的析构过程 在“GObject 的信号机制”文中,谈到 GObject 子类对象的析构过程分为两个阶段,第一阶段是 dispose,第二阶段是 finalize。之所以划分成两个阶段而不是一步到位

吾皇的博客 1393

网络抓包实战:如何捕获与解析802.1Q VLAN标签报文

在网络通信中,数据包是信息传输的基本单元,而VLAN(虚拟局域网)技术通过在数据链路层插入802.1Q标签,实现了网络流量的逻辑隔离与高效管理。其核心原理是在标准以太网帧头中嵌入4字节的VLAN标识,使交换机能够根据VID(VLAN ID)进行精准转发。掌握VLAN报文的捕获与解析技术,对于网络故障排查、安全审计和性能优化具有重要价值,尤其在需要验证网络隔离策略或诊断Trunk链路异常时。本文聚焦于使用Wireshark工具,结合端口镜像等实操方法,详细演示如何抓取并解读携带802.1Q标签的原始报文,帮助

weixin_33417488的博客 382

解决VMWare ESXi PCIe直通显卡导致的DevicePowerOn启动故障

本文详细解析了VMWare ESXi中PCIe直通显卡导致的DevicePowerOn启动故障,重点分析了MMIO空间不足的根本原因,并提供了完整的解决方案。通过修改.vmx文件中的关键参数,如pciPassthru.64bitMMIOSizeGB,可以有效解决显存分配问题。文章还涵盖了硬件兼容性检查、性能调优技巧及大规模部署的实战案例,帮助用户彻底解决显卡直通难题。

weixin_42537919的博客 575

Gobject tutorial 八

如果这是最后一个对对象B的引用,那么A释放对B的引用,会导致unref 函数执行对象B的dispose, 进而导致B对象释放对对象A的引用,如果这也是对对象A的最后一个引用,对象B对对象A的引用的释放会导致第二次执行A的dispose。既然在注册属性过程中,GparamSpec是必须的,那么,就有必要对生成GParamSpec的函数进行说明,我们以上例中的g_param_spec_float为例,看看Glib的说明。对于不同的对象实例,属性值是不同的,因此,属性值是存储在对象的实例中的。

编程是一门艺术 969

自然二进制数与格雷码的相互转换

自然二进制数与格雷码两者优势: 自然二进制数的编码方式简单明了,容易理解,在加减运算中能够直接进行,同时十分方便进行一些位运算操作(如移位、取反等)。 格雷码计数时只有一位变化,可有效减少计数器状态的冗余转换,同时在传输数据时能够减小传输错误的概率,此外带权重编码处理更加方便。 在一定程度上自然二进制数与格雷码优缺点基本相反,综上所述,自然二进制数和格雷码各有优劣之处,需要根据具体应用场景选择合适的编码方式。简单来说,在计数器和编码器中,倾向于使用格雷码;而在进行加减运算时,则倾向于使用自然二进制数。

Loudrs的博客 7493

GObject内存管理模型

本文来自于GObject Reference Manual.GObject的内存管理想法上很简单,但API稍显复杂:目的是提供一个基于引用计数(Reference Counting)可用于不同内存管理模型(如,GC)的灵活模型。函数g_object_ref/g_object_unref用于对一个GObject增加或减少引用计数。引用计数由g_object_new赋初值,即当前调用者为仅有的GObj

认真你就输了 3219

RK3566/RK3568 Android 11添加系统服务

【代码】RK3566/RK3568 Android 11添加系统服务。

qq_23921815的博客 641

基于PPT的三维光路结构示意图绘制实例演示-技术细节

基于PPT的三维光路结构示意图绘制实例演示-技术细节

简单光学 7468

GObject 简明教程(二)

最近,我一直在深入学习 GStreamer(相关教程可以从我主页中看到)。在探索其复杂的设计逻辑时,我意识到需要深入研究 GStreamer 的源码。而因为 GStreamer 是基于 GObject 开发的,掌握 GObject 的基本概念就显得尤为重要。本文整理自,简化了细节,保留了一些关键内容,以便更好地理解。上一章GObject 简明教程(一)我们介绍了的前面五章。今天我们继续,将后面几章也进行总结和更新。

记录学习的过程 959

【nvidia-B200 生产环境】NVIDIA 570.124.06+Cuda12.8 Ubuntu22.04 nccl-test 一键部署脚本(免修改复制即用)

目录1. 初始化与日志记录2. 安装基础工具与配置更新3. NVIDIA 驱动安装 570.124.064. 安装 Mellanox OFED 24.10-2.1.8.05. 安装 CUDA 12.86. 安装 NCCL 和测试7. 配置 rc.local 和其他优化8. B200 单独步骤9. 最终测试与重启10. 完整生产脚本,复制即可直接使用总结 功能: 设置日志目录和日志文件路径。 使用 命令将标准输出和错误输出同时写入日志文件和终端。 记录脚本开始时间,并计算开始的秒数

jundao1997的专栏 2797

如何定义和实现新的GObject之对象构造和析构

1、对象构造 在尝试构建自己的GObjects时人们常常会感到困惑,因为它们有很多不同的方法来实现对象的构造过程:很难确定哪个是正确的方法。 表4中,“g_object_new”显示了在对象实例化过程中调用的用户提供的函数以及它们被调用的顺序。instance_init函数相当于C++中的构造函数。在所有父节点的instance_init函数都被调用后子类的instance_init都将被调用

lp525110627的博客 1327

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

GObject对象系统(7) 定义和实现一个新的GObject

How to define and implement a new GObject Boilerplate header code Boilerplate code Obje...

chudaiao7567的博客 1343

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

创建GObject子类的基本步骤

创建GObject子类的基本步骤: 在 .h 文件中包含 glib-object.h; #include 在 .h 文件中构建实例结构体与类结构体,并分别将 GObject 类的实例结构体与类结构体置于成员之首 typedef struct _ProjectObject { GObject parent_instance; //first el

fantasy666666的专栏 858

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

函数指针、回调函数与 GObject 闭包 GObject 子类对象的析构过程 GObject 的信号机制——概览

原文地址:http://garfileo.is-programmer.com/2011/3/21/gobject-signal.25477.html Garfileo posted @ 2011年3月21日 20:16 in GObject 笔记 with tags glib GObject gsignal , 3894 阅读 手册所述,GObject 信号(Gigna

yazhouren的专栏 1529

GObject 简明教程(一)

最近,我一直在深入学习 GStreamer(相关教程可以从我主页中看到)。在探索其复杂的设计逻辑时,我意识到需要深入研究 GStreamer 的源码。而因为 GStreamer 是基于 GObject 开发的,掌握 GObject 的基本概念就显得尤为重要。本文整理自,简化了细节,保留了一些关键内容,以便更好地理解。提示:以下是本篇文章正文内容,下面案例可供参考。

记录学习的过程 2297

GObject入门(一)类和实例

GObject入门

paw5zx的博客 1149

Gobject子类的定义/注册/实现

定义 GObject 的子类instance 结构:包含于类的实例相关的域,相当于 C++ 中的非静态公共成员。class 结构:包含的域相当于 C++ 中的静态公共成员。私有成员在哪里定义?与 C++ 不同,私有成员不是直接定义在类的声明中的(你甚至找不到一个到私有数据的指针)。GObject 的私有数据是在 class 结构初始化的时候,通过调用 g_typ_class_...

weixin_34269583的博客 236

GObject 子类对象的私有属性模拟

上一篇文章“使用 GObject 库模拟类的数据封装形式”讲述了 GObject 子类化过程,本文以其为基础,进一步讲述如何对数据进行隐藏,即对面向对象程序设计中的“私有属性”概念进行模拟。 非类类型数据的隐藏 第一个问题,可以称之为非类类型数据结构的隐藏,因为 PMDListNode 是普通的 C 结构体。隐藏这个结构体成员的方法有多种。 第一种方法尤为简单,如下:

gjioui的博客 264

GObject对象系统(4) GObject基类

 The previous chapter discussed the details of GLib's Dynamic Type System. The GObject library also contains an implementation for a base fund...

chudaiao7567的博客 485

GObject对象系统(5) 对象内存管理

 Object memory management The memory-management API for GObjects is a bit complicated but the idea behind it is pretty simple: the...

chudaiao7567的博客 885

Gobject 学习总结

简单的来说,GObject是一个程序库,它可以帮助我们使用C语言编写面向对象的程序。 很多人被灌输了这样一种概念:要写面向对象程序,那么就需要学习一种面向对象编程语言,例如C++、Java、C# 等等,而 C 语言是用来编写结构化程序的。事实上,面向对象只是一种编程思想,不是一种编程语言。换句话说,面向对象是一种游戏规则,它不是游戏。GObject 告诉我们,使用 C 语言编写程序时,可以运用面向...

chen_jianjian的专栏 5021

[Glib] GObject 的 dispose 和 finalize 成员函数的各自作用

GObject学习教程---第十一章:GObject 子类对象的析构过程_knowledgebao的博客-优快云博客索引:https://blog.youkuaiyun.com/knowledgebao/article/details/84633798本文是学习学习他人的博客的心得(具体详见“楼主见解”),如果源网站可访问的话,建议直接访问源网站:楼主见解:主要讲解析构为什么需要2个函数来实现。讲解了dispose和finalize的使用场景。析构函数末尾必须调用基类的对应析构函数。James Henstr...ht

ykun089的博客 695

Gobject专栏索引

索引首页:https://blog.youkuaiyun.com/knowledgebao/article/details/84776046 官网API:https://developer.gnome.org/gobject/stable/ gobject相关概念:https://blog.youkuaiyun.com/knowledgebao/article/details/82498187 第一章:GObjec...

knowledgebao的博客 7528
上一篇: GObject学习教程---第十章:GObject 的信号机制——概览
下一篇: GObject学习教程---第十二章:GObject 信号机制——信号注册
knowledgebao
博客等级 码龄15年 401粉丝 198原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值