欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
GType 類(lèi)型系統 - 清華大學(xué)開(kāi)源軟件俱樂(lè )部 THOSS

GType 類(lèi)型系統

出自清華大學(xué)開(kāi)源軟件俱樂(lè )部 THOSS

跳轉到: 導航, 搜索

下面是 Wikipedia 上對類(lèi)型系統(type system)的定義:

In computer science, a type system defines how a programming language classifies values and expressions into types, how it can manipulate those types and how they interact.

GObject 提供了一套運行時(shí)的面向對象的類(lèi)型系統——GType。說(shuō)它是運行時(shí)的類(lèi)型系統,是因為類(lèi)型的定義、檢查、操作、轉換不是在編譯時(shí)進(jìn)行的,而是在程序運行過(guò)程中通過(guò)相關(guān)函數調用來(lái)完成;說(shuō)它是面向對象的,是因為它提供了類(lèi)、接口還有繼承的機制。

目錄

[隱藏]

    GType 類(lèi)型系統的功能

    GType 主要提供了以下幾個(gè)功能:

    • 基本類(lèi)型
    • 類(lèi)和接口
    • 查看類(lèi)型信息,如父類(lèi)、子類(lèi)和實(shí)現的接口列表
    • 類(lèi)型的向上和向下轉換,類(lèi)型檢查

    基本類(lèi)型

    所謂基本類(lèi)型是指系統自動(dòng)提供的,無(wú)須用戶(hù)自己定義的類(lèi)型。GType 定義了19種基本類(lèi)型:

    /* gtype.h */         #define G_TYPE_INTERFACE		G_TYPE_MAKE_FUNDAMENTAL (2)    #define G_TYPE_CHAR			G_TYPE_MAKE_FUNDAMENTAL (3)    #define G_TYPE_UCHAR			G_TYPE_MAKE_FUNDAMENTAL (4)    #define G_TYPE_BOOLEAN			G_TYPE_MAKE_FUNDAMENTAL (5)    #define G_TYPE_INT			G_TYPE_MAKE_FUNDAMENTAL (6)    #define G_TYPE_UINT			G_TYPE_MAKE_FUNDAMENTAL (7)    #define G_TYPE_LONG			G_TYPE_MAKE_FUNDAMENTAL (8)    #define G_TYPE_ULONG			G_TYPE_MAKE_FUNDAMENTAL (9)    #define G_TYPE_INT64			G_TYPE_MAKE_FUNDAMENTAL (10)    #define G_TYPE_UINT64			G_TYPE_MAKE_FUNDAMENTAL (11)    #define G_TYPE_ENUM			G_TYPE_MAKE_FUNDAMENTAL (12)    #define G_TYPE_FLAGS			G_TYPE_MAKE_FUNDAMENTAL (13)    #define G_TYPE_FLOAT			G_TYPE_MAKE_FUNDAMENTAL (14)    #define G_TYPE_DOUBLE			G_TYPE_MAKE_FUNDAMENTAL (15)    #define G_TYPE_STRING			G_TYPE_MAKE_FUNDAMENTAL (16)    #define G_TYPE_POINTER			G_TYPE_MAKE_FUNDAMENTAL (17)    #define G_TYPE_BOXED			G_TYPE_MAKE_FUNDAMENTAL (18)    #define G_TYPE_PARAM			G_TYPE_MAKE_FUNDAMENTAL (19)    #define G_TYPE_OBJECT			G_TYPE_MAKE_FUNDAMENTAL (20)

    可以發(fā)現多數基本類(lèi)型都對應到 C 的基本類(lèi)型,但有幾個(gè)特殊的基本類(lèi)型:G_TYPE_INTERFACE 代表接口類(lèi)型,G_TYPE_PARAM 代表對象屬性的參數說(shuō)明,G_TYPE_OBJECT 代表 GObject 類(lèi)型。關(guān)于 GType 的類(lèi)型有幾點(diǎn)需要強調:

    • 每一個(gè)類(lèi)型有一個(gè)C語(yǔ)言類(lèi)型為 GType 的唯一的標識符,這個(gè)標識符其實(shí)就是一個(gè)整形,上面這些宏返回的就是一個(gè) GType,自定義的類(lèi)(如 MY_IP_ADDRESS,也是如此);
    • 這個(gè)標識符用的不多,但是有些場(chǎng)合需要指定類(lèi)型,就需要用到它:
    1. new 一個(gè)對象的時(shí)候;
    2. 指定對象屬性的類(lèi)型;
    3. 指定 GValue 值的類(lèi)型;
    4. 聲明一個(gè)類(lèi)實(shí)現某個(gè)接口;
    5. GType 系統內部。

    類(lèi)和接口

    GType 類(lèi)型系統允許注冊類(lèi)、接口,支持聲明某個(gè)類(lèi)實(shí)現某個(gè)接口。由于 GObject 是所有類(lèi)的基類(lèi),所以實(shí)際上在定義、注冊和實(shí)現 GObject 類(lèi)的子類(lèi)這一節中已經(jīng)說(shuō)明了如何注冊類(lèi)了,下面主要講如何定義、注冊和實(shí)現一個(gè)接口。

    定義接口

    定義接口的方法和定義類(lèi)的方法十分類(lèi)似,主要區別在于接口不能實(shí)例化,所以不需要定義 instance 結構。下面是一個(gè)例子:

    #define MAMAN_IBAZ_TYPE                (maman_ibaz_get_type ())    #define MAMAN_IBAZ(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_IBAZ_TYPE, MamanIbaz))    #define MAMAN_IS_IBAZ(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_IBAZ_TYPE))    #define MAMAN_IBAZ_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), MAMAN_IBAZ_TYPE, MamanIbazInterface))         typedef struct _MamanIbaz MamanIbaz; /* dummy object */    typedef struct _MamanIbazInterface MamanIbazInterface;         /* 接口結構 */    struct _MamanIbazInterface {    /* 所有接口都是 GTypeInterface 的子類(lèi) */    GTypeInterface parent;         /* 虛函數列表 */    void (*do_action) (MamanIbaz *self);    };         GType maman_ibaz_get_type (void);         /* 一般都這樣封裝一下接口提供的函數 */    void maman_ibaz_do_action (MamanIbaz *self);

    要理解接口的定義和實(shí)現原理,首先需要理解“虛函數表”的概念,對 C++ 而言,每一個(gè)聲明為 virtual 的成員函數都會(huì )加到類(lèi)的“虛函數表”里面,這樣系統就能保證對象的實(shí)際類(lèi)型調用正確的虛函數實(shí)現,對 Java 而言,所有成員函數默認都是 virtual 的。GType 里面的接口結構其實(shí)就是一個(gè)“虛函數表”,里面保存了一些函數指針,每個(gè)實(shí)現這個(gè)接口的類(lèi)都保存一份獨立的接口結構拷貝,同時(shí)恰當設置里面的函數指針,保證使用的是自己的實(shí)現。

    下面是 maman_ibaz_get_type 和 maman_ibaz_do_action 函數的實(shí)現:

    GType    maman_ibaz_get_type ()    {    static GType type = 0;         if (!type)    {    type = g_type_register_static_simple (G_TYPE_INTERFACE, "MamanIbaz",    sizeof (MamanIbazInterface),    (GClassInitFunc) maman_ibaz_class_init,    0, NULL, 0);    }         return type;    }         void maman_ibaz_do_action (MamanIbaz *self)    {    MAMAN_IBAZ_GET_INTERFACE (self)->do_action (self);    }

    在定義一個(gè)接口的時(shí)候有兩個(gè) tricky 的地方:

    • MamanIbaz 結構并沒(méi)有被定義,而只是聲明。在使用接口的函數時(shí),假設類(lèi) MamanBaz 實(shí)現了接口 MamanIbaz,那么傳給函數的指針應該是 MAMAN_IBAZ(ptr_to_a_mamanbaz_object)。這和面向對象中接口的概念是一致的,實(shí)現了某個(gè)接口的類(lèi)的對象能向上轉換成接口的對象。
    • 在 maman_ibaz_do_action 函數的實(shí)現中,需要先通過(guò) MAMAN_IBAZ_GET_INTERFACE (self) 獲得一個(gè)接口結構(虛函數表),然后再調用虛表里面的 do_action 函數,由于 self 是由實(shí)現這個(gè)接口的對象轉換來(lái)的,所以這就能保證執行的 do_action 函數是 self 對象的類(lèi)所重載的版本。

    注冊接口

    在 GType 類(lèi)型系統中,類(lèi)和接口的注冊方法是一樣的,兩者的區別在于對 GTypeInfo 中各個(gè)域的作用。

    • base_init:一般都設為 NULL
    • base_finalize:一般都設為 NULL
    • class_init:接口的默認初始化函數,如果實(shí)現該接口的類(lèi)不提供初始化接口(虛表)的函數的話(huà),那么將由這個(gè)函數進(jìn)行初始化,很多接口也直接設為 NULL
    • class_finalize:和 class_init 相反

    接口實(shí)現

    接口的函數由實(shí)現該接口的類(lèi)提供。實(shí)現接口的類(lèi)在自己的 xxx_get_type 函數里面通過(guò) g_type_add_interface_static 函數來(lái)聲明需要實(shí)現的接口。通過(guò)一個(gè)例子很容易就明白了:

    static void maman_baz_do_action (MamanIbaz *self)    {    g_print ("Baz implementation of IBaz interface Action.\n");    }              static void    baz_interface_init (gpointer         g_iface,    gpointer         iface_data)    {    MamanIbazInterface *iface = (MamanIbazInterface *)g_iface;    iface->do_action = maman_baz_do_action;    }         GType    maman_baz_get_type (void)    {    static GType type = 0;    if (type == 0) {    static const GTypeInfo info = {    sizeof (MamanBazInterface),    NULL,   /* base_init */    NULL,   /* base_finalize */    NULL,   /* class_init */    NULL,   /* class_finalize */    NULL,   /* class_data */    sizeof (MamanBaz),    0,      /* n_preallocs */    NULL    /* instance_init */    };    static const GInterfaceInfo ibaz_info = {    (GInterfaceInitFunc) baz_interface_init,    /* interface_init */    NULL,               /* interface_finalize */    NULL          /* interface_data */    };    type = g_type_register_static (G_TYPE_OBJECT,    "MamanBazType",    &info, 0);    g_type_add_interface_static (type,    MAMAN_IBAZ_TYPE,    &ibaz_info);    }    return type;    }

    g_type_add_interface_static 函數需要用戶(hù)提供一個(gè)類(lèi)型為 GInterfaceInfo 的參數,該結構定義如下:

    struct _GInterfaceInfo    {    GInterfaceInitFunc     interface_init;    GInterfaceFinalizeFunc interface_finalize;    gpointer               interface_data;    };

    第一個(gè)域是“虛表”的初始化函數,有實(shí)現接口的類(lèi)提供,在這個(gè)函數中需要將虛表中的函數指針指向相應的實(shí)現函數。在上面的例子中,這個(gè)函數就是 baz_interface_init,它的第一個(gè)參數就是需要初始化的虛表。

    查看類(lèi)型信息

    GType 提供了 API 用于檢查一個(gè)類(lèi)型的各種信息,對用戶(hù)來(lái)說(shuō),比較常用的有幾個(gè):

    • g_type_parent:獲取父類(lèi)的類(lèi)型
    • g_type_class_ref:返回類(lèi)的 class 結構
    • g_type_interface_peek:返回類(lèi)所實(shí)現的某個(gè)接口的接口結構(虛表)
    • g_type_children:返回子類(lèi)列表
    • g_type_interfaces:返回實(shí)現的接口列表

    更多的 API 可以參考 GLib 的手冊。

    類(lèi)型轉換

    在定義類(lèi)和接口的時(shí)候,我們都需要定義一個(gè)宏,用于將其他類(lèi)型轉換成我們定義的類(lèi)型,例如 MY_IP_ADDRESS 宏和 MAMAN_IBAZ_TYPE 宏,這些宏在底層都調用 g_type_check_instance_cast 函數,顧名思義,這個(gè)函數首先會(huì )檢查轉換是否合法,這類(lèi)似于 C++ 中的 dynamic_cast。

    類(lèi)型轉換在 Gtk+ 的代碼中有大量的應用,例如下面的代碼:

    int main (int argc,    char *argv[])    {    GtkWidget *window, *ipaddress;    gint address[4] = { 1, 20, 35, 255 };         gtk_init (&argc, &argv);         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);    gtk_window_set_title (GTK_WINDOW (window), "GtkIPAddress");    gtk_container_set_border_width (GTK_CONTAINER (window), 10);         g_signal_connect (G_OBJECT (window), "destroy",         G_CALLBACK (gtk_main_quit), NULL);         ipaddress = my_ip_address_new ();    my_ip_address_set_address (MY_IP_ADDRESS (ipaddress), address);         g_signal_connect (G_OBJECT (ipaddress), "ip-changed",         G_CALLBACK (ip_address_changed), NULL);         gtk_container_add (GTK_CONTAINER (window), ipaddress);         gtk_widget_show_all (window);         gtk_main ();         return 0;    }

    GType 類(lèi)型系統內部的主要數據結構

    在 GType 類(lèi)型系統內部,每個(gè)類(lèi)和接口都與一個(gè) TypeNode 數據結構對應。

    struct _TypeNode    {    GTypePlugin *plugin;    guint        n_children : 12;    guint        n_supers : 8;    guint        _prot_n_ifaces_prerequisites : 9;    guint        is_classed : 1;    guint        is_instantiatable : 1;    guint        mutatable_check_cache : 1;	/* combines some common path checks */    /* 子類(lèi)列表 */    GType       *children;    /* 類(lèi)和接口保存的數據是不一樣的 */    TypeData * volatile data;    GQuark       qname;    GData       *global_gdata;    union {    /* 如果是一個(gè)類(lèi),這個(gè) union 保存的是實(shí)現的接口列表 */    IFaceEntry  *iface_entries;		/* for !iface types */    GType       *prerequisistes;    } _prot;    /* 父類(lèi)數組 */    GType        supers[1]; /* flexible array */    };

    TypeData 實(shí)際上是一個(gè) union,不同的類(lèi)型對應不同的結構:

    union _TypeData    {    CommonData         common;    IFaceData          iface;    ClassData          class;    InstanceData       instance;    };

    如果類(lèi)型是一個(gè)類(lèi),那么對應到 InstanceData,如果是接口,對應到 IFaceData:

    struct _InstanceData    {    CommonData         common;    guint16            class_size;    guint              init_state : 4;    GBaseInitFunc      class_init_base;    GBaseFinalizeFunc  class_finalize_base;    GClassInitFunc     class_init;    GClassFinalizeFunc class_finalize;    gconstpointer      class_data;    gpointer           class;    guint16            instance_size;    /* 私有數據的大小,通過(guò) g_type_class_add_private 設置 */    guint16            private_size;    /* 現在已經(jīng)不用這個(gè)域了 */    guint16            n_preallocs;    GInstanceInitFunc  instance_init;    };         struct _IFaceData    {    CommonData         common;    /* 用 GTypeInfo 里面的 class_size 域賦值 */    guint16            vtable_size;    /* 用 base_init 域賦值 */    GBaseInitFunc      vtable_init_base;    /* 用 base_finalize 域賦值 */    GBaseFinalizeFunc  vtable_finalize_base;    /* 用 class_init 域賦值 */    GClassInitFunc     dflt_init;    /* 用 class_finalize 域賦值 */    GClassFinalizeFunc dflt_finalize;    gconstpointer      dflt_data;    gpointer           dflt_vtable;    };

    可以發(fā)現,這兩個(gè)結構的內容基本等同于 GTypeInfo 結構的內容,用戶(hù)指定的類(lèi)型信息大部分是保存在這兩個(gè)結構里面的。

    那么,一個(gè)類(lèi)實(shí)現的接口信息又保存在哪里呢?在 TypeNode 結構里面有一個(gè) IFaceEntry 列表,每個(gè) IFaceEntry 都保存該類(lèi)實(shí)現的一個(gè)接口的信息。

    struct _IFaceEntry    {    GType           iface_type;    /* 類(lèi)實(shí)現的接口的虛表,每個(gè)類(lèi)獨立 */    GTypeInterface *vtable;    InitState       init_state;    };

    回憶前面的內容,類(lèi)需要為實(shí)現的接口提供一個(gè)初始化函數,這個(gè)函數是 GInterfaceInfo 結構的一個(gè)域,通過(guò) g_type_add_interface_static 函數來(lái)設置。這個(gè)初始化函數又是怎樣保存的呢?GType 為每一個(gè)接口關(guān)聯(lián)了一個(gè) IFaceHolder 結構的鏈表,每個(gè)表元素記錄一個(gè)實(shí)現該接口的類(lèi)的信息,其中包括該類(lèi)提供的 GInterfaceInfo 結構。

    struct _IFaceHolder    {    GType           instance_type;    GInterfaceInfo *info;    GTypePlugin    *plugin;    IFaceHolder    *next;    };

    到現在,關(guān)于一個(gè)類(lèi)型的所有信息如何設置、如何保存的問(wèn)題已經(jīng)講清楚了,在類(lèi)的實(shí)例化過(guò)程中將會(huì )用到這些信息。

    取自"
    打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
    猜你喜歡
    類(lèi)似文章
    生活服務(wù)
    分享 收藏 導長(cháng)圖 關(guān)注 下載文章
    綁定賬號成功
    后續可登錄賬號暢享VIP特權!
    如果VIP功能使用有故障,
    可點(diǎn)擊這里聯(lián)系客服!

    聯(lián)系客服

    欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久