Gobject tutorial 七

The GObject base class

GObject是一个fundamental classed instantiatable type,它的功能如下:

  • 内存管理
  • 构建/销毁实例
  • set/get属性方法
  • 信号
/*** GObjectClass:* @g_type_class: the parent class* @constructor: the @constructor function is called by g_object_new () to *  complete the object initialization after all the construction properties are*  set. The first thing a @constructor implementation must do is chain up to the*  @constructor of the parent class. Overriding @constructor should be rarely *  needed, e.g. to handle construct properties, or to implement singletons.* @set_property: the generic setter for all properties of this type. Should be*  overridden for every type with properties. If implementations of*  @set_property don't emit property change notification explicitly, this will*  be done implicitly by the type system. However, if the notify signal is*  emitted explicitly, the type system will not emit it a second time.* @get_property: the generic getter for all properties of this type. Should be*  overridden for every type with properties.* @dispose: the @dispose function is supposed to drop all references to other *  objects, but keep the instance otherwise intact, so that client method *  invocations still work. It may be run multiple times (due to reference *  loops). Before returning, @dispose should chain up to the @dispose method *  of the parent class.* @finalize: instance finalization function, should finish the finalization of *  the instance begun in @dispose and chain up to the @finalize method of the *  parent class.* @dispatch_properties_changed: emits property change notification for a bunch*  of properties. Overriding @dispatch_properties_changed should be rarely *  needed.* @notify: the class closure for the notify signal* @constructed: the @constructed function is called by g_object_new() as the*  final step of the object creation process.  At the point of the call, all*  construction properties have been set on the object.  The purpose of this*  call is to allow for object initialisation steps that can only be performed*  after construction properties have been set.  @constructed implementors*  should chain up to the @constructed call of their parent class to allow it*  to complete its initialisation.* * The class structure for the GObject type.* * |[<!-- language="C" -->* // Example of implementing a singleton using a constructor.* static MySingleton *the_singleton = NULL;* * static GObject** my_singleton_constructor (GType                  type,*                           guint                  n_construct_params,*                           GObjectConstructParam *construct_params)* {*   GObject *object;*   *   if (!the_singleton)*     {*       object = G_OBJECT_CLASS (parent_class)->constructor (type,*                                                            n_construct_params,*                                                            construct_params);*       the_singleton = MY_SINGLETON (object);*     }*   else*     object = g_object_ref (G_OBJECT (the_singleton));* *   return object;* }* ]|*/
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[3];
};/*** GObject:** The base object type.* * All the fields in the `GObject` structure are private to the implementation* and should never be accessed directly.** Since GLib 2.72, all #GObjects are guaranteed to be aligned to at least the* alignment of the largest basic GLib type (typically this is #guint64 or* #gdouble). If you need larger alignment for an element in a #GObject, you* should allocate it on the heap (aligned), or arrange for your #GObject to be* appropriately padded. This guarantee applies to the #GObject (or derived)* struct, the #GObjectClass (or derived) struct, and any private data allocated* by G_ADD_PRIVATE().*/
struct  _GObject
{GTypeInstance  g_type_instance;/*< private >*/guint          ref_count;  /* (atomic) */GData         *qdata;
};

Object instantiation

g_object_new()族能够实例化任何继承自GObject的GType。族中所有函数都能保证将类结构和实例结构在GLib的类型系统中正确初始化,之后会在某个时机调用类的constructor方法。

类的构造方法的作用如下:

  • 通过g_type_create_instance()函数分配并清空内存。
  • 使用构造属性初始化对象实例。
static GObject*
g_object_constructor (GType                  type,guint                  n_construct_properties,GObjectConstructParam *construct_params)
{GObject *object;/* create object */object = (GObject*) g_type_create_instance (type);/* set construction parameters */if (n_construct_properties){GObjectNotifyQueue *nqueue = g_object_notify_queue_freeze (object, FALSE);/* set construct properties */while (n_construct_properties--){GValue *value = construct_params->value;GParamSpec *pspec = construct_params->pspec;construct_params++;object_set_property (object, pspec, value, nqueue, TRUE);}g_object_notify_queue_thaw (object, nqueue);/* the notification queue is still frozen from g_object_init(), so* we don't need to handle it here, g_object_newv() takes* care of that*/}return object;
}

GObject能够确保所有类结构和实例结构的成员(除指向父结构的成员外)的值都被设置为0。

当所有构造相关的工作都完成,构造属性都被设置完成后,最后会调用constructed方法。

继承自GObject的对象都能重写类的constructed方法。举例如下:

#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 */char *filename;guint zoom_level;
};/* 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_finalize (GObject *obj)
{ViewerFile *self = VIEWER_FILE (obj);g_free (self->filename);/* Always chain up to the parent finalize function to complete object* destruction. */G_OBJECT_CLASS (viewer_file_parent_class)->finalize (obj);
}static void
viewer_file_class_init (ViewerFileClass *klass)
{GObjectClass *object_class = G_OBJECT_CLASS (klass);object_class->constructed = viewer_file_constructed;object_class->finalize = viewer_file_finalize;
}static void
viewer_file_init (ViewerFile *self)
{/* initialize the object */
}

 通过g_object_new(VIEWER_TYPE_FILE,NULL)的方式,第一次实例化ViewerFile对象时,会调用view_file_base_init函数,接着调用view_file_class_init函数。这样新对象的类结构就能够被初始化完成。

当g_object_new获取到新对象的初始化完成的类结构的索引之后,如果GObject的constructor函数被重写,那么,g_object_new函数将会调用新类型的类结构中constructor(如上例中的viewer_file_cosntructed,实际上也是新类ViewFileClass中GObject的constructor,这是因为,ViewFile是一个final类型对象)来创建新对象。

gpointer
g_object_new (GType	   object_type,const gchar *first_property_name,...)
{GObject *object;
....../* short circuit for calls supplying no properties */if (!first_property_name)return g_object_new_with_properties (object_type, 0, NULL, NULL);......return object;
}GObject *
g_object_new_with_properties (GType          object_type,guint          n_properties,const char    *names[],const GValue   values[])
{GObjectClass *class, *unref_class = NULL;GObject *object;
......class = g_type_class_peek_static (object_type);if (class == NULL)class = unref_class = g_type_class_ref (object_type);if (n_properties > 0){
......}elseobject = g_object_new_internal (class, NULL, 0);
......return object;
}static gpointer
g_object_new_internal (GObjectClass          *class,GObjectConstructParam *params,guint                  n_params)
{
......GObject *object;
......if G_UNLIKELY (CLASS_HAS_CUSTOM_CONSTRUCTOR (class))return g_object_new_with_custom_constructor (class, params, n_params);object = (GObject *) g_type_create_instance (class->g_type_class.g_type);......
}static gpointer
g_object_new_with_custom_constructor (GObjectClass          *class,GObjectConstructParam *params,guint                  n_params)
{
......GObject *object;....../* construct object from construction parameters */object = class->constructor (class->g_type_class.g_type, class->n_construct_properties, cparams);......
return object
}

Chaining up to its parent

在继承Gobject的新类型的初始化过程中,如上所述,会存在GObjectClass的constructor被用户改写的情况,那么,用户为新对象设置的constructor与GObjectClass的默认constructor之间是什么关系呢?

如下图所示:

 如图,有两个类结构,GObjectClass和TstrClass,两个类都有各自的finalize函数,TstrClass的finalize函数用于销毁Tstr 实例结构中与其本身相关的数据(不包含Tstr结构中其父结构GObjectClass中的数据),TStrClass的finalize函数在最后会调用其父类GObjectClass的finalize函数来销毁GObject中的数据。这期间有个函数调用关系,这个调用关系就是图示“chain up”的含义。

我们在gtk库中找个finalize函数来具体说明一下。

static void
gtk_print_backend_cups_finalize (GObject *object)
{GtkPrintBackendCups *backend_cups;GTK_DEBUG (PRINTING, "CUPS Backend: finalizing CUPS backend module");backend_cups = GTK_PRINT_BACKEND_CUPS (object);g_free (backend_cups->default_printer);backend_cups->default_printer = NULL;gtk_cups_connection_test_free (backend_cups->cups_connection_test);backend_cups->cups_connection_test = NULL;g_hash_table_destroy (backend_cups->auth);g_free (backend_cups->username);#ifdef HAVE_COLORDg_object_unref (backend_cups->colord_client);
#endifg_clear_object (&backend_cups->avahi_cancellable);g_clear_pointer (&backend_cups->avahi_default_printer, g_free);g_clear_object (&backend_cups->dbus_connection);g_clear_object (&backend_cups->secrets_service_cancellable);if (backend_cups->secrets_service_watch_id != 0){g_bus_unwatch_name (backend_cups->secrets_service_watch_id);}g_list_free_full (backend_cups->temporary_queues_in_construction, g_free);backend_cups->temporary_queues_in_construction = NULL;g_list_free_full (backend_cups->temporary_queues_removed, g_free);backend_cups->temporary_queues_removed = NULL;backend_parent_class->finalize (object);
}

 现在我们可以回到我们之前的问题,类似于finalize,constructor也有“chain up“的关系存在。

同样的,我们在gtk库中找一个constructor函数看看。

static GObject*
gtk_button_constructor (GType                  type,guint                  n_construct_properties,GObjectConstructParam *construct_params)
{GObject *object;GtkButton *button;object = (* G_OBJECT_CLASS (gtk_button_parent_class)->constructor) (type,n_construct_properties,construct_params);button = GTK_BUTTON (object);button->constructed = TRUE;if (button->label_text != NULL)gtk_button_construct_child (button);return object;
}

回到我们之前的话题,在初始化过程中,通过"chain up"会调用到g_object_constructor,只不过constructor的调用顺序与finalize相反。因为,我们需要g_object_constructor函数调用g_type_create_instance来为我们的新类型实例分配空间。同时,instance_init函数也会在此时执行。instance_init的返回,也意味这新类型的初始化过程完成。之后,用户就能使用新类型。

GTypeInstance*
g_type_create_instance (GType type)
{TypeNode *node;GTypeInstance *instance;GTypeClass *class;gchar *allocated;gint private_size;gint ivar_size;guint i;node = lookup_type_node_I (type);......class = g_type_class_ref (type);/* We allocate the 'private' areas before the normal instance data, in* reverse order.  This allows the private area of a particular class* to always be at a constant relative address to the instance data.* If we stored the private data after the instance data this would* not be the case (since a subclass that added more instance* variables would push the private data further along).** This presents problems for valgrindability, of course, so we do a* workaround for that case.  We identify the start of the object to* valgrind as an allocated block (so that pointers to objects show up* as 'reachable' instead of 'possibly lost').  We then add an extra* pointer at the end of the object, after all instance data, back to* the start of the private area so that it is also recorded as* reachable.  We also add extra private space at the start because* valgrind doesn't seem to like us claiming to have allocated an* address that it saw allocated by malloc().*/private_size = node->data->instance.private_size;ivar_size = node->data->instance.instance_size;......allocated = g_malloc0 (private_size + ivar_size);instance = (GTypeInstance *) (allocated + private_size);for (i = node->n_supers; i > 0; i--){TypeNode *pnode;pnode = lookup_type_node_I (node->supers[i]);if (pnode->data->instance.instance_init){instance->g_class = pnode->data->instance.class;pnode->data->instance.instance_init (instance, class);}}......instance->g_class = class;if (node->data->instance.instance_init)node->data->instance.instance_init (instance, class);return instance;
}

初始化流程如下表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/353871.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于单片机的智能窗户控制系统的设计

摘 要&#xff1a; 根据单片机技术和现代传感器技术 &#xff0c; 本文主要针对基于单片机的智能窗户控制系统的设计进行探讨 &#xff0c; 仅供参考 。 关键词&#xff1a; 单片机 &#xff1b; 智能窗户 &#xff1b; 控制系统 &#xff1b; 设计 在现代科学技术持续发展的带…

【精品方案】产业园区数字孪生规划方案(39页PPT)

引言&#xff1a;随着数字化和智能化技术的快速发展&#xff0c;传统产业园区面临着转型升级的重大机遇。数字孪生技术作为一种将物理世界与数字世界紧密结合的创新技术&#xff0c;为产业园区的规划、建设和运营管理提供了全新的解决方案。本方案旨在通过构建产业园区数字孪生…

Upload-Labs:Pass - 1(JS前端白名单)

Pass_1 1. 上传测试2. 代码审计**获取文件输入的值**&#xff1a;**检查是否选择了文件**&#xff1a;**定义允许的文件类型**&#xff1a;**提取文件的扩展名**&#xff1a;**检查文件类型是否允许上传**&#xff1a;**构建错误消息并提醒用户**&#xff1a; 3.绕过思路3.1 将…

集合系列(二十六) -利用LinkedHashMap实现一个LRU缓存

一、什么是 LRU LRU是 Least Recently Used 的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c;选择最近最久未使用的页面予以淘汰。 简单的说就是&#xff0c;对于一组数据&#xff0c;例如&#xff1a;int[] a {1,2,3,4,5,6}&#xff0c;…

一文带你读懂向量数据库(上)

大数据产业创新服务媒体 ——聚焦数据 改变商业 什么是向量数据库&#xff1f; 向量数据库的概述&#xff1a;向量数据库是一种数据库&#xff0c;专门设计用于存储和查询向量数据&#xff0c;常用于机器学习和数据科学领域。向量数据库可以高效地存储大规模的向量数据&#x…

STM32HAL库--NVIC和EXTI

1. 外部中断实验 1.1 NVIC和EXTI简介 1.1.1 NVIC简介 NVIC 即嵌套向量中断控制器&#xff0c;全称 Nested vectored interrupt controller。是ARM Cortex-M处理器中用于管理中断的重要组件。负责处理中断请求&#xff0c;分配优先级&#xff0c;并协调中断的触发和响应。 它是…

【千帆AppBuilder】你有一封邮件待查收|未来的我,你好吗?欢迎体验AI应用《未来信使》

我在百度智能云千帆AppBuilder开发了一款AI原生应用&#xff0c;快来使用吧&#xff01;「未来信使」&#xff1a;https://appbuilder.baidu.com/s/Q1VPg 目录 背景人工智能未来的信 未来信使功能介绍Prompt组件 千帆社区主要功能AppBuilderModelBuilder详细信息 推荐文章 未来…

Django REST framework数据展示技巧:分页、过滤与搜索的实用配置与实践

系列文章目录 Django入门全攻略&#xff1a;从零搭建你的第一个Web项目Django ORM入门指南&#xff1a;从概念到实践&#xff0c;掌握模型创建、迁移与视图操作Django ORM实战&#xff1a;模型字段与元选项配置&#xff0c;以及链式过滤与QF查询详解Django ORM深度游&#xff1…

k8s部署grafana beyla

k8s部署grafana beyla OS: Static hostname: test Icon name: computer-vm Chassis: vm Machine ID: 22349ac6f9ba406293d0541bcba7c05d Boot ID: 83bb7e5dbf27453c94ff9f1fe88d5f02 Virtualization: vmware Operating System: Ubuntu 22.04.4 LTS Kernel: Linux 5.15.0-105-g…

C#.Net筑基-类型系统①基础

C#.Net的BCL提供了丰富的类型&#xff0c;最基础的是值类型、引用类型&#xff0c;而他们的共同&#xff08;隐私&#xff09;祖先是 System.Object&#xff08;万物之源&#xff09;&#xff0c;所以任何类型都可以转换为Object。 01、数据类型汇总 C#.NET 类型结构总结如下图…

使用@Value注解无法成功获取配置文件内容,常见原因

在日常的java开发中&#xff0c;我们经常会遇到一些需要将信息写在配置文件的要求&#xff0c;比如文件的输出目录&#xff0c;输入目录的。当在配置文件中写入对应的目录配置时&#xff0c;那么怎么读取配置文件的内容就需要我们去了解了。 在java中一般使用Value这个注解去读…

SSM小区车辆信息管理系统-计算机毕业设计源码06111

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…

【机器学习】第5章 朴素贝叶斯分类器

一、概念 1.贝叶斯定理&#xff1a; &#xff08;1&#xff09;就是“某个特征”属于“某种东西”的概率&#xff0c;公式就是最下面那个公式。 2.朴素贝叶斯算法概述 &#xff08;1&#xff09;是为数不多的基于概率论的分类算法&#xff0c;即通过考虑特征概率来预测分类。 …

ubuntu如何查看ip地址

ubuntu如何查看ip地址 方法一&#xff1a;使用ifconfig方法二&#xff1a;使用ip命令 方法一&#xff1a;使用ifconfig 命令行输入ifconfig&#xff1a; 这里inet后跟的内容就是IP地址。 方法二&#xff1a;使用ip命令 命令行输入&#xff1a;ipa ddr&#xff1a; 这里ine…

可抑制癌细胞增殖!慧湖药学院联手天津医科大,研发新型肿瘤抑制蛋白降解剂 dp53m

或许很多人不知道&#xff0c;其实我们每个人体内都存在癌细胞。 人体每天都在进行着数十亿甚至上百亿细胞的新生与更替&#xff0c;在这个代谢过程中&#xff0c;DNA 复制难免会「出错」&#xff0c;比如会出现基因突变&#xff0c;让正常的细胞变成原位癌细胞。不过&#xff…

最新版首发 | 手把手教你安装 Vivado2024.1(附安装包)

Q&#xff1a;Vivado出2024版了&#xff01;不知迪普微有没有对应的安装包呢&#xff1f; A&#xff1a;有的&#xff01;回复“Vivado2024.1”即可获得相应安装包哦~ Q&#xff1a;好哒~但是我不会安装&#xff0c;可否安排一期安装教程&#xff1f; A&#xff1a;立马安排&…

ONES 功能上新|ONES 开放平台新功能一览

ONES 开放平台提供 OpenAPI、插槽、事件等能力&#xff0c;以便开发者通过插件&#xff0c;实现第三方集成和流程定制&#xff0c;满足客户的二次开发需求。 支持在任意工作项视图的详情表单中&#xff0c;添加插件的自定义标签页&#xff0c;以满足插件开发者在工作项详情页显…

人力资源招聘社会校企类型招聘系统校园招聘小程序

校企社会人力资源招聘小程序&#xff1a;开启高效招聘新时代 &#x1f680;开篇&#xff1a;打破传统&#xff0c;开启招聘新篇章 在快速发展的现代社会&#xff0c;人力资源招聘已经成为企业和学校共同关注的重要议题。为了更高效、便捷地满足双方的招聘需求&#xff0c;一款…

【NoSQL数据库】Redis Cluster集群(含redis集群扩容脚本)

Redis Cluster集群 Redis ClusterRedis 分布式扩展之 Redis Cluster 方案功能数据如何进行存储 redis 集群架构集群伸缩向集群中添加一个新的master节点&#xff0c;并向其中存储 num10 .脚本对redis集群扩容缩容&#xff0c;脚本参数为redis集群&#xff0c;固定从6001移动200…

Mac用虚拟机玩游戏很卡 Mac电脑玩游戏怎么流畅运行 苹果电脑怎么畅玩Windows游戏

对于许多Mac电脑用户而言&#xff0c;他们经常面临一个令人头疼的问题&#xff1a;在虚拟机中玩游戏时卡顿严重&#xff0c;影响了游戏体验。下面我们将介绍Mac用虚拟机玩游戏很卡&#xff0c;Mac电脑玩游戏怎么流畅运行的相关内容。 一、Mac用虚拟机玩游戏很卡 下面我们来看…