GObject面向对象的继承的例子

1、继承GObject的对象Boy(父类是GObject)
(1)头文件boy.h:

    #ifndef _BOY_H_
    #define _BOY_H_
    #include <glib-object.h>
    /**BOY_TYPE宏封装了boy_get_type函数,可以直接取得并替代Boy对象的ID标识;
     * BOY(obj)宏是G_TYPE_CHECK_INSTANCE_CAST宏的再一次封装,目的是将一个Gobject对象强制转换为Boy对象
    **/
    #define BOY_TYPE (boy_get_type())
    #define BOY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), BOY_TYPE, Boy))
     
    typedef struct _Boy Boy;
    typedef struct _BoyClass BoyClass;
    /**结构类型_Boy是Boy对象的实例,就是说我们每创建一个Boy对象,也就同时创建了一个Boy结构。
     * Boy对象中的parent表示此对象的父类,GObject系统中所有对象的共同的根都是GObject类,所以这是必须的;
     * 其它的成员可以是公共的,这里包括表示年龄的age,表示名字的name和表示方法的函数指针cry,
     * 外部代码可以操作或引用它们。
    **/
    struct _Boy
    {
        GObject parent;
        gint age;
        gchar *name;
        void (*cry)(void);
    };
    /**结构类型_BoyClass是Boy对象的类结构,它是所有Boy对象实例所共有的。
     * BoyClass中的parent_class是GObjectClass,同GObject是所有对象的共有的根一样,GObejctClass是所有对象的类结构的根。
     * 在BoyClass中我们还定义了一个函数指针boy_born,也就是说这一函数指针也是所有Boy对象实例共有的,
     * 所有的Boy实例都可以调用它;同样,如果需要的话,你也可以在类结构中定义其它数据成员。
    **/
    struct _BoyClass
    {
        GObjectClass parent_class;
        void (*boy_born)(void);
    };
    /**其余的函数定义包括三种:一种是取得Boy对象的类型ID的函数boy_get_type,这是必须有的;
     * 另一种是创建Boy对象实例的函数boy_new和boy_new_with_*,这是非常清晰明了的创建对象的方式,当然你也可以用g_object_new函数来创建对象;
     * 第三种是设定或取得Boy对象属性成员的值的函数boy_get_*和boy_set_*。
     * 正常情况下这三种函数都是一个对象所必需的,另外一个函数boy_info用来显示此对象的当前状态**/
    GType boy_get_type(void);
    Boy *boy_new(void);
    gint boy_get_age(Boy *boy);
    void boy_set_age(Boy *boy, int age);
    char *boy_get_name(Boy *boy);
    void boy_set_name(Boy *boy, char *name);
    Boy *boy_new_with_name(gchar *name);
    Boy * boy_new_with_age(gint age);
    Boy * boy_new_with_name_and_age(gchar *name, gint age);
    void  boy_info(Boy *boy);
    #endif // _BOY_H_

(2)实现文件boy.c:

    #include "boy.h"
    /**用LAST_SIGNAL来表示最后一个信号(不用实现的信号)是一种非常良好的编程风格**/
    enum { BOY_BORN, LAST_SIGNAL };
    static gint boy_signals[LAST_SIGNAL] = { 0 };
    static void boy_cry (void);
    static void boy_born(void);
    static void boy_init(Boy *boy);
    static void boy_class_init(BoyClass *boyclass);
     
    /**g_type_register_static函数用来注册对象的类型,它的第一个参数是表示此对象的父类的对象类型,我们这里是G_TYPE_OBJECT,这个宏用来表示GObject的父类;
     * 第二个参数表示此对象的名称,这里为"Boy";
     * 第三个参数是此对象的GTypeInfo结构型指针,这里赋值为&boyinfo;
     * 第四个参数是对象注册成功后返回此对象的整型ID标识。 **/
    GType boy_get_type(void)
    {
        static GType boy_type = 0;
        if(!boy_type) {
            static const GTypeInfo boy_info = {
                sizeof(BoyClass),
                NULL,NULL,
                (GClassInitFunc)boy_class_init,
                NULL,NULL,
                sizeof(Boy),
                0,
                (GInstanceInitFunc)boy_init
            };
            boy_type = g_type_register_static(G_TYPE_OBJECT,"Boy",&boy_info,0);
        }
        return boy_type;
    }
    /**boy_init和boy_class_init,它们分别用来初始化实例结构和类结构。它们并不被在代码中明显调用,
     * 关键是将其用宏转换为地址指针,然后赋值到GTypeInfo结构中,然后由GType系统自行处理,
     * 同时将它们定义为静态的也是非常必要的。 **/
    static void boy_init(Boy *boy)
    {
        boy->age = 0;
        boy->name = "none";
        boy->cry = boy_cry;
    }
    static void boy_class_init(BoyClass *boyclass)
    {
        boyclass->boy_born = boy_born;
        /**Boy对象定义了一个信号BOY_BORN,在对象创建时发出,表示Boy对象诞生。
        *同时还需要定义静态的整型指针数组来保存信号的标识
        **/
        boy_signals[BOY_BORN] = g_signal_new("boy_born",
                    BOY_TYPE,
                    G_SIGNAL_RUN_FIRST,
                    G_STRUCT_OFFSET(BoyClass,boy_born),
                    NULL,NULL,
                    g_cclosure_marshal_VOID__VOID,
                    G_TYPE_NONE, 0, NULL);
    }
    Boy *boy_new(void)
    {
        Boy *boy;
        boy = g_object_new(BOY_TYPE, NULL);
        //g_signal_emit向指定义对象的实例发射信号
        g_signal_emit(boy, boy_signals[BOY_BORN], 0);
        return boy;
    }
    int boy_get_age(Boy *boy)
    {
        return boy->age;
    }
    void boy_set_age(Boy *boy, int age)
    {
        boy->age = age;
    }
    char *boy_get_name(Boy *boy)
    {
        return boy->name;
    }
    void boy_set_name(Boy *boy, char *name)
    {
        boy->name = name;
    }
    Boy*  boy_new_with_name(gchar *name)
    {
        Boy *boy;
        boy = boy_new();
        boy_set_name(boy, name);
        return boy;
    }
    Boy*  boy_new_with_age(gint age)
    {
        Boy* boy;
        boy = boy_new();
        boy_set_age(boy, age);
        return boy;
    }
    Boy *boy_new_with_name_and_age(gchar *name, gint age)
    {
        Boy *boy;
        boy = boy_new();
        boy_set_name(boy,name);
        boy_set_age(boy,age);
        return boy;
    }
    static void boy_cry (void)
    {
        g_print("---The Boy is crying......\n");
    }
    static void boy_born(void)
    {
        g_print("---Message : A boy was born.\n");
    }
    void boy_info(Boy *boy)
    {
        g_print("---The Boy name is %s\n", boy->name);
        g_print("---The Boy age is %d\n", boy->age);
    }

2、继承自Boy的对象Man(父类是Boy)
(1)头文件man.h:

    #ifndef _MAN_H_
    #define _MAN_H_
    /**********Man继承自Boy对象,Man对象在Boy对象的基础上又增加了一个属性job和一个方法bye***********/
    #include "boy.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;
    struct _Man
    {
        Boy parent;
        gchar *job;
        void (*bye)(void);
    };
    struct _ManClass
    {
        BoyClass parent_class;
    };
     
    GType man_get_type();
    Man *man_new(void);
    gchar *man_get_job(Man *man);
    void man_set_job(Man *man, gchar *job);
    Man *man_new_with_name_age_and_job(gchar *name, gint age, gchar *job);
    void man_info(Man *man);
     
    #endif // _MAN_H_

(2)实现文件man.c:

    #include "man.h"
    static void man_bye(void);
    static void man_init(Man *man);
    static void man_class_init(Man *man);
    /**关键在于定义对象时将父对象实例定义为Boy,父类设定为BoyClass,在注册此对象时将其父对象类型设为BOY_TYPE。
     **/
    GType man_get_type(void)
    {
        static GType man_type = 0;
        if(!man_type) {
            static const GTypeInfo man_info = {
                sizeof(ManClass),
                NULL, NULL,
                (GClassInitFunc)man_class_init,
                NULL, NULL,
                sizeof(Man),
                0,
                (GInstanceInitFunc)man_init
            };
            /**在注册此对象时将其父对象类型设为BOY_TYPE**/
            man_type = g_type_register_static(BOY_TYPE, "Man", &man_info, 0);
        }
        return man_type;
    }
    static void man_init(Man *man)
    {
        man->job = "none";
        man->bye = man_bye;
    }
    static void man_class_init(Man *man)
    {
    }
    Man*  man_new(void)
    {
        Man *man;
        man = g_object_new(MAN_TYPE, 0);
        return man;
    }
    gchar* man_get_job(Man *man)
    {
        return man->job;
    }
    void  man_set_job(Man *man, gchar *job)
    {
        man->job = job;
    }
    Man*  man_new_with_name_age_and_job(gchar *name, gint age, gchar *job)
    {
        Man *man;
        man = man_new();
        boy_set_name(BOY(man), name);
        boy_set_age(BOY(man), age);
        man_set_job(man, job);
        return man;
    }
    static void man_bye(void)
    {
        g_print("+++Goodbye everyone!\n");
    }
    /**在设定对象属性时如用到父对象的属性要强制转换下,如取得对象的name属性,就必须用BOY(obj)->name,
     *因为Man本身没有name属性,而其父对象Boy有,所以用BOY宏将其强制为Boy类型的对象。
    **/
    void man_info(Man *man)
    {
        /**定义对象时将父对象实例定义为Boy,父类设定为BoyClass**/
        g_print("+++the man name is %s\n", BOY(man)->name);
        g_print("+++the man age is %d\n", BOY(man)->age);
        g_print("+++the man job is %s\n", man->job);
    }

3、main文件和makefile及运行
main.c文件:

    #include <glib.h>
    #include "boy.h"
    #include "man.h"
     
    int main(int argc, char *argv[])
    {
        Boy *tom, *peter;
        Man *green, *brown;
        g_type_init();//注意,初始化类型系统,必需
        g_print("**********************\n");
        tom = boy_new_with_name("Tom");
        tom->cry();
        boy_info(tom);
        g_print("**********************\n");
        peter = boy_new_with_name_and_age("Peter", 10);
        peter->cry();
        boy_info(peter);
        g_print("**********************\n");
        g_print("######################\n");
        green = man_new();
        /**设定Man对象的name属性用到其父对象Boy的方法**/
        boy_set_name(BOY(green), "Green");
        boy_set_age(BOY(green), 28);
        man_set_job(green, "Doctor");
        man_info(green);
        green->bye();
        g_print("######################\n");
        brown = man_new_with_name_age_and_job("Brown", 30, "Teacher");
        man_info(brown);
        brown->bye();
        g_print("######################\n");
        return TRUE;
    }

makefile文件:

    CC = gcc
    all:
        $(CC) -c boy.c `pkg-config --cflags glib-2.0 gobject-2.0`
        $(CC) -c man.c `pkg-config --cflags glib-2.0 gobject-2.0`
        $(CC) -c main.c `pkg-config --cflags glib-2.0 gobject-2.0`
        $(CC) -o simple boy.o man.o main.o `pkg-config --libs glib-2.0 gobject-2.0`

运行结果:
 

猜你喜欢

转载自blog.csdn.net/evsqiezi/article/details/83048501