Gobject tutorial 六

Instantiatable classed types Initialization and destruction

类型的实例化是通过函数g_tpye_create_instance()实现的。这个函数首先会查找与类型相关的GTypeInfo结构体,之后,查询结构体中的instance_size和 instance policy即 n_preallocs(在 2.10版本后废弃)。

如果正在创建的实例时此对象的第一个实例,类型系统必须为对象类结构体分配空间并进行初始化。在初始化时,类结构体的第一部分数据是通过复制此类的父类的结构体。类结构体的其余数据赋值为0.如果对象的类无父类,则对象的类结构体初始化为0.之后,类型系统从最顶端的基础对象开始,根据继承关系,直到现在正在实例化的对象为止,顺序调用base_init,接着,调用对象的class_init来完成类结构的初始化,最后初始化接口。

一旦类型系统初始化完成一个类结构,它就会将实例化的对象的类指针指向这个完成初始化的类结构。这就实现了多个实例化对象共用一个初始化类结构体。之后,会调用对象的instance_init函数,调用顺序是从最顶端的基础对象开始,根据继承关系,直到正在实例化的对象。

对象实例化的销毁,是通过函数g_type_free_instance()实现的。它的功能很简单:它会将实例结构体返还到实例池(这是池是根据n_preallocs分配的)。如果这个实例是一个对象的最后一个实例,那么,当实例销毁时,此对象的类初始化结构体也会被销毁。

类的销毁过程与类结构体初始化过程是对称的。即,先销毁接口,接着调用对象的class_finalize,最后,按照与调用class_init相反的顺序调用base_finalize。

过程如下图所示:

Non-instantiatable classed types: interfaces

interface与抽象类相似,只不过,interface中定义的通用API能被没有继承关系的类使用。它定义了一组方法,在Glib中,我们称这组方法为虚函数,这些方法是由实现接口的类来实现的。不同的类可以有相同的接口方法集。比如,CD播放器、MP3等设备上都有播放、暂停和停止按钮。此时,我们可以认为播放、暂停和停止属于接口中的方法集。

那么,接口是怎么定义以及使用的呢?下面我们举例说明,值得注意的是,接口的定义只需要一个数据结构,而不像对象,需要定义实例和类这两个数据结构,且我们定义的接口的数据结构第一个成员必须为GTypeInterface。GTypeInterface是所有接口的基类。其他成员还有接口函数指针。

我们实现的接口名为TComparable, 接口中方法为cmp。

/*tcomparable.h*/
#pragma once#include <glib-object.h>#define T_TYPE_COMPARABLE  (t_comparable_get_type ())
/*G_DECLARE_INTERFACE (TComparable, t_comparable, T, COMPARABLE, GObject)*/
GType t_comparable_get_type (void);
typedef struct _TComparable TComparable;
typedef struct _TComparableInterface TComparableInterface;
#define T_COMPARABLE(instance)           (G_TYPE_CHECK_INSTANCE_CAST(instance, T_TYPE_COMPARABLE, TComparable))
#define T_IS_COMPARABLE(instance)        (G_TYPE_CHECK_INSTANCE_TYPE(instance, T_TYPE_COMPARABLE))
#define T_COMPARABLE_GET_IFACE(instance) (G_TYPE_INSTANCE_GET_INTERFACE((instance), T_TYPE_COMPARABLE, TComparableInterface))  struct _TComparableInterface {GTypeInterface parent;/* signal */void (*arg_error) (TComparable *self);/* virtual function 将由实现接口的类的方法来覆盖*/int (*cmp) (TComparable *self, TComparable *other);
};/* t_comparable_cmp */
/* if self > other, then returns 1 */
/* if self = other, then returns 0 */
/* if self < other, then returns -1 */
/* if error happens, then returns -2 */int
t_comparable_cmp (TComparable *self, TComparable *other);gboolean
t_comparable_eq (TComparable *self, TComparable *other);gboolean
t_comparable_gt (TComparable *self, TComparable *other);gboolean
t_comparable_lt (TComparable *self, TComparable *other);gboolean
t_comparable_ge (TComparable *self, TComparable *other);gboolean
t_comparable_le (TComparable *self, TComparable *other);
/*tcomparable.c*/
#include "tcomparable.h"static guint t_comparable_signal;static void
t_comparable_default_init (TComparableInterface *iface);
GType
t_comparable_get_type (void) {static GType type = 0;GTypeInfo info;if (type == 0) {info.class_size = sizeof (TComparableInterface);info.base_init = NULL;info.base_finalize = NULL;info.class_init = (GClassInitFunc)  t_comparable_default_init;info.class_finalize = NULL;info.class_data = NULL;info.instance_size = 0;info.n_preallocs = 0;info.instance_init = NULL;info.value_table = NULL;type = g_type_register_static (G_TYPE_INTERFACE, "TComparable", &info, 0);}return type;
}static void
arg_error_default_cb (TComparable *self) {g_printerr ("\nTComparable: argument error.\n");
}static void
t_comparable_default_init (TComparableInterface *iface) {/* virtual function */iface->cmp = NULL;/* argument error signal */iface->arg_error = arg_error_default_cb;t_comparable_signal =g_signal_new ("arg-error",T_TYPE_COMPARABLE,G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,G_STRUCT_OFFSET (TComparableInterface, arg_error),NULL /* accumulator */,NULL /* accumulator data */,NULL /* C marshaller */,G_TYPE_NONE /* return_type */,0     /* n_params */,NULL  /* param_types */);
}int
t_comparable_cmp (TComparable *self, TComparable *other) {g_return_val_if_fail (T_IS_COMPARABLE (self), -2);TComparableInterface *iface = T_COMPARABLE_GET_IFACE (self);return (iface->cmp == NULL ? -2 : iface->cmp (self, other));
}gboolean
t_comparable_eq (TComparable *self, TComparable *other) {return (t_comparable_cmp (self, other) == 0);
}gboolean
t_comparable_gt (TComparable *self, TComparable *other) {return (t_comparable_cmp (self, other) == 1);
}gboolean
t_comparable_lt (TComparable *self, TComparable *other) {return (t_comparable_cmp (self, other) == -1);
}gboolean
t_comparable_ge (TComparable *self, TComparable *other) {int result = t_comparable_cmp (self, other);return (result == 1 || result == 0);
}gboolean
t_comparable_le (TComparable *self, TComparable *other) {int result = t_comparable_cmp (self, other);return (result == -1 || result == 0);
}

 到此,我们完成了对接口TComparable的定义。下面,我们来说明如何在各个类中使用,以及接口的虚拟函数是如何被各个类的函数覆盖的。

/*tint.c*/
#include "../tnumber/tnumber.h"
#include "../tnumber/tint.h"
#include "../tnumber/tdouble.h"
#include "tcomparable_without_macro.h"enum {PROP_0,PROP_INT,N_PROPERTIES
};static GParamSpec *int_properties[N_PROPERTIES] = {NULL, };struct _TInt {TNumber parent;int value;
};static void t_comparable_interface_init (TComparableInterface *iface);static void
t_int_class_init (TIntClass *class);
static void
t_int_init (TInt *self);GType 
t_int_get_type (void)
{static GType type = 0;if (type == 0) {const GTypeInfo info = {sizeof (TIntClass),NULL,   /* base_init */NULL,   /* base_finalize */(GClassInitFunc) t_int_class_init,   /* class_init */NULL,   /* class_finalize */NULL,   /* class_data */sizeof (TInt),0,      /* n_preallocs */(GInstanceInitFunc) t_int_init,    /* instance_init */NULL /* value table */};const GInterfaceInfo comparable_info = {(GInterfaceInitFunc) t_comparable_interface_init,  /* interface_init */NULL,   /* interface_finalize */NULL    /* interface_data */};type = g_type_register_static (T_TYPE_NUMBER, "TInt", &info, 0);g_type_add_interface_static (type, T_TYPE_COMPARABLE, &comparable_info);}return type;
}static int
t_int_comparable_cmp (TComparable *self, TComparable *other) {if (! T_IS_NUMBER (other)) {g_signal_emit_by_name (self, "arg-error");return -2;}int i;double s, o;s = (double) T_INT (self)->value;if (T_IS_INT (other)) {g_object_get (other, "value", &i, NULL);o = (double) i;} elseg_object_get (other, "value", &o, NULL);if (s > o)return 1;else if (s == o)return 0;else if (s < o)return -1;else /* This can't happen. */return -2;
}static void
t_comparable_interface_init (TComparableInterface *iface) {iface->cmp = t_int_comparable_cmp;
}static void
t_int_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) {TInt *self = T_INT (object);if (property_id == PROP_INT)self->value = g_value_get_int (value);elseG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}static void
t_int_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) {TInt *self = T_INT (object);if (property_id == PROP_INT)g_value_set_int (value, self->value);elseG_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}static void
t_int_init (TInt *self) {
}/* arithmetic operator */
/* These operators create a new instance and return a pointer to it. */
#define t_int_binary_op(op) \int i; \double d; \if (T_IS_INT (other)) { \g_object_get (T_INT (other), "value", &i, NULL); \return  T_NUMBER (t_int_new_with_value (T_INT(self)->value op i)); \} else { \g_object_get (T_DOUBLE (other), "value", &d, NULL); \return  T_NUMBER (t_int_new_with_value (T_INT(self)->value op (int) d)); \}static TNumber *
t_int_add (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);t_int_binary_op (+)
}static TNumber *
t_int_sub (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);t_int_binary_op (-)
}static TNumber *
t_int_mul (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);t_int_binary_op (*)
}static TNumber *
t_int_div (TNumber *self, TNumber *other) {g_return_val_if_fail (T_IS_INT (self), NULL);int i;double d;if (T_IS_INT (other)) {g_object_get (T_INT (other), "value", &i, NULL);if (i == 0) {g_signal_emit_by_name (self, "div-by-zero");return NULL;} elsereturn  T_NUMBER (t_int_new_with_value (T_INT(self)->value / i));} else {g_object_get (T_DOUBLE (other), "value", &d, NULL);if (d == 0) {g_signal_emit_by_name (self, "div-by-zero");return NULL;} elsereturn  T_NUMBER (t_int_new_with_value (T_INT(self)->value / (int)  d));}
}static TNumber *
t_int_uminus (TNumber *self) {g_return_val_if_fail (T_IS_INT (self), NULL);return T_NUMBER (t_int_new_with_value (- T_INT(self)->value));
}static char *
t_int_to_s (TNumber *self) {g_return_val_if_fail (T_IS_INT (self), NULL);int i;g_object_get (T_INT (self), "value", &i, NULL); return g_strdup_printf ("%d", i);
}static void
t_int_class_init (TIntClass *class) {TNumberClass *tnumber_class = T_NUMBER_CLASS (class);GObjectClass *gobject_class = G_OBJECT_CLASS (class);/* override virtual functions */tnumber_class->add = t_int_add;tnumber_class->sub = t_int_sub;tnumber_class->mul = t_int_mul;tnumber_class->div = t_int_div;tnumber_class->uminus = t_int_uminus;tnumber_class->to_s = t_int_to_s;gobject_class->set_property = t_int_set_property;gobject_class->get_property = t_int_get_property;int_properties[PROP_INT] = g_param_spec_int ("value", "val", "Integer value", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE);g_object_class_install_properties (gobject_class, N_PROPERTIES, int_properties);
}TInt *
t_int_new_with_value (int value) {TInt *i;i = g_object_new (T_TYPE_INT, "value", value, NULL);return i;
}TInt *
t_int_new (void) {TInt *i;i = g_object_new (T_TYPE_INT, NULL);return i;
}

tstr.c、tdouble.c与tint.c使用Tcompararble的方式相同。到此,数据类型都定义完成,接下来说明,在应用程序中如何使用TComparable。

#include <glib-object.h>
#include "tcomparable_without_macro.h"
#include "../tnumber/tnumber.h"
#include "../tnumber/tint.h"
#include "../tnumber/tdouble.h"
#include "../tstr/tstr.h"static void
t_print (const char *cmp, TComparable *c1, TComparable *c2) {char *s1, *s2;TStr *ts1, *ts2, *ts3;ts1 = t_str_new_with_string("\"");if (T_IS_NUMBER (c1))s1 = t_number_to_s (T_NUMBER (c1));else if (T_IS_STR (c1)) {ts2 = t_str_concat (ts1, T_STR (c1));ts3 = t_str_concat (ts2, ts1);s1 = t_str_get_string (T_STR (ts3));g_object_unref (ts2);g_object_unref (ts3);} else {g_print ("c1 isn't TInt, TDouble nor TStr.\n");return;}if (T_IS_NUMBER (c2))s2 = t_number_to_s (T_NUMBER (c2));else if (T_IS_STR (c2)) {ts2 = t_str_concat (ts1, T_STR (c2));ts3 = t_str_concat (ts2, ts1);s2 = t_str_get_string (T_STR (ts3));g_object_unref (ts2);g_object_unref (ts3);} else {g_print ("c2 isn't TInt, TDouble nor TStr.\n");return;}g_print ("%s %s %s.\n", s1, cmp, s2);g_object_unref (ts1);g_free (s1);g_free (s2);
}    static void
compare (TComparable *c1, TComparable *c2) {if (t_comparable_eq (c1, c2))t_print ("equals", c1, c2);else if (t_comparable_gt (c1, c2))t_print ("is greater than", c1, c2);else if (t_comparable_lt (c1, c2))t_print ("is less than", c1, c2);else if (t_comparable_ge (c1, c2))t_print ("is greater than or equal to", c1, c2);else if (t_comparable_le (c1, c2))t_print ("is less than or equal to", c1, c2);elset_print ("can't compare to", c1, c2);
}int
main (int argc, char **argv) {const char *one = "one";const char *two = "two";const char *three = "three";TInt *i;TDouble *d;TStr *str1, *str2, *str3;i = t_int_new_with_value (124);d = t_double_new_with_value (123.45);str1 = t_str_new_with_string (one);str2 = t_str_new_with_string (two);str3 = t_str_new_with_string (three);compare (T_COMPARABLE (i), T_COMPARABLE (d));compare (T_COMPARABLE (str1), T_COMPARABLE (str2));compare (T_COMPARABLE (str2), T_COMPARABLE (str3));compare (T_COMPARABLE (i), T_COMPARABLE (str1));g_object_unref (i);g_object_unref (d);g_object_unref (str1);g_object_unref (str2);g_object_unref (str3);return 0;
}

Interface initialization

与abstract class类似,初始化时,会为接口结构分配空间,之后将父接口结构复制进来,如果没有父接口结构,则新分配的结构会被初始化为0。之后将g_type设置为正在初始化的接口类型,g_instance_type 设置为此正在实现此接口的对象类型。接着调用接口结构中base_init、default_init(class_int)、接口实现时所在类型的interface_init(例如Tint中的 t_compare_interface_init).如果同一个接口在很多类型中都存在实现(例如,Tcomparable在Tint,Tstr中都有实现),那么,接口实现所在的每个类型在初始化过程中,当轮到接口初始化时,接口中的base_init、interface_init都要执行一次,然而,default_init却只执行一次。因此,对接口的初始化一般放在default_init中,就如上例中的t_comparable_default_init中设置信号那样。

过程及说明如下表所示:

 Interface Destruction

当接口实现所在类型的最后一个实例化(如TInt的实例化)销毁时,与此类型相关的接口的实现也会销毁。

在销毁接口的实现时,类型系统GType会首先调用接口实现的interface_finalize之后调用接口的base_finalize。同样的每个接口实现所在类型在销毁时,这两个函数都被被调用一次。当所有接口实现所在类的实例都被销毁时,接口类型才会被销毁。

过程及说明如下表所示:

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

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

相关文章

MySQL数据库管理 二

1、数据表高级操作 &#xff08;1&#xff09;克隆表 方法一&#xff1a; create table 新表名 like 旧表名; #克隆表结构 insert into 新表名 select * from 旧表名; #克隆表数据 #此方法能保证 新表的表结构、表数据 跟旧表都是一致的 方法二&#x…

ECharts 词云案例三:2024年阅读关键词

ECharts 词云案例三&#xff1a;2024年阅读关键词 引言 在数据可视化领域&#xff0c;ECharts 以其强大的功能性和灵活性&#xff0c;成为开发者和设计师的首选工具之一。继上一篇关于 ECharts 词云图的详细介绍后&#xff0c;本文将探索词云图的进阶应用——使用蒙版来创造更…

19.面包屑导航制作

面包屑导航制作 官网&#xff1a;组件 | Element 1. 在layout下新建BreadCrumb.vue BreadCrumb.vue <template><div class"bread-text"><el-breadcrumb class"bred"separator"/"><el-breadcrumb-item v-for"item in…

家人们,我最近迷上了食家巷的方形饼

那独特的方形造型&#xff0c;超级可爱。&#x1f44f;刚出炉的方形饼&#xff0c;热气腾腾&#xff0c;散发着诱人的香气。&#x1f60b;咬一口&#xff0c;酥脆的外皮“咔滋”作响&#xff0c;里面的面饼却又十分绵软&#xff0c;口感层次超丰富&#xff01;&#x1f929;无论…

Golang | Leetcode Golang题解之第144题二叉树的前序遍历

题目&#xff1a; 题解&#xff1a; func preorderTraversal(root *TreeNode) (vals []int) {var p1, p2 *TreeNode root, nilfor p1 ! nil {p2 p1.Leftif p2 ! nil {for p2.Right ! nil && p2.Right ! p1 {p2 p2.Right}if p2.Right nil {vals append(vals, p1.V…

iview 组件里面的(任何一个月)整月日期全部选中_iview时间轴选中有历史记录日期

iview 组件里面的整月日期全部选中&#xff1a; ①&#xff1a;第一种是当前月的日期全部选中&#xff1a; 先上效果图&#xff1a;当前月分 获取到的值&#xff1a; 当前月的方法&#xff1a; // getDateStr() {// var curDate new Date();// var curMonth curDate.ge…

每日一题——Python代码实现力扣58. 最后一个单词的长度(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码逻辑&#xff1a; 时间复杂度&#xff1a; 空间复杂度&#xff1a; …

HTML5休闲小游戏《城堡守卫传说》源码,引流、刷广告利器

HTML5休闲小游戏《城堡守卫传说》源码&#xff0c;直接把源码上传到服务器就能使用了&#xff01; 下载链接&#xff1a;https://www.huzhan.com/code/goods467802.html

成都百洲文化传媒有限公司助力商家扬帆远航

在数字经济的浪潮中&#xff0c;电商行业如日中天&#xff0c;成都百洲文化传媒有限公司正是这一领域的佼佼者。作为一家专注于电商服务的传媒公司&#xff0c;百洲文化以其专业的服务、创新的理念和卓越的成果&#xff0c;在业内树立了良好的口碑&#xff0c;成为众多商家信赖…

划分子网和构造超网的学习

子网掩码长度&#xff1d;32位 某位&#xff1d;1&#xff1a;IP地址中的对应位为网络号和子网号 某位&#xff1d;0&#xff1a;IP地址中的对应位为主机号 从一个 IP 数据报的首部并无法判断源主机或目的主机所连接的网络是否进行了子网划分。 使用子网掩码(subnet mask)可…

Python大数据-电商商品详情数据分析【JD电商平台为例】

一、项目背景 网上购物已经成为大众生活的重要组成部分。人们在电商平台上浏览商品并购物&#xff0c;产生了海量的用户行为数据&#xff0c;用户对商品的详情数据对商家具有重要的意义。利用好这些碎片化、非结构化的数据&#xff0c;将有利于企业在电商平台上的持续发展&…

Hbuilder无线连接手机

1.链接数据线进行操作 打开adbs所在位置 2.运行cmd 或者 powershell 3.运行项目

Linux 式套娃,把“文件系统”安装在一个“文件”上?

背景 “文件”在文件系统之中&#xff0c;这是人人理解的概念。但“文件”之上还有一个文件系统&#xff1f;那岂不是成套娃了。但这个其实是可以的。这个就涉及到今天我们要讲的 loop 设备。 很多童鞋在学习 Linux 的文件系统时&#xff0c;涉及到对磁盘设备的格式化&#x…

一个轻量级的TTS模型实现

1.环境 python 版本 3.9 2.训练数据集 本次采用LJSpeech数据集&#xff0c;百度网盘下载地址 链接&#xff1a;https://pan.baidu.com/s/1DDFmPpHQrTR_NvjAfwX-QA 提取码&#xff1a;1234 3.安装依赖 pip install TTS 4.工程结构 5代码部分 decoder.py import torch f…

汇编基础之使用vscode写hello world

汇编语言&#xff08;Assembly Language&#xff09; 概述 汇编语言&#xff08;Assembly Language&#xff09;是一种低级编程语言&#xff0c;它直接对应于计算机的机器代码&#xff08;machine code&#xff09;&#xff0c;但使用了更易读的文本符号。每台个人计算机都有…

iOS 18 Siri 升级之后都有哪些改变?

新界面 首先最显著的改变就是 Siri 的界面不同了&#xff0c;之前的界面是在打开 Siri 之后会出现一个圆形图案&#xff0c;而在 Siri 升级之后变成了屏幕边缘发出亮光。 来源&#xff1a;Apple 可在任意位置使用 苹果的生成式人工智能 Apple Intelligence 将为 Siri 提供支…

注意力机制和Transformer模型各部分功能解释

文章目录 Transformer1、各部分功能解释2、通过例子解释a.输入预处理位置编码b.Encoder 的处理c.Decoder的输入Decoder的工作流程d.输出预测总结 Attention代码和原理理解 Transformer 运行机理&#xff1a; &#xff08;1&#xff09;假设我们需要进行文本生成任务。我们将已…

Springboot集成SSE消息推送

SSE介绍 SSE&#xff08;Server-Sent Events&#xff09;的全称是服务器推送事件&#xff0c;它是一种基于 HTTP 协议的实时通信技术&#xff0c;用于在客户端和服务器之间建立持久、单向的链接&#xff0c;允许服务器向客户端发送异步消息。 了解 websocket 的小伙伴&…

SAP BC 换了logo后,其他人的logo都已经换了,但是其中有一台就是PRD 显示DEV的logo,从smw0上下载的是PRD

昨天终于发现是缓存的问题 GUI登录后 选项-本地数据-缓存 删除本地缓存文件&#xff0c;问题解决了

机器学习课程复习——聚类算法

Q:什么是硬聚类,什么是软聚类? 如果一个样本只能属于一个类,则称为硬聚类(hard clustering); 如果一个样本可以属于多个类,则称为软聚类(soft clustering)。 Q:聚类和分类的区别? 聚类分类学习类型无监督学习方法 不需要事先标记的数据 通过发现数据中的模式或结构来组…