gobject創建一個新的實例(繼承和重構)

概述

在 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, 實例名))

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章