前言

最近阅读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创建一个实例变量,然后将变量的引用计数置为1
  • g_object_ref将其引用计数加1
  • g_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学习笔记(二)类型创建与注册

GObject学习笔记(一)类和实例的更多相关文章

  1. python学习笔记4_类和更抽象

    python学习笔记4_类和更抽象 一.对象 class 对象主要有三个特性,继承.封装.多态.python的核心. 1.多态.封装.继承 多态,就算不知道变量所引用的类型,还是可以操作对象,根据类型 ...

  2. input子系统学习笔记六 按键驱动实例分析下【转】

    转自:http://blog.chinaunix.net/uid-20776117-id-3212095.html 本文接着input子系统学习笔记五 按键驱动实例分析上接续分析这个按键驱动实例! i ...

  3. Java学习笔记之---类和对象

    Java学习笔记之---类和对象 (一)类 类是一个模板,它描述一类对象的行为和状态  例如:动物类是一个类,动物们都有属性:颜色,动物们都有行为:吃饭 public class Dog { Stri ...

  4. python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容

    python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...

  5. Java学习笔记——File类之文件管理和读写操作、下载图片

    Java学习笔记——File类之文件管理和读写操作.下载图片 File类的总结: 1.文件和文件夹的创建 2.文件的读取 3.文件的写入 4.文件的复制(字符流.字节流.处理流) 5.以图片地址下载图 ...

  6. ArcGIS案例学习笔记-中国2000坐标转换实例

    ArcGIS案例学习笔记-中国2000坐标转换实例 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 目的:西安1980.中国2000.WGS84(GPS)等任意坐标系 ...

  7. UML学习笔记:类图

    UML学习笔记:类图 有些问题,不去解决,就永远都是问题! 类图 类图(Class Diagrame)是描述类.接口以及它们之间关系的图,用来显示系统中各个类的静态结构. 类图包含2种元素:类.接口, ...

  8. ensorflow学习笔记四:mnist实例--用简单的神经网络来训练和测试

    http://www.cnblogs.com/denny402/p/5852983.html ensorflow学习笔记四:mnist实例--用简单的神经网络来训练和测试   刚开始学习tf时,我们从 ...

  9. openresty 学习笔记小结:综合应用实例

    openresty 学习笔记小结:综合应用实例 这个综合实验实现的功能其实很简单,用户访问一个页面,显示一个默认页面.输入参数(post或者get都可以),如果参数在数据库查询得到并满足一定条件,根据 ...

  10. Python 学习笔记14 类 - 使用类和实例

    当我们熟悉和掌握了怎么样创建类和实例以后,我们编程中的大多数工作都讲关注在类的简历和实例对象使用,修改和维护上. 结合实例我们来进一步的学习类和实例的使用: 我们新建一个汽车的类: #-*- codi ...

随机推荐

  1. uni-app和vue及微信小程序的异同

    uni-app和vue的区别1.目录不同 uni-app目录依赖原生小程序风格,比如分包的概念 vue中对不同的页面只需要在views文件夹中定义不同组件,然后配置路由跳转就行了,所有页面都是这样, ...

  2. Kubernetes利用Volume挂载ConfigMap与Secret

    1.概述 在Kubernetes集群中,应用的配置管理是一个关键且复杂的任务.随着应用的扩展和微服务架构的普及,传统的配置文件管理方式已经难以满足动态.灵活的配置需求.幸运的是,Kubernetes提 ...

  3. 【YashanDB数据库】YAS-02079 archive log mode must be enabled when database is in replication mode

    [标题]错误码处理 [问题分类]调整归档 [关键字]关闭归档.YAS-02079.replication mode [问题描述]执行alter database noarchivelog 关闭归档时, ...

  4. 真人模特失业?AI虚拟试衣一键成图,IDM-VTON下载介绍

    在电商行业竞争尤为激烈的当下,除了打价格战外,如何有效的控制成本,是每个从业者都在思考的问题 IDM-VTON是一个AI虚拟换装工具,旨在帮助服装商家解决约拍模特导致的高昂成本问题,只需一张服装图片, ...

  5. 坑人的opencv安装

    我想捡起来C++,最近在看opencv,于是我想着一起吧. 但是我低估了这个小麻烦的魅力,曾经安装opencv c++版本就头秃,如今依然头秃.说明我没长进啊-- 折腾了两天,终于装上了. 其中最麻烦 ...

  6. Angular 18+ 高级教程 – Component 组件 の Attribute Directives 属性型指令

    介绍 指令就是没有模板的组件.除了模板其它的都有,比如 selector.inject.@Input.lifecycle 等等. 那既然都有完整的组件了,为什么还搞一个少掉模板的指令呢? 很简单啊,因 ...

  7. JavaScript Bom和Dom的一般性详解

    一.JavaScript的组成 JavaScript的实现包括以下3个部分: ECMAScript(核心) 描述了JS的语法和基本对象. 文档对象模型 (DOM) 处理网页内容的方法和接口 浏览器对象 ...

  8. C#实现信创国产Linux桌面录制成MP4(源码,银河麒麟、统信UOS)

    信创国产化已是大势所趋,在国产操作系统上的应用开发的需求越来越多,比如,有客户需要在银河麒麟和统信UOS上实现录制桌面生成一个mp4文件.那么这个要如何实现了? 一. 技术方案 要完成这些功能,具体来 ...

  9. 华为GaussDB数据库(单机版)在ARM环境下的安装指南

    一.软件版本 机器配置:8核16G,CPU: Huawei Kunpeng 920 2.9GHz 操作系统:EulerOS 2.8 64bit with ARM 数据库版本:GaussDB Kerne ...

  10. 深入理解 Nuxt.js 中的 app:error 钩子

    title: 深入理解 Nuxt.js 中的 app:error 钩子 date: 2024/9/27 updated: 2024/9/27 author: cmdragon excerpt: 摘要: ...