十六、GObject类用法总结
基于前面知识,我们知道GObject是静态类对象,可以创建N个实例,但是只会创建一个类结构体对象。
比如常用 GObjectClass
里面的:
-
类里面函数指针,可以做信号的默认处理函数(指向默认处理函数)
-
子类可以重写父类里面的函数指针(指向的处理函数),进而实现多态。
-
子类也可以调用父类的函数指针。
1 对象初始化过程分析
1.1 区分不同父类内存区域
需要主要两部分内存空间:一是父类自身占用的内存空间,另一个是子类复制父类部分的内存空间比如 GtkWIdget
:
-
GTK_WIDGET_GET_CLASS
得到的是自身拷贝父类部分的内存空间。(这部分有些数据已经被 gtk_widget_class_init函数修改) -
gtk_widget_parent_class
父类的内存部分。(不会被子类修改,两个类是独立的)
1.2 分析初始化过程
-
父类(类结构体)区域直接拷贝(不会调用父类class_init初始化函数),然后调用该对象的类初始化函数 class_init 。
-
实例(结构体),不是直接拷贝父类实例结构体区别,而且调用父类实例结构体初始化函数。
2 对象销毁过程分析
2.1 区分两种销毁函数
g_object_unref
解引用到零的时候执行会先调用dispose,再finalize:
-
G_OBJECT_GET_CLASS (object)->dispose (object);
,这部分应该释放一些对其他对象的引用,释放信号连接等操作。可以参考GtkWidget
。 -
G_OBJECT_GET_CLASS (object)->finalize (object);
,这部分应该释放相关变量的内存。可以参考GtkWidget
。
通过比较查看 g_object_unref
函数发现,dispose中可以重新对对象进行引用,使得最终不会调用finalize函数。finalize
只用被调用完成后,实例结构体的内存就会被释放。
2.2 链式释放分析
先执行完该对象的finalize,最后会执行父类的->finalize,依次链式执行。
3 对象属性注册与设置分析
3.1 每个类都会有相关的设置和得到属性函数
属性都是注册在 GobjectClass
里面,因为属性是 Gobject
对象具备的功能。虽然图中可以看到,每次继承,都会修改类中, GobjectClass
(自己类拷贝的区域)的设定属性和得到属性部分。
3.2 如何对应到每个类,使用相应的设置属性函数
是否继承了父类的属性:
答:继承了父类的属性。那既然继承了父类的属性,设定属性和得到属性函数,每个类对应的函数都不一样,系统是如何区分的??
如何区别一个类中,属性是继承于那个对象: