Gobject tutorial 二

2024-06-15 12:20
文章标签 tutorial gobject

本文主要是介绍Gobject tutorial 二,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Type system and registration process

Gobject本身是一个基础对象类型。我们平常并不会直接使用。通常我们都是使用其衍生类型,比如,各种类型的GtkWidget。

本次,我们聊聊如何创建一个Gobject的衍生对象。我们的例子是实现一个表示数字的对象。尽管c语言中有int、double等类型来表示数字。然而我们的例子与他们并不冲突。对此,我们需要从更抽象的层次来理解。如果你去了解抽象代数,或许你会对此有更深刻的认识。

Name convention

首先,我们来了解一下命名规则。对象类型的名称包含名字空间和对象名字两部分。比如说,Gobject包含名字空间G和对象名字Object,GtkWidget包含名字空间Gtk和对象名字Widget。在我们的例子中,我们使用T作为名字空间,Double作为对象名字。TDouble就是我们构建的新的类型的名字。它是由GObject衍生而来,它代表一个真实的数字,一个真实的阿拉伯数字,数字的类型就是c语言中的double。

Define TDoubleClass and TDouble

我们的新类型TDoube,包含TDouble类和TDouble实例。因此,对于一个完整的TDouble类型,我们要分两部分进行定义。

对于TDouble的类,以C语言的形式进行表示时,它的名字是TDoubleClass,定义如下:

typedef struct _TDoubleClass TDoubleClass;
struct _TDoubleClass {GObjectClass parent_class;
};

我们要说明的是,表示TDoubleClass的结构体的第一个成员必须是其父类结构体。那么,问题来了,为啥这么做呢?如果去研究GTK源码,你会发现其中有很多强制类型转化来简化获取结构体成员的操作。此处这么定义就能说明为什么可以做强制类型转换。

对于TDouble的实例,以C语言的形式进行表示时,它的名字是TDouble,定义如下:

typedef struct _TDouble TDouble;
struct _TDouble {GObject parent;double value;
};

同理, 表示TDouble的结构体的第一个成员必须是其父实例结构体。原因同上。

Creation process of a child of GObject

新类型TDouble的创建包含以下几个步骤:

  1. 将TDouble类型注册到类型系统中。
  2. 类型系统为TDoubleClass 和TDouble分配内存空间。
  3. 初始化TDoubleClass。
  4. 初始化TDouble。

Registration

对于注册本身来说,分为静态注册和动态注册两种。两者的区别在于,即使特定类型的所有实例都被销毁了,静态注册的类型也不会销毁其类。而动态注册的类型在其最后一个实例销毁时,其类也会被销毁。值得注意的是,GObject是静态注册的,同时,它的衍生对象类型静态注册的。静态注册的函数如下:

GType
g_type_register_static (GType           parent_type,const gchar     *type_name,const GTypeInfo *info,GTypeFlags      flags);

GTypeInfo结构体,正如其名,它存放的是关于对象类型的信息。其定义如下:

typedef struct _GTypeInfo  GTypeInfo;struct _GTypeInfo
{/* interface types, classed types, instantiated types */
//用于表示类结构体的大小,对于Tdouble,此值就是siezof(TDoubleClass)guint16                class_size;
//下边两个成员用于initialize/finalize类的动态成员GBaseInitFunc          base_init;GBaseFinalizeFunc      base_finalize;/* interface types, classed types, instantiated types */GClassInitFunc         class_init; //初始化类的静态成员。GClassFinalizeFunc     class_finalize; //finalize classgconstpointer          class_data; //用户提供的参数,供上述两函数使用/* instantiated types */guint16                instance_size; //实例的大小,对于TDouble,此值就是sizeoof(TDouble)guint16                n_preallocs;//ignoredGInstanceInitFunc      instance_init; //初始化实例成员/* value handling */const GTypeValueTable  *value_table; //对基类有用,对于GObject的衍生类,无用。
};

下面举例说明,一个完成的注册新类型的流程。

 1 #include <glib-object.h>2 3 #define T_TYPE_DOUBLE  (t_double_get_type ())4 5 typedef struct _TDouble TDouble;6 struct _TDouble {7   GObject parent;8   double value;9 };
10 
11 typedef struct _TDoubleClass TDoubleClass;
12 struct _TDoubleClass {
13   GObjectClass parent_class;
14 };
15 
16 static void
17 t_double_class_init (TDoubleClass *class) {
18 }
19 
20 static void
21 t_double_init (TDouble *self) {
22 }
23 /*此函数返回TDouble对象的类型,对于此功能的函数命名,有个规则,那就是<name space>_<name>_get_type ,为了更方便使用其返回值,我们定义了一个宏来指代其返回值。
这个宏也是有命名规则的。即<NAME_SPACE>_TYPE_<NAME> */
24 GType
25 t_double_get_type (void) {
26   static GType type = 0;
27   GTypeInfo info;
28 
29   if (type == 0) {
30     info.class_size = sizeof (TDoubleClass);
31     info.base_init = NULL;
32     info.base_finalize = NULL;
33     info.class_init = (GClassInitFunc)  t_double_class_init;
34     info.class_finalize = NULL;
35     info.class_data = NULL;
36     info.instance_size = sizeof (TDouble);
37     info.n_preallocs = 0;
38     info.instance_init = (GInstanceInitFunc)  t_double_init;
39     info.value_table = NULL;
40     type = g_type_register_static (G_TYPE_OBJECT, "TDouble", &info, 0);
41   }
42   return type;
43 }
44 
45 int
46 main (int argc, char **argv) {
47   GType dtype;
48   TDouble *d;
49 
50   dtype = t_double_get_type (); /* or dtype = T_TYPE_DOUBLE */
51   if (dtype)
52     g_print ("Registration was a success. The type is %lx.\n", dtype);
53   else
54     g_print ("Registration failed.\n");
55 
56   d = g_object_new (T_TYPE_DOUBLE, NULL);
57   if (d)
58     g_print ("Instantiation was a success. The instance address is %p.\n", d);
59   else
60     g_print ("Instantiation failed.\n");
61   g_object_unref (d); /* Releases the object d. */
62 
63   return 0;
64 }
65 

G_DEFINE_TYPE macro 

上述的注册套路是固定的。因此,可以定义宏来简化编程。这个宏就是G_DEFINE_TYPE。

G_DEFINE_TYPE宏的主要工作如下:

  • 声明类初始化函数,函数命名规则为<name space>_<name>_class_init。对于TDouble来说,这个函数就叫做t_double_class_init。此处只负责声明,实现部分由用户负责。
  • 声明实例初始化函数,函数命名规则为<name space>_<name>_init。对于TDouble来说,这个函数名就是t_double_init。同样的,此处只负责声明,实现部分由用户负责。
  • 定义一个静态变量,此变量指向其父类。这个变量的命名规则为<name space>_<name>_parent_class。对于TDouble来说,这个变量名就是t_double_parent_class。
  • 定义了一个<name space>_<name>_get_type函数。对于TDouble来说,就是定义了t_doule_get_type.对于使用此宏的对象类型来说,已经完成对对象类型的注册。

使用此宏,上述例子可以写成这样。

#include <glib-object.h>#define T_TYPE_DOUBLE  (t_double_get_type ())typedef struct _TDouble TDouble;
struct _TDouble {GObject parent;double value;
};typedef struct _TDoubleClass TDoubleClass;
struct _TDoubleClass {GObjectClass parent_class;
};G_DEFINE_TYPE (TDouble, t_double, G_TYPE_OBJECT)static void
t_double_class_init (TDoubleClass *class) {
}static void
t_double_init (TDouble *self) {
}int
main (int argc, char **argv) {GType dtype;TDouble *d;dtype = t_double_get_type (); /* or dtype = T_TYPE_DOUBLE */if (dtype)g_print ("Registration was a success. The type is %lx.\n", dtype);elseg_print ("Registration failed.\n");d = g_object_new (T_TYPE_DOUBLE, NULL);if (d)g_print ("Instantiation was a success. The instance address is %p.\n", d);elseg_print ("Instantiation failed.\n");g_object_unref (d);return 0;
}

这篇关于Gobject tutorial 二的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1063441

相关文章

A Tutorial on Near-Field XL-MIMO Communications Towards 6G【论文阅读笔记】

此系列是本人阅读论文过程中的简单笔记,比较随意且具有严重的偏向性(偏向自己研究方向和感兴趣的),随缘分享,共同进步~ 论文主要内容: 建立XL-MIMO模型,考虑NUSW信道和非平稳性; 基于近场信道模型,分析性能(SNR scaling laws,波束聚焦、速率、DoF) XL-MIMO设计问题:信道估计、波束码本、波束训练、DAM XL-MIMO信道特性变化: UPW ➡ NU

beanstalkc Tutorial 中文版

英文原版:https://github.com/earl/beanstalkc/blob/wip-doc-rtfd/doc/tutorial.rst 背景介绍: Beanstalk,一个高性能、轻量级的分布式内存队列系统。而beanstalkc是Beanstalk的一个python客户端库。看题主写的通俗易懂,就直接翻译过来。 开始: 启动服务端beanstalkd进程来监听14711端口,可以

OpenGuass under Ubuntu_22.04 install tutorial

今天开始短学期课程:数据库课程设计。今天9点左右在SL1108开课,听陈老师讲授了本次短学期课程的要求以及任务安排,随后讲解了国产数据库的三层架构的逻辑。配置了大半天才弄好,放一张成功的图片,下面开始记录成功的步骤: My operator system is Ubuntu_22.04. procedures sudo wget https://opengauss.obs.cn-so

Tutorial : Getting Started with Kubernetes on your Windows Laptop with Minikube

https://rominirani.com/tutorial-getting-started-with-kubernetes-on-your-windows-laptop-with-minikube-3269b54a226#.d9lmuvzf2 本文的注意事项: 1, 截止到2017.01.20, window上的kubernetes依然是实验性的, 存在各种不可预知的bug

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(仿射变换)

本系列学习笔记参考自OpenCV2.4.10之opencv\sources\samples\cpp\tutorial_code和http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文将继续学习opencv-tutorial-code中的ImgTrans,这里讲主要介绍仿射变换。仿射变换是直角坐标系的一种,描述的是一

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(图片边框与图片卷积)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文将继续介绍如何给一张图片添加边框以及如何对一张图片进行卷积。核心函数为copyMakeBorder与filter2D 1.co

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(Canny边缘检测)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文接下来将介绍图像变换相关的Demo,如下图所示: CannyDetector_Demo.cpp(Canny边缘检测)

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgProc(图像处理)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html       本博文将继续学习 OpenCV2.4.10中tutorial-code下的ImgProc,还有对于涉及到的知

OpenCV2.4.10之samples_cpp_tutorial-code_learn------安装配置与第一个Opencv程序

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html opencv作为一个开源的二维图形库,提供了一套完整的二维图像处理等相关算法的C/C++实现。自opencv2.0版

【kaldi】Kaldi tutorial翻译之Prerequisites(前提条件)-kaldi学习前必备梳理

本翻译仅供自己学习使用,不承担任何其他责任。水平有限拒绝转载。欢迎大家指出错误,共同学习。 我们假设本页的读者了解使用HMM-GMM进行语音识别的基础知识。在这里我们需要在线简明介绍的是:M. Gales and S. Young (2007).``The Application of Hidden Markov Models in Speech Recognition."