首先介紹如何宣告介面,GObject system中介面的宣告方式與類別的宣告很類似,所有的介面都必須直接或間接繼承自最上層稱為G_TYPE_INTERFACE的介面,並透過g_type_register_static將其註冊至GObject system。前段曾提過介面是特化的類別,這就是一個明顯的例證。
.... .... .... #define DRAWABLE_IFACE (drawable_get_type()) #define DRAWABLE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), DRAWABLE_IFACE, Drawable)) #define IS_DRAWABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), DRAWABLE_IFACE)) #define DRAWABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE((inst), DRAWABLE_IFACE, DrawableInterface)) typedef struct _Drawable Drawable; typedef struct _DrawableInterface DrawableInterface; struct _DrawableInterface { GTypeInterface parent; void (*draw)(Drawable* self); }; GType drawable_get_type(); void draw_object(Drawable* drawable); .... .... .... static void drawable_base_init(DrawableInterface* self); static void drawable_base_finalize(DrawableInterface* self); static void drawable_class_init(DrawableInterface* self); GType drawable_get_type() { static GType type = 0; if (type == 0) { static const GTypeInfo info = { sizeof(DrawableInterface), (GBaseInitFunc)drawable_base_init, (GBaseFinalizeFunc)drawable_base_finalize, (GClassInitFunc)drawable_class_init, NULL, NULL, }; type = g_type_register_static(G_TYPE_INTERFACE, "Drawable", &info, 0); } return type; } static void drawable_base_init(DrawableInterface* self) { g_print("Drawable(0x%08x)::base::initialize\n", (guint)self); } static void drawable_base_finalize(DrawableInterface* self) { g_print("Drawable(0x%08x)::base::finalize\n", (guint)self); } static void drawable_class_init(DrawableInterface* self) { g_print("Drawable(0x%08x)::class::initialize\n", (guint)self); } void draw_object(Drawable* drawable) { if (!IS_DRAWABLE(drawable)) { g_print("%s(0x%08x) is not drawable.\n", G_OBJECT_TYPE_NAME(drawable), (guint)drawable); return; } DRAWABLE_GET_INTERFACE(drawable)->draw(drawable); } .... .... ....由於介面並無法攜帶類別資料,故宣告介面時,僅需專注於方法的宣告即可。在此賦予drawable一個方法稱為draw,實作drawable者可將畫圖的程式邏輯實作於此方法內。接著,令Rectangle類別實作drawable介面。
.... .... .... static void drawable_init(DrawableInterface* iface); static void rectangle_draw(Rectangle* self); GType rectangle_get_type() { static GType type = 0; if (type == 0) { static const GTypeInfo info = { sizeof(RectangleClass), (GBaseInitFunc)rectangle_base_init, (GBaseFinalizeFunc)rectangle_base_finalize, (GClassInitFunc)rectangle_class_init, NULL, NULL, sizeof(Rectangle), 0, (GInstanceInitFunc)rectangle_init, NULL }; type = g_type_register_static(SHAPE_TYPE, "Rectangle", &info, 0); { static const GInterfaceInfo interface_info = { (GInterfaceInitFunc)drawable_init, }; g_type_add_interface_static(type, DRAWABLE_IFACE, &interface_info); } } return type; } .... .... .... static void drawable_init(DrawableInterface* iface) { g_print("Rectangle(0x%08x)::Drawable::initialize\n", (guint)iface); iface->draw = (void*)rectangle_draw; } .... .... .... static void rectangle_draw(Rectangle* self) { g_print("Rectangle(0x%08x)::Drawable::draw\n", (guint)self); g_print("\t+------+\n" "\t| |\n" "\t+------+\n"); } .... .... ....要令某類別實作介面僅須於註冊型別時,透過g_type_add_interface_static向系統宣告即可,GObject system可讓型別同時註冊並擁有多個介面,當型別宣告介面後,其子類別也將自動繼承該介面,子類別若要改寫自父類別繼承而來的介面也只要經由g_type_add_interface_static重新宣告界面並實作之即可達到目地。
以下為測試碼:
.... .... .... int main(int argc, char** argv) { Rectangle* rect; Circle* circle; g_type_init(); rect = rectangle_new(4, 5); draw_object(DRAWABLE(rect)); rectangle_free(rect); circle = circle_new(6); draw_object(DRAWABLE(circle)); circle_free(circle); return 0; } .... .... ....測試碼執行結果:
> ./shape-test Shape(0x09de0250)::base::initialize Shape(0x09de0250)::class::initialize Shape(0x09dfafc0)::base::initialize Rectangle(0x09dfafc0)::base::initialize Drawable(0x09de01e8)::base::initialize Drawable(0x09de01e8)::class::initialize Drawable(0x09dfb010)::base::initialize Rectangle(0x09dfafc0)::class::initialize Rectangle(0x09dfb010)::Drawable::initialize Rectangle(0x09dda048)::instance::initialize Rectangle(0x09dda048)::SetProperty::Width(4) Rectangle(0x09dda048)::SetProperty::Height(5) Shape(0x09dda048)::constructor Rectangle(0x09dda048)::constructor Rectangle(0x09dda048, 4x5) is created. Rectangle(0x09dda048)::Drawable::draw +------+ | | +------+ Rectangle(0x09dda048)::dispose Shape(0x09dda048)::dispose Rectangle(0x09dda048)::finalize Shape(0x09dda048)::finalize Shape(0x09dfba00)::base::initialize Circle(0x09dfba00)::base::initialize Circle(0x09dfba00)::class::initialize Circle(0x09dda060)::instance::initialize Circle(0x09dda060)::SetProperty::Radius(6) Shape(0x09dda060)::constructor Circle(0x09dda060)::constructor Circle(0x09dda060, r=6) is created. (process:2161): GLib-GObject-WARNING **: invalid cast from `Circle' to `Drawable' Circle(0x09dda060) is not drawable. Circle(0x09dda060)::dispose Shape(0x09dda060)::dispose Circle(0x09dda060)::finalize Shape(0x09dda060)::finalize >
本範例原始碼下載
No comments:
Post a Comment