GObject基类

GObject基类
前一章讨论了GLib动态类型系统的细节。GObject库还包含一个名为GObject的基本类型的实现。
GObject是一个基本的类实例化类型。 它实现:
(1)内存管理引用计数
(2)实例的构造/析构
(3)具有set/get函数对的通用每个对象属性
(4)轻松使用信号
所有使用GLib类型系统的GNOME库(如GTK +和GStreamer)都继承自GObject,因此了解其工作原理很重要。
1、对象实例化
g_object_new系列函数可用于实例化从GObject基类型继承的任何GType。 所有这些功能确保类和实例结构已由GLib的类型系统正确初始化,然后在一个或多个调用构造函数类方法中调用,该方法用于:
(1)通过g_type_create_instance分配和清除内存。
(2)使用构造属性初始化对象的实例。
虽然可以预期所有的类和实例成员(指向父母的字段除外)被设置为零,但有些人认为明确设置它们是良好的做法。一旦所有构造操作已经完成并且构造函数属性设置好,就调用类的构造函数。
从GObject继承的对象运行覆盖构造函数。 下面的示例显示了ViewerFile如何覆盖父构造过程:
#define VIEWER_TYPE_FILE viewer_file_get_type ()
G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)

struct _ViewerFile
{
  GObject parent_instance;

  /* instance members */
};

/* will create viewer_file_get_type and set viewer_file_parent_class */
G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)

static void
viewer_file_constructed (GObject *obj)
{
  /* update the object state depending on constructor properties */

  /* Always chain up to the parent constructed function to complete object
   * initialisation. */
  G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj);
}

static void
viewer_file_class_init (ViewerFileClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->constructed = viewer_file_constructed;
}

static void
viewer_file_init (ViewerFile *self)
{
  /* initialize the object */
}
如果用户使用以下方式实例化一个对象ViewerFile:
ViewerFile * file = g_object_new(VIEWER_TYPE_FILE,NULL);
如果这是这个对象的第一个实例,那么在任何一个viewer_file_base_class_init函数之后,将会调用viewer_file_class_init函数。这将确保新对象的类结构正确初始化。在这里viewer_file_class_init预计会覆盖对象的类方法并设置类自己的方法。在上面的例子中,
构造方法是唯一被重写的方法:它被设置为viewer_file_constructor。
一旦g_object_new获得对初始化类结构的引用,将调用其构造函数来创建新对象的实例。如果构造函数在viewer_file_class_init中被覆盖了,重写的构造函数必须链接到其父构造函数。为了找到父类并链接到父类构造函数,我们可以使用由G_DEFINE_TYPE宏为我们设置的viewer_file_parent_class指针。最后,在某一点上,g_object_constructor由链中的最后一个构造函数调用。此函数通过g_type_create_instance分配对象的实例缓冲区,这意味着如果instance_init函数指针已注册,此时将调用instance_init函数。在instance_init返回后,对象被完全初始化,应该准备好让用户调用它的任何方法。g_type_create_instance返回时,g_object_constructor设置构造属性(即赋予g_object_new的属性)并返回给用户的构造函数。
上面描述的过程可能看起来有点复杂,但是可以通过下表轻松地总结出g_object_new调用的函数及其调用顺序:
Invocation time Function invoked Function's parameters Remark
First call to g_object_newfor target type target type's base_initfunction On the inheritance tree of classes from fundamental type to target type.base_init is invoked once for each class structure. Never used in practice. Unlikely you will need it.
target type's class_initfunction On target type's class structure Here, you should make sure to initialize or override class methods (that is, assign to each class' method its function pointer) and create the signals and the properties associated to your object.
interface's base_initfunction On interface's vtable  
interface's interface_initfunction On interface's vtable  
Each call to g_object_newfor target type target type's class constructormethod: GObjectClass->constructor On object's instance If you need to handle construct properties in a custom way, or implement a singleton class, override the constructor method and make sure to chain up to the object's parent class before doing your own initialization. In doubt, do not override the constructor method.
type's instance_initfunction On the inheritance tree of classes from fundamental type to target type. the instance_init provided for each type is invoked once for each instance structure. Provide an instance_init function to initialize your object before its construction properties are set. This is the preferred way to initialize a GObject instance. This function is equivalent to C++ constructors.
target type's class constructedmethod: GObjectClass->constructed On object's instance If you need to perform object initialization steps after all construct properties have been set. This is the final step in the object initialization process, and is only called if the constructor method returned a new object instance (rather than, for example, an existing singleton).

读者应该关心调用函数顺序的一点点变化:在技术上,类的构造函数在GType的instance_init函数之前被调用(因为g_type_create_instance调用instance_init是由用户希望链接到的顶级类g_object_constructor调用的构造函数方法),用户提供的构造函数将始终在GType的instance_init函数之后运行,因为用户提供的构造函数在执行之前必须被链接。

2、对象内存管理

用于GObjects内存管理的API有点复杂,但它背后的想法很简单:目的是提供一个基于引用计数的灵活模型,可以集成到使用或需要不同内存管理模型的应用程序(如垃圾 采集)。 下面描述用于操纵该引用计数的方法。

3、引用计数
函数g_object_ref / g_object_unref分别增加和减少引用计数。这些功能是线程安全的。g_object_unref用来清除传递给他的对象指针 ,g_clear_object是更为方便使用的g_object_unref的封装。引用计数由g_object_new初始化为1,这意味着调用者当前是新创建此对象的唯一所有者。当引用计数达到0时,也就是说,该对象的最后一个引用调用g_object_unref,将调用dispose和finalize类方法。最后,调用finalize之后将会调用g_type_free_instance来释放对象实例。根据注册类型决定的内存分配策略(通过g_type_register_ *函数之一)对象的实例内存将被释放或返回到此类型的对象池。一旦对象被释放,如果它是该类型的最后一个实例则该类型的类结构体将按照“Instantiable classed types:objects”一节和“非实例化类类型:interfaces”一节所述被销毁。
下表总结了GObject的销毁过程:

Invocation time Function invoked Function's parameters Remark
Last call to g_object_unreffor an instance of target type target type's dispose class function GObject instance When dispose ends, the object should not hold any reference to any other member object. The object is also expected to be able to answer client method invocations (with possibly an error code but no memory violation) until finalize is executed. dispose can be executed more than once. dispose should chain up to its parent implementation just before returning to the caller.
target type's finalize class function GObject instance Finalize is expected to complete the destruction process initiated by dispose. It should complete the object's destruction. finalize will be executed only once. finalize should chain up to its parent implementation just before returning to the caller. The reason why the destruction process is split is two different phases is explained in the section called “Reference counts and cycles”.
Last call to g_object_unreffor the last instance of target type interface's interface_finalizefunction On interface's vtable Never used in practice. Unlikely you will need it.
interface's base_finalizefunction On interface's vtable Never used in practice. Unlikely you will need it.
target type's class_finalizefunction On target type's class structure Never used in practice. Unlikely you will need it.
type's base_finalizefunction On the inheritance tree of classes from fundamental type to target type.base_init is invoked once for each class structure. Never used in practice. Unlikely you will need it.
4、弱引用
弱引用用于监视对象的finalization:g_object_weak_ref添加一个监视回调函数,该回调函数不会拥有对象的引用,但是当对象运行其dispose方法时会调用该回调。 因此,每个弱引用可以在对象finalization时被多次调用(因为 dispose可以在对象finalization期间运行多次)。g_object_weak_unref可用于从对象中删除监视回调。
弱引用也可以用g_object_add_weak_pointer和g_object_remove_weak_pointer实现。 这些函数为它们应用的对象添加了一个弱引用,确保在对象被定义时,使用户给定的指针无效。

类似地,上面函数不是线程安全的,如果需要线程安全性,可以使用GWeakRef。

5、参考计数和循环
GObject的内存管理模型旨在轻松集成到使用垃圾收集的现有代码中。这就是为什么销毁过程分为两个阶段:第一阶段执行dispose,释放对其他成员对象的所有引用。第二阶段执行finalize,完成对象的销毁过程。对象方法应该能够在两个阶段之间运行而没有程序错误。
这两步破坏过程对于打破引用计数循环非常有用。虽然循环的检测取决于外部代码,一旦检测到循环,外部代码可以调用g_object_run_dispose,这将确实会破坏任何现有的循环,因为它将调用对象关联的dispose,并且释放所有对其他对象的引用。
这解释了前面提到的dispose的规则之一:dispose可以被多次调用。假设我们有一个引用计数循环:对象A引用了对象B而对象B又引用了对象A。假设我们已经检测到这个循环,并且我们想要破坏这两个对象。一种方法是在其中一个对象上调用g_object_run_dispose。
如果对象A释放其对所有对象的所有引用,这意味着它释放对对象B的引用。如果对象B不再有其他任何对象引用,则这是其最后一个引用计数,这意味着这是最后一个unref运行B的dispose程序。反过来,释放B对A的引用。如果这是A的最后一个引用计数,最后一个unref会运行A的dispose程序,该处理程序在A的finalize处理程序被调用之前第二次运行!
如果通过语言绑定来处理GObjects,那么上述的例子可能会有所改变,因此,应该严格遵守对象破坏的规则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值