GObject学习笔记(一)类和实例
前言
最近阅读Aravis源码,其中大量运用了GObject,于是打算学习一下。
此系列笔记仅主要面向初学者,不会很深入探讨源码的细节,专注于介绍GObject的基本用法。
此系列笔记参考GObject Tutorial for beginners
本文可在个人博客中阅读,体验更加
套个盾:文中定义的名词只是为了更好地理解GObject,不具备权威性。
类和实例
在GObject中,每个可实例化类类型都与两个结构体相关联:一个是类结构体,一个是实例结构体。
- 类结构体会被注册到类型系统中(具体注册方式在下一节讨论),在
g_object_new首次调用时,类型系统会检查相应的类结构体是否已经被初始化为一个类变量,没有则创建并初始化。此后所有该类的实例变量都将共享这个已初始化的类变量。每个类变量只会被创建一次。 - 每次调用
g_object_new时都会创建实例变量。
在GObject系统中,类结构体和实例结构体都会被实例化,在内存中占有特定的空间。为了便于描述,我们将分配给类结构体的实例称为“类变量”,而分配给实例结构体的实例称为“实例变量”。
GObject实例的结构体定义如下
//file: gobject.h
typedef struct _GObject GObject;
struct _GObject
{
GTypeInstance g_type_instance;
/*< private >*/
guint ref_count; /* (atomic) */
GData *qdata;
};
GObject类的结构体定义如下(我们可以先不用了解结构的细节):
//file: gobject.h
typedef struct _GObjectClass GObjectClass;
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的类和实例的使用
//file: example01.c
#include <glib-object.h>
int main (int argc, char **argv)
{
GObject* instance1,* instance2; //指向实例的指针
GObjectClass* class1,* class2; //指向类的指针
instance1 = g_object_new (G_TYPE_OBJECT, NULL);
instance2 = g_object_new (G_TYPE_OBJECT, NULL);
g_print ("The address of instance1 is %p\n", instance1);
g_print ("The address of instance2 is %p\n", instance2);
class1 = G_OBJECT_GET_CLASS (instance1);
class2 = G_OBJECT_GET_CLASS (instance2);
g_print ("The address of the class of instance1 is %p\n", class1);
g_print ("The address of the class of instance2 is %p\n", class2);
g_object_unref (instance1);
g_object_unref (instance2);
return 0;
}
其中:
g_object_new函数创建实例变量并返回指向它的指针。在实例变量第一次被创建之前,它对应的类变量也会被创建并初始化。- 参数
G_TYPE_OBJECT是GObject基类的类型标识符,这是GObject类型系统的核心,所有其他GObject类型都从这个基类型派生。 - 宏
G_OBJECT_GET_CLASS返回指向参数所属类变量的指针 g_object_unref会销毁实例变量并释放内存。
输出:
The address of instance1 is 0x55d3ddc05600
The address of instance2 is 0x55d3ddc05620
The address of the class of instance1 is 0x55d3ddc05370
The address of the class of instance2 is 0x55d3ddc05370
可以发现,两个实例变量的地址不同,但两个实例变量对应的类变量的地址相同,因为两个实例变量共享一个类变量
引用计数
引用计数机制的概念在此不做介绍
在GObject中,GObject实例具有引用计数机制:
//file: example02.c
#include <glib-object.h>
static void show_ref_count (GObject* instance)
{
if (G_IS_OBJECT (instance))
/* Users should not use ref_count member in their program. */
/* This is only for demonstration. */
g_print ("Reference count is %d.\n", instance->ref_count);
else
g_print ("Instance is not GObject.\n");
}
int main (int argc, char **argv)
{
GObject* instance;
instance = g_object_new (G_TYPE_OBJECT, NULL);
g_print ("Call g_object_new.\n");
show_ref_count (instance);
g_object_ref (instance);
g_print ("Call g_object_ref.\n");
show_ref_count (instance);
g_object_unref (instance);
g_print ("Call g_object_unref.\n");
show_ref_count (instance);
g_object_unref (instance);
g_print ("Call g_object_unref.\n");
g_print ("Now the reference count is zero and the instance is destroyed.\n");
g_print ("The instance memories are possibly returned to the system.\n");
g_print ("Therefore, the access to the same address may cause a segmentation error.\n");
return 0;
}
其中:
g_object_new创建一个实例变量,然后将变量的引用计数置为1g_object_ref将其引用计数加1g_object_unref将引用计数减1,如果此时引用计数为0,则析构变量。
输出:
Call g_object_new.
Reference count is 1.
Call g_object_ref.
Reference count is 2.
Call g_object_unref.
Reference count is 1.
Call g_object_unref.
Now the reference count is zero and the instance is destroyed.
The instance memories are possibly returned to the system.
Therefore, the access to the same address may cause a segmentation error.
初始化和析构过程
GObject初始化和销毁的实际过程比较复杂。以下是简单的描述,不做详细说明.
初始化
1.用类型系统注册GObject类型。这是在调用main函数之前的GLib的初始化过程中完成的。(如果编译器是gcc,则__attribute__ ((constructor))用于限定初始化函数。)
2.为GObjectClass和GObject结构分配内存
3.初始化GObjectClass结构内存。这个内存将是GObject的类变量。
4.初始化GObject结构内存。这个内存将是GObject的实例变量。
上述初始化过程在第一次调用g_object_new函数时执行。在第二次及后续调用g_object_new时,它只执行两个过程:①为GObject结构分配内存②初始化内存。
析构
1.销毁GObject实例。释放实例的内存
GObject变量类型是静态类型。静态类型永远不会破坏它的类。因此,即使被销毁的实例变量是最后一个,类变量仍然存在,直到程序终止。
参考文章
1.GObject Tutorial for beginners
推荐
GObject学习笔记(一)类和实例的更多相关文章
- python学习笔记4_类和更抽象
python学习笔记4_类和更抽象 一.对象 class 对象主要有三个特性,继承.封装.多态.python的核心. 1.多态.封装.继承 多态,就算不知道变量所引用的类型,还是可以操作对象,根据类型 ...
- input子系统学习笔记六 按键驱动实例分析下【转】
转自:http://blog.chinaunix.net/uid-20776117-id-3212095.html 本文接着input子系统学习笔记五 按键驱动实例分析上接续分析这个按键驱动实例! i ...
- Java学习笔记之---类和对象
Java学习笔记之---类和对象 (一)类 类是一个模板,它描述一类对象的行为和状态 例如:动物类是一个类,动物们都有属性:颜色,动物们都有行为:吃饭 public class Dog { Stri ...
- python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容
python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...
- Java学习笔记——File类之文件管理和读写操作、下载图片
Java学习笔记——File类之文件管理和读写操作.下载图片 File类的总结: 1.文件和文件夹的创建 2.文件的读取 3.文件的写入 4.文件的复制(字符流.字节流.处理流) 5.以图片地址下载图 ...
- ArcGIS案例学习笔记-中国2000坐标转换实例
ArcGIS案例学习笔记-中国2000坐标转换实例 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 目的:西安1980.中国2000.WGS84(GPS)等任意坐标系 ...
- UML学习笔记:类图
UML学习笔记:类图 有些问题,不去解决,就永远都是问题! 类图 类图(Class Diagrame)是描述类.接口以及它们之间关系的图,用来显示系统中各个类的静态结构. 类图包含2种元素:类.接口, ...
- ensorflow学习笔记四:mnist实例--用简单的神经网络来训练和测试
http://www.cnblogs.com/denny402/p/5852983.html ensorflow学习笔记四:mnist实例--用简单的神经网络来训练和测试 刚开始学习tf时,我们从 ...
- openresty 学习笔记小结:综合应用实例
openresty 学习笔记小结:综合应用实例 这个综合实验实现的功能其实很简单,用户访问一个页面,显示一个默认页面.输入参数(post或者get都可以),如果参数在数据库查询得到并满足一定条件,根据 ...
- Python 学习笔记14 类 - 使用类和实例
当我们熟悉和掌握了怎么样创建类和实例以后,我们编程中的大多数工作都讲关注在类的简历和实例对象使用,修改和维护上. 结合实例我们来进一步的学习类和实例的使用: 我们新建一个汽车的类: #-*- codi ...
随机推荐
- Oracle数据库安装与还原
安装Oracle 11g数据库 安装数据库参考这位大佬的文章:(135条消息) Oracle 11g版本下载及安装超详细教程图解_oracle11g下载_田夜的博客-CSDN博客 非常详细 利用dmp ...
- LaTeX 插入伪代码
使用 algorithm 包和 algpseudocode 包 algorithm 包 用途: 提供一个浮动体环境来包含算法(类似于 figure 和 table 环境),使得算法可以自动编号并出现在 ...
- Docker高级:Redis集群实战!4主4从缩容到3主3从,怎么处理?
在上一篇,我们学会了redis集群的扩容.从3主3从扩容到4主4从. 那么,接着,活动过去了.流量没有那么大了.需要缩容了.从4主4从缩容到3主3从了.那么这个时候又该怎么处理呢? PS本系列:< ...
- MDC – Work with Framework & Customize
前言 在 MDC – Material Design, Angular Material, MDC, MWC, Lit 的关系 中, 我有提到基于 MDC 的 Framework 生态有多糟糕. 但它 ...
- CMake构建学习笔记16-使用VS进行CMake项目的开发
目录 1. 概论 2. 详论 2.1 创建工程 2.2 加载工程 2.3 配置文件 2.4 工程配置 2.5 调试执行 3. 项目案例 4. 总结 1. 概论 在之前的系列博文中,我们学习了如何构建第 ...
- Flutter 因你更优秀 | 2021 第一季度开发者调研
Flutter 终于在新的一年迎来了 2.0 版本,这是继 Dart 健全的空安全 Beta 版,以及 在测试方面取得重大进展 之后的一个全新的里程碑.在迈入这个新版本的当下,我们也已经准备好为大家带 ...
- iManager for K8S 配置https证书流程步骤
针对10.1及之前版本,需要手动去配置证书,未来版本会考虑进行界面化配置. 一.提前准备 1. 证书需要准备三个文件 *.key *.crt private.pem 2. 如果没有修改iManager ...
- Softmax 函数 详解
- 【赵渝强老师】MongoDB中的索引(下)
(四)索引的类型三:复合索引(Compound Index) MongoDB支持复合索引,即将多个键组合到一起创建索引.该方式称为复合索引,或者也叫组合索引,该方式能够满足多键值匹配查询使用索引的情形 ...
- 可视化U-Net编码器每层的输出(在已经训练好的模型下展示,并不是初始训练阶段展示)
想看一下对于一个训练好的模型,其每一层编码阶段的可视化输出是什么样子的.我以3Dircabd肝脏血管分割为例,训练好了一个U-Net模型.然后使用该模型在推理阶段使用,并可视化了每一层编码器. 分割结 ...