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方法。

类的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.mzph.cn/pingmian/30441.shtml

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

相关文章

云徙科技助力竹叶青实现用户精细化运营,拉动全渠道销售额增长

竹叶青茶以其别具一格的风味与深厚的历史底蕴&#xff0c;一直被誉为茶中瑰宝。历经千年的传承与创新&#xff0c;竹叶青不仅坚守着茶叶品质的极致追求&#xff0c;更在数字化的浪潮中&#xff0c;率先打破传统&#xff0c;以科技力量赋能品牌&#xff0c;成为茶行业的领军者。…

家长必备:超全的VIP硬笔书法课程(250课完结版),手把手教附可打印控笔素材!

今天要跟大家聊聊一个特别有意思的玩意儿——硬笔书法。你没听错&#xff0c;就是那种用钢笔、圆珠笔&#xff0c;甚至铅笔就能写出漂亮字的技艺。这可不仅仅是写字那么简单&#xff0c;它是一门艺术&#xff0c;一种生活的态度。 阿星记得小时候&#xff0c;爷爷总是拿着毛笔…

http缓存及http2配置

http缓存及http2配置极大提高了网页加载得速度 1.1 nginx安装 首先是需要安装nginx 去官网下载windows版本的安装包 nginx 命令 nginx start //启动 nginx -s stop nginx -s reload // 重新运行 tasklist /fi "imagename eq nginx.exe" //进程 把打包好的文件copy…

PyTorch -- RNN 快速实践

RNN Layer torch.nn.RNN(input_size,hidden_size,num_layers,batch_first) input_size: 输入的编码维度hidden_size: 隐含层的维数num_layers: 隐含层的层数batch_first: True 指定输入的参数顺序为&#xff1a; x&#xff1a;[batch, seq_len, input_size]h0&#xff1a;[batc…

使用密钥对登录服务器

目录 1、使用密钥文件登录服务器 2、登录成功画面&#xff1a; 3、如若出现以下状况&#xff0c;则说明密钥文件登录失败 1、使用密钥文件登录服务器 首先需要上传pem文件 2、登录成功画面&#xff1a; 3、如若出现以下状况&#xff0c;则说明密钥文件登录失败 解决方法&…

嵌入式技术学习——Linux环境编程(高级编程)——shell编程

一、shell编程的基础介绍 1.为什么要进行shell编程? 在Linux系统中&#xff0c;虽然有各种各样的图形化接口工具&#xff0c;但是shell仍然是一个非常灵活的 工具。 Shell不仅仅是命令的收集&#xff0c;而且是一门非常棒的编程语言。 您可以通过使用shell使大量的任务自动化…

mfc140.dll电脑文件丢失的处理方法,这4种方法能快速修复mfc140.dll

mfc140.dll文件是一个非常重要的dll文件&#xff0c;如果它丢失了&#xff0c;那么会严重的影响程序的运行&#xff0c;这时候我们要找方法去修复mfc140.dll这个文件&#xff0c;那么你知道怎么修复么&#xff1f;如果不知道&#xff0c;那么不妨看看下面的mfc140.dll文件丢失的…

【DAMA】掌握数据管理核心:CDGA考试指南

引言&#xff1a;        在当今快速发展的数字化世界中&#xff0c;数据已成为组织最宝贵的资产之一。有效的数据管理不仅能够驱动业务决策&#xff0c;还能提升竞争力和市场适应性。DAMA国际一直致力于数据管理和数字化的研究、实践及相关知识体系的建设。秉承公益、志愿…

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

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

SpringBoot配置第三方专业缓存技术Ehcache

Ehcache缓存技术 我们刚才是用Springboot提供的默认缓存技术 我们用的是simple 是一个内存级的缓存 我们接下来要使用专业的缓存技术了 Ehcache 是一个流行的开源 Java 分布式缓存&#xff0c;由 Terracotta 公司开发和维护。它提供了一个快速、可扩展、易于集成的内存缓存…

如何制定适合不同行业的新版FMEA培训计划?

在快速变化的市场环境中&#xff0c;失效模式与影响分析&#xff08;FMEA&#xff09;作为一种预防性的质量控制工具&#xff0c;越来越受到企业的重视。然而&#xff0c;不同行业在FMEA应用上存在着明显的差异&#xff0c;因此制定适合不同行业的新版FMEA培训计划显得尤为重要…

Sui主网升级至V1.27.2版本

其他升级要点如下所示&#xff1a; 重点&#xff1a; #17245 增加了一个新的协议版本&#xff0c;并在开发网络上启用了Move枚举。 JSON-RPC #17245: 在返回的JSON-RPC结果中增加了对Move枚举值的支持。 GraphQL #17245: 增加了对Move枚举值和类型的支持。 CLI #179…

明基的台灯值得入手吗?书客、柏曼真实横向测评对比

如今&#xff0c;近视问题在人群中愈发凸显&#xff0c;据2024年的最新统计数据揭示&#xff0c;我国儿童青少年的近视率已经飙升至惊人的52.7%。在学业日益繁重的背景下&#xff0c;学生们的视力健康成为了社会各界关注的焦点。近视不仅影响视力&#xff0c;还可能引发一系列严…

LeetCode80. 删除有序数组中的重复项 II题解

LeetCode80. 删除有序数组中的重复项 II题解 题目链接&#xff1a; https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/ 题目描述&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素…

渲染农场深度解析:原理理解、配置要点与高效使用策略

许多设计领域的新手可能对“渲染农场”这一概念感到陌生。渲染农场是一种强大的计算资源集合&#xff0c;它通过高性能的CPU和GPU以及专业的渲染引擎&#xff0c;为设计项目提供必要的渲染支持。这种平台由多台计算机或渲染节点组成&#xff0c;形成一个分布式网络&#xff0c;…

从零基础到学完CCIE要多久?

思科认证的CCIE是网络工程师追求的顶级认证之一。 对于刚入门的初学者来说&#xff0c;从零基础到通过CCIE认证&#xff0c;这条路需要多长时间&#xff1f; 这个问题的答案因人而异&#xff0c;取决于多种因素。 这不仅是一个关于时间的问题&#xff0c;更是一个关于规划、学习…

操作系统真象还原:输入输出系统

第10章-输入输出系统 这是一个网站有所有小节的代码实现&#xff0c;同时也包含了Bochs等文件 10.1 同步机制–锁 10.1.1 排查GP异常&#xff0c;理解原子操作 线程调度工作的核心内容就是线程的上下文保护&#xff0b;上下文恢复 。 根本原因是访问公共资源需要多个操作&…

【教学类-64-04】20240619彩色鱼骨图(一)6.5*1CM 6根棒子720种

背景需求&#xff1a; 幼儿益智早教玩具❗️鱼骨拼图 - 小红书在家也能自制的木棒鱼骨拼图&#xff0c;你也收藏起来试一试吧。 #母婴育儿 #新手爸妈 #玩具 #宝宝玩具怎么选 #早教 #早教玩具 #幼儿早教 #益智早教 #玩具 #宝宝早教 #益智拼图 #宝宝拼图 #玩不腻的益智玩具 #儿童…

vscode插件开发之 - Treeview视图

一些测试类插件&#xff0c;往往需要加载测试文件&#xff0c;并执行这些测试文件。以playwright vscode为例&#xff0c;该插件可以显示目录下所有的测试文件。如下图所示&#xff0c;显示了tests目录下的所有xxx.spec.js文件&#xff0c;那么如何在vscode插件开发中显示TreeV…

[Python学习篇] Python公共操作

公共运算符 运算符描述支持的容器类型合并字符串、列表、元组*复制字符串、列表、元组in元素是否存在字符串、列表、元组、字典not in元素是否不存在字符串、列表、元组、字典 示例&#xff1a; 字符串 str1 ab str2 cd print(str1 str2) # abcd print(str1 * 3) # ab…