首先介紹如何宣告介面,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