概述
在 GObject世界里,类是两个结构体的组合,一个是实例结构体,另一个是类结构体。GOBJECT的继承需要实现实例结构体的继承和类结构体的继承,Gobject对象的初始化可分为两个部分:类结构体初始化和实例结构体初始化。类结构体初始化函数只被调用一次,而实例结构体的初始化函数的调用次数等于对象实例化的次数。这意味着,所有对象共享的数据,可保存在类结构体中,而所有对象私有的数据,则保存在实例结构体中。
宏定义解析G_DEFINE_TYPE
G_DEFINE_TYPE(Man, man, G_TYPE_OBJECT);
参数1 Man:注册新的类名称(与结构体同名)。
参数2 man:注册新类初始化函数前缀,比如shape_init(man *shape)。这里填写什么字符串(假设为:XXX),就要实现XXX_init,XXX_class_init,XXX_get_type。
参数3 G_TYPE_OBJECT:父类的类型,这里表示man的父类是OBJECT。其实就是对应父类的XXX_get_type。
定义一个新的类,最少要实现三个函数
/* 类结构 */
typedef struct _mytest {
int member1;
char member2;
void (*func)(void);
/* 略 */
} Mytest;
//对象初始化函数
void mytest_init(Mytest *arg);
//类的初始化函数
void mytest_class_init(MytestClass *class);
//该函数实现向GObject注册我们新定义的mytest类,可通过G_DEFINE_TYPE进行实现。
Gtype mytest_get_type(void);
第一个函数是实例结构体初始化,第二个是类结构体初始化,第三个是实现向GObject注册我们新定义的mytest类,可通过G_DEFINE_TYPE进行实现。
Demo实现了Man类Teacher类,Teacher类继承了Man类,并且重载了Man类的info()函数
man.h
#ifndef _MAN_H_
#define _MAN_H_
#include <glib-object.h>
//宏定义这个函数
#define MAN_TYPE (man_get_type())
//为了后面的继承需要这个宏定义
#define MAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), MAN_TYPE, Man))
typedef struct _Man Man;
typedef struct _ManClass ManClass;
//实例结构体,结构体的首元素类型必须是Gobject
struct _Man{
GObject parent;
gchar* name;
int age;
void (*info) (void);
int (*SetAge)(Man *man,int age);
int (*GetAge)(Man *man);
};
//类结构体,结构体的首元素必须是GObjectClass
struct _ManClass{
GObjectClass parent_class;
};
//被宏定义的函数在这里声明
GType man_get_type(void);
void info_func(void);
int set_age(Man *man,int age);
int get_age(Man *man);
#endif
man.c
#include "man.h"
#include <glib.h>
//这里必须要
G_DEFINE_TYPE(Man, man, G_TYPE_OBJECT);
void info_func(void)
{
g_print("This is man info func\n");
}
static void man_init(Man* man)
{
man->age = 0;
man->name = "";
man->info = info_func;
man->SetAge = set_age;
man->GetAge = get_age;
g_print("This is man_init func\n");
}
static void man_class_init(ManClass* manClass)
{
g_print("This is man_class_init func\n");
}
int set_age(Man *man,int age)
{
man->age = age;
return 0;
}
int get_age(Man *man)
{
return man->age;
}
teacher.h
#ifndef _TEACHER_H_
#define _TEACHER_H_
#include "man.h"
//宏定义这个函数
#define TEACHER_TYPE (teacher_get_type())
typedef struct _Teacher Teacher;
typedef struct _TeacherClass TeacherClass;
//结构体的第一个元素是Man
struct _Teacher{
Man parent;
gint salary;
gchar* duty;
gchar* (*GetDuty)(Teacher*);
};
//结构体的第一个元素是ManClass
struct _TeacherClass{
ManClass parent_class;
};
void teacher_info(void);
//被宏定义的函数在这里声明
GType teacher_get_type(void);
gchar* get_duty(Teacher* tea);
#endif
teacher.c
#include "teacher.h"
//这里必须要
G_DEFINE_TYPE(Teacher, teacher, MAN_TYPE);
static void teacher_init(Teacher* tea)
{
Man* man = MAN(tea);
man->name = "man";
man->age = 12;
//重构info函数
man->info = teacher_info;
tea->salary = 10000;
tea->duty = "jiangshi";
tea->GetDuty = get_duty;
}
static void teacher_class_init(TeacherClass* TeacherClass)
{
g_print("%s\n",__func__);
}
void teacher_info(void)
{
g_print("%s\n",__func__);
}
gchar* get_duty(Teacher* tea)
{
return tea->duty;
}
main.c
#include "man.h"
#include "teacher.h"
#include <glib.h>
int main(void)
{
Man* man1 = NULL;
//创建一个对象并返回对象的指针
man1 = g_object_new(MAN_TYPE, NULL);
man1->info();
man1->SetAge(man1,19);
g_print("man1->age = %d\n",man1->GetAge(man1));
//销毁对象
g_object_unref(man1);
Teacher* tea = NULL;
tea = g_object_new(TEACHER_TYPE, NULL);
//info函数被重构
MAN(tea)->info();
g_print("tea->duty=%s\n",tea->GetDuty(tea));
g_object_unref(tea);
return 0;
}
运行结果
root@ubuntu:/code/test/ManObject# gcc *.c `pkg-config --cflags --libs glib-2.0 gobject-2.0`
root@ubuntu:/code/test/ManObject# ./a.out
This is man_class_init func
This is man_init func
This is man info func
man1->age = 19
teacher_class_init
This is man_init func
teacher_info
tea->duty=jiangshi
root@ubuntu:/code/test/ManObject#
总结
到最后,其实可以抛开复杂的底层实现,简单的归纳为下面几点:
1、在.h中加入头文件#include <glib-object.h>;
2、在.h中定义实例结构体和类结构体;
3、在.h中写宏定义#define XXX_TYPE (xxx_get_type());
4、在.h中声明xxx_get_type()函数
5、在.c中使用宏定义G_DEFINE_TYPE;
6、在.c中定义xxx_init()函数和xxx_class_init()函数
7、如果这个类要作为父类,则还需要在.h宏定义#define XXX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), XXX_TYPE, 实例名))