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 ...
随机推荐
- C#自己封装数据库操作类BaseADO
这几天学习数据库操作,就自己封装了一个数据库操作类,下面是代码展示 下面的例子是Access数据库 也可能用在Sql数据库中,只在在第一行代码上修改标识符即可 #define OLEDB_ using ...
- MFC 静态拆分视图窗口
今天学习了MFC中拆分窗口,现将方法记录下. 想要在窗口视图中拆分成左右两个视图窗口,首先要注意的是拆分后要加载到左右的视图要符合动态创建的类, 也就是要在自己创建的视图类中添加动态创建机制宏. 类内 ...
- **错误积累&&防止GG写法总结
19.3.20 关于int与ll 1.如果一道题时间充足,把全部变量定义成long long 2.特别注意最上面宏定义的变量类型,特别是FOR 3.如果是int,用1LL* ...... **实例,让 ...
- history的replace("/admin")与("admin")的区别
假设当前路由为:localhost:3000/index/a 有"/"的情况是直接从根目录替换 改完之后的路由为:localhost:3000/admin 没有"/&qu ...
- 修改 Ubuntu 文件夹为英文
如果你在安装 Ubuntu 时,语言选了中文,那么系统自动创建的文件夹也会是中文(下载.图片 等).有时这会造成不便.可以通过以下命令将文件夹改为英文: LANG=C LC_ALL=C xdg-use ...
- 移动端Android跟ios兼容性问题,反人类!!!
一.查询参数编码问题 我们在日常开发中,有时候会遇到拼接参数特别多的情况,那么就会导致一行代码特别长.那么为了美观呢,有的同学会进行换行处理,如下代码: 可以看到我红色框出来的地方就是经过了手动的回车 ...
- 【YashanDB知识库】存储过程报错snapshot too old
问题描述 20231127上午客户反馈绩效系统20231125.20231126出现2次YAS-02020 snapshot too old的问题,测试也有类似问题. 该过程是客户新增的存储过程,目的 ...
- 用CSS border画一个铅笔
先上效果图 该例子来自 CSS世界 的书中项目 总结技巧如下: 巧用 border 和 伪元素 来 绘制层叠效果. 使用 transform-origin 来改变元素的轴心 使用 filter:dro ...
- idea运行java项目main方法报build failure错误的解决方法
当在使用 IntelliJ IDEA 运行 Java 项目的 main 方法时遇到 "Build Failure" 错误,这通常意味着在项目的构建过程中遇到了问题.解决这类问题通常 ...
- Nuxt.js 应用中的 link:prefetch 钩子详解
title: Nuxt.js 应用中的 link:prefetch 钩子详解 date: 2024/10/7 updated: 2024/10/7 author: cmdragon excerpt: ...