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 ...
随机推荐
- SpringBoot静态文件映射问题
如果遇到这种情况,检查静态文件(js/css/img)是不是在默认的static路径下,在查看application配置中的 static-path-pattern: 是否和前端映射路径完全相同,要是 ...
- release版本 APP 出现waiting for debugger
前提:同一包代码,打包两个版本,修改包名,在同一设备上存在两个版本 状态:运行时,发现 一版本是正常 另一版本打开会提示 Waiting for debugger弹窗,(此时由于是开发状态,设备一直开 ...
- 非常简易的SpringBoot后台项目
非常简易的SpringBoot后台项目 1. 创建项目 使用IDEA创建 Spring项目,或在 https://start.spring.io/ . https://start.aliyun.com ...
- sql server 将数据库表里面的数据,转为insert语句,方便小批量转移数据
create proc [dbo].[proc_insert] (@tablename varchar(256)) as begin set nocount on declare @sqlstr va ...
- Zeppelin 学习
Zeppelin 遇到的问题: 1. 在interpreter 界面配置 dependency management 了以后,报 Error setting properties for interp ...
- 查看tensorflow pb模型文件
""" @Author: Qiangz @Date: 2019/7/5 @Description: """ import tensorflo ...
- .NET Core搭配Vue开源弹幕效果,实现一个评论小项目。好玩!
ZY树洞 前言 ZY树洞是一个基于.NET Core开发的简单的评论系统,主要用于大家分享自己心中的感悟.经验.心得.想法等. 好了,不卖关子了,这个项目其实是上班无聊的时候写的,为什么要写这个项目呢 ...
- Angular 18+ 高级教程 – NgModule
前言 NgModule 在 Angular v14 以前是一门必修课.然而,自 Angular v14 推出 Standalone Component 以后,它的地位变得越来越边缘化了. 本教程从开篇 ...
- BFS 颜色填涂———洛谷p1162
填涂颜色 题目描述 由数字 \(0\) 组成的方阵中,有一任意形状的由数字 \(1\) 构成的闭合圈.现要求把闭合圈内的所有空间都填写成 \(2\).例如:\(6\times 6\) 的方阵(\(n= ...
- [TK] 三色二叉树 hzoi-tg#282 存图方法
可以发现,假如在序列中遇到一个数为 \(2\) ,也就是有两个子节点,那么接下来的全部数字都是描述左树的,一直到左树被遍历完成. 这让你想到了什么? 当然是DFS啦. 根据DFS我们有下面这样的存图思 ...