GObject基本用法
GObject为C语言提供了面向对象支持
安装:
sudo apt install libglib2.0-dev
GObject模拟类的封装
为数据类型名称添加一些前缀(PT格式:P——Program,T——数据类型),模拟命名空间
所谓数据封装,就是将低层次的元素组合起来,形成新的、高层次实体的技术
纯C语言实现双向链表:
#ifndef _PROGRAM_LINKEDLIST
#define _PROGRAM_LINKEDLIST
typedef struct _Program_Linkedlist
{
struct _Program_Linkedlist *prev, *next;
void *data;
}_Program_Linkedlist;
typedef struct Program_Linkedlist
{
struct Program_Linkedlist *head, *tail;
}Program_Linkedlist;
#endif
使用了GObject模拟类的数据封装形式:
#ifndef _PROGRAM_LINKEDLIST
#define _PROGRAM_LINKEDLIST
typedef struct _Program_Linkedlist
{
struct _Program_Linkedlist *prev, *next;
void *data;
}_Program_Linkedlist;
typedef struct Program_Linkedlist
{
GObject parent_instance; //
struct Program_Linkedlist *head, *tail;
}Program_Linkedlist;
typedef struct _ProgramLinkedListClass
{
GObjectClass parent_class;
}ProgramLinkedListClass;
#endif
类是两个结构体的组合,一个是实例结构体,另一个是类结构体
上述的
Program_Linkedlist_t
是实例结构体,而
ProgramLinkedListClass
是类结构体,合称
ProgramLinkedList
类
实例结构体的第一个成员是
GObject
结构体,类结构体的的一个成员是
GObjectClass
结构体
它们分别是
GObject
类的实例结构体与类结构体
上述表述意为该类继承自
GObject
类
继承GObject类后可以:
- 基于引用计数进行内存管理
- 构建对象的构造函数和析构函数
- 设置对象属性的set/get函数
- 使用信号机制
对对象的实例化:
Program_Linkedlist *dlist = g_object_new(PM_TYPE_DLIST, NULL);
销毁实例
g_object_unref(dlist);
g_object_new
为对象的实例分配内存和初始化,然后将实例的引用计数设为1
g_object_unref
将对象的实例的引用计数减1,检测引用计数是否为0,是则释放空间
类的实例是对象,每个对象都有可能存在多个实例
实际上它们是同一个东西
呵呵
上述使用的
PM_TYPE_DLIST
是一个宏,其定义形式为:
#define PM_TYPE_DLIST (pm_dlist_get_type())
GType pm_dlist_get_type(void);
在C文件中,需要定义如下内容:
G_DEFINE_TYPE (Program_Linkedlist, pm_dlist, G_TYPE_OBJECGT)
void pm_dlist_init(Program_Linkedlist *self)
{
}
void pm_dlist_class_init(Program_LinkedlistClass *class)
{
}
G_DEFINE_TYPE
宏可以帮我们实现类的定义
第一个参数,是我们所定义的类的类名
第二个参数,是类的成员函数名称的前缀
第三个参数,是该类的父类
G_TYPE_OBJECT
指代
GObject
类的
g_object_get_type
函数
PT格式:
P_TYPE_T
宏
p_t_get_type()
函数
提供
p_t_get_type
函数可以让GObject识别你定义的数据类型
该函数的作用是向GObject库提供PT类的相关信息
需要包含:类初始化函数,实例初始化函数
本文简单总结
首先,你需要一个头文件和一个C文件
头文件中需要有这些东西:
- 类结构体定义,其中父类需要放在成员的第一位
- 实例结构体定义,其中父类需要放在成员的第一位
-
定义宏
P_TYPE_T
,这个宏等价于
p_t_get_type
函数
在C文件中需要有这些东西:
-
G_DEFINE_TYPE
宏,真正定义类,它的构造为:第一个参数为类型的名字,第二个参数是类的函数名的前缀,第三个参数是父类的
P_TYPE_T
宏 -
类的初始化函数
p_t_class_init
-
实例的初始化函数
p_t_init
一个简单的helloworld类:
类的头文件
#ifndef _PM_HELLOWORLD_H
#define _PM_HELLOWORLD_H
#include <glib-object.h>
#define PM_TYPE_HELLOWORLD (pm_helloworld_get_type())
typedef struct PMHelloWorld
{
GObject parentInstance;
}PMHelloWorld;
typedef struct PMHelloWorldClass
{
GObjectClass parentClass;
}PMHelloWorldClass;
#endif
GType pm_helloworld_get_type(void);
类的C文件
#include "class_C_1.h"
G_DEFINE_TYPE (PMHelloWorld, pm_helloworld, G_TYPE_OBJECT);
static void pm_helloworld_init(PMHelloWorld *self)
{
g_print("Hello world!\n");
}
static void pm_helloworld_class_init(PMHelloWorldClass *class)
{
}
main文件
#include <stdio.h>
#include "class_C_1.h"
int main()
{
// g_type_init(); g_type_init在2.36后可以自动执行
PMHelloWorld *helloworld = g_object_new(PM_TYPE_HELLOWORLD, NULL);
if (G_IS_OBJECT(helloworld))
printf("这是一个GObject对象\n");
return 0;
}
makefile文件
cflags=`pkg-config --cflags gobject-2.0`
libs=`pkg-config --libs gobject-2.0`
all:
make main
main: main.o class_C_1.o
gcc -o main main.o class_C_1.o $(libs)
main.o: main.c class_C_1.h
gcc -c main.c $(cflags)
class_C_1.o: class_C_1.h class_C_1.c
gcc -c class_C_1.c $(cflags)
clean:
rm class_C_1.o main main.o
remake:
make clean
make all