如何定义和实现新的GObject之对象构造和析构
2017-05-12 16:44
1211 查看
1、对象构造
在尝试构建自己的GObjects时人们常常会感到困惑,因为它们有很多不同的方法来实现对象的构造过程:很难确定哪个是正确的方法。
表4中,“g_object_new”显示了在对象实例化过程中调用的用户提供的函数以及它们被调用的顺序。instance_init函数相当于C++中的构造函数。在所有父节点的instance_init函数都被调用后子类的instance_init都将被调用。它不能随意的传递构造参数(如C ++中),但是如果您的对象需要任意参数来完成初始化,则可以使用构造属性。
只有在所有的instance_init函数都运行之后,才能设置构造属性。在所有构造属性设置完成之前,不会将对象引用返回给g_object_new的客户端。
重要的是要注意对象构造不能失败。如果您需要一个可能会失败的GObject构造,则可以使用GIO库提供的GInitable和GAsyncInitable接口。
首先应当实现如下代码:
属性ID必须从1开始,因为0被保留供GObject内部使用。
有些人有时需要在传递给构造函数的属性设置完成之后才能完成类型实例的初始化。 这可以通过使用在对象实例化”的部分中描述的constructor()类方法,或者更简单地说,使用compiled()类方法。 请注意,仅在属性标记为G_PARAM_CONSTRUCT_ONLY或G_PARAM_CONSTRUCT时才会调用compiled()虚函数,且调用发生在传递给g_object_new()的常规属性设置之前。
2、对象析构
同样,通常很难弄清楚使用哪种机制来实现对象的销毁过程:当最后一次g_object_unref函数调用时,会发生许多事情,如表5“g_object_unref”所述。
您的对象的销毁过程分为两个阶段:dispose和finalize。由于GObject使用的参考计数机制的性质以及销毁序列中的信号发射情况下的临时复现情况,这种分成两个阶段的方法是处理潜在周期的必要条件。有关详细信息,请参阅“引用计数和循环”一节。
在尝试构建自己的GObjects时人们常常会感到困惑,因为它们有很多不同的方法来实现对象的构造过程:很难确定哪个是正确的方法。
表4中,“g_object_new”显示了在对象实例化过程中调用的用户提供的函数以及它们被调用的顺序。instance_init函数相当于C++中的构造函数。在所有父节点的instance_init函数都被调用后子类的instance_init都将被调用。它不能随意的传递构造参数(如C ++中),但是如果您的对象需要任意参数来完成初始化,则可以使用构造属性。
只有在所有的instance_init函数都运行之后,才能设置构造属性。在所有构造属性设置完成之前,不会将对象引用返回给g_object_new的客户端。
重要的是要注意对象构造不能失败。如果您需要一个可能会失败的GObject构造,则可以使用GIO库提供的GInitable和GAsyncInitable接口。
首先应当实现如下代码:
G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) static void viewer_file_class_init (ViewerFileClass *klass) { } static void viewer_file_init (ViewerFile *self) { ViewerFilePrivate *priv = viewer_file_get_instance_private (self); /* initialize all public and private members to reasonable default values. * They are all automatically initialized to 0 to begin with. */ }如果需要特殊的构造属性(使用G_PARAM_CONSTRUCT_ONLY设置),请在class_init()函数中安装属性函数覆盖GObject类的set_property()和get_property()方法,并按照“对象属性”一节所述实现它们。
属性ID必须从1开始,因为0被保留供GObject内部使用。
enum { PROP_FILENAME = 1, PROP_ZOOM_LEVEL, N_PROPERTIES }; static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; static void viewer_file_class_init (ViewerFileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = viewer_file_set_property; object_class->get_property = viewer_file_get_property; obj_properties[PROP_FILENAME] = g_param_spec_string ("filename", "Filename", "Name of the file to load and display from.", NULL /* default value */, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE)); obj_properties[PROP_ZOOM_LEVEL] = g_param_spec_uint ("zoom-level", "Zoom level", "Zoom level to view the file at.", 0 /* minimum value */, 10 /* maximum value */, 2 /* default value */, G_PARAM_READWRITE)); g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); }如果需要,请确保您可以构建和运行与上述代码相似的代码。 此外,确保您的构造属性可以在构造期间被设置且没有其他不好的影响。
有些人有时需要在传递给构造函数的属性设置完成之后才能完成类型实例的初始化。 这可以通过使用在对象实例化”的部分中描述的constructor()类方法,或者更简单地说,使用compiled()类方法。 请注意,仅在属性标记为G_PARAM_CONSTRUCT_ONLY或G_PARAM_CONSTRUCT时才会调用compiled()虚函数,且调用发生在传递给g_object_new()的常规属性设置之前。
2、对象析构
同样,通常很难弄清楚使用哪种机制来实现对象的销毁过程:当最后一次g_object_unref函数调用时,会发生许多事情,如表5“g_object_unref”所述。
您的对象的销毁过程分为两个阶段:dispose和finalize。由于GObject使用的参考计数机制的性质以及销毁序列中的信号发射情况下的临时复现情况,这种分成两个阶段的方法是处理潜在周期的必要条件。有关详细信息,请参阅“引用计数和循环”一节。
struct _ViewerFilePrivate { gchar *filename; guint zoom_level; GInputStream *input_stream; }; G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) static void viewer_file_dispose (GObject *gobject) { ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); /* In dispose(), you are supposed to free all types referenced from this * object which might themselves hold a reference to self. Generally, * the most simple solution is to unref all members on which you own a * reference. */ /* dispose() might be called multiple times, so we must guard against * calling g_object_unref() on an invalid GObject by setting the member * NULL; g_clear_object() does this for us. */ g_clear_object (&priv->input_stream); /* Always chain up to the parent class; there is no need to check if * the parent class implements the dispose() virtual function: it is * always guaranteed to do so */ G_OBJECT_CLASS (viewer_file_parent_class)->dispose (gobject); } static void viewer_file_finalize (GObject *gobject) { ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); g_free (priv->filename); /* Always chain up to the parent class; as with dispose(), finalize() * is guaranteed to exist on the parent's class virtual function table */ G_OBJECT_CLASS (viewer_file_parent_class)->finalize (gobject); } static void viewer_file_class_init (ViewerFileClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = viewer_file_dispose; object_class->finalize = viewer_file_finalize; } static void viewer_file_init (ViewerFile *self); { ViewerFilePrivate *priv = viewer_file_get_instance_private (self); priv->input_stream = g_object_new (VIEWER_TYPE_INPUT_STREAM, NULL); priv->filename = /* would be set as a property */; }在dispose运行之后finalize运行之前,可能会调用对象方法。 GObject不认为这是一个程序错误:您必须能够正常检测到这一点,既不会崩溃也不会警告用户,通过使一个被dispose的实例恢复到惰性状态。
相关文章推荐
- 如何定义和实现新的GObject之对象方法
- 斗地主算法的设计与实现(一)--项目介绍&如何定义和构造一张牌
- 【面向对象程序设计常见面试题】如何定义和实现一个类的成员函数为回调函数?
- 斗地主算法的设计与实现(一)--项目介绍&如何定义和构造一张牌
- [置顶] 斗地主算法的设计与实现--项目介绍&如何定义和构造一张牌
- 斗地主算法的设计与实现(一)--项目介绍&如何定义和构造一张牌
- 子函数中定义静态类的对象(还不错哦)(注意区别,析构与构造在子函数中的行为)
- 斗地主算法的设计与实现--项目介绍&如何定义和构造一张牌
- 创建Employee类,在类中定义三个属性:编号,姓名,年龄,然后在构造方法里初始化这三个属性,最后载实现接口中的定义的CompareTo方法,将对象按编号升序排列。根据已有的代码,补全程序。
- 如何定义和实现新的GObject之代码实现
- C++如何实现只能动态分配类对象,不能定义类对象
- 斗地主算法的设计与实现(一)--项目介绍&如何定义和构造一张牌
- 斗地主算法的设计与实现(一)--项目介绍&如何定义和构造一张牌
- 构造方法、析构方法是如何定义的
- GObject 参考手册:教程:如何定义和实现接口
- JSP页面如何访问标签中定义的变量-使用实现
- 类的构造,析构,临时对象与函数参数的关系
- 临时对象的构造与析构
- 用CRTP实现类定义对象的计数器
- 如何实现操作系统内对象只实例化一次