GTK 的物件導向架構

GTK 基本上是使用 C 語言來撰寫,即使C語言本身不支援物件導向,但GTK在架構上運用了一些方式,使得使用GTK時可以支援許多物件導向的概念。

在物件導向的封裝特性上,GTK以結構(structure)的方式來模擬類別,事實上GTK也直接稱這些結構為類別,以建構GtkWindow的程式碼為例:
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

在函式的組織上,與GtkWindow相關的函式,都是以gtk_window名稱作為開頭,gtk_window_new()就像是物件導向程式語言中的建構式,如果要設置GtkWindow的相關屬性,例如標題名稱:
gtk_window_set_title(GTK_WINDOW(window), "哈囉!GTK+!");

gtk_window_set_title()的第一個參數接受GtkWindow指標,透過這種方式,讓實際上屬於全域的函 式,看來就像是專屬於GtkWindow所使用,就如同物件上所帶有的公開(public)方法(method)或成員函式(member function),而在私有(private)的模擬上,GTK使用static函式,例如在gtkwindow.c原始程式碼中,可以看到:
static void gtk_window_dispose            (GObject           *object);
static void gtk_window_destroy            (GtkObject         *object);
static void gtk_window_finalize           (GObject           *object);
static void gtk_window_show               (GtkWidget         *widget);
static void gtk_window_hide               (GtkWidget         *widget);
static void gtk_window_map                (GtkWidget         *widget);
static void gtk_window_unmap              (GtkWidget         *widget);
static void gtk_window_realize            (GtkWidget         *widget);
static void gtk_window_unrealize          (GtkWidget         *widget);

這些static函式不會出現在gtkwindow.h標頭文件中,僅可在gtkwindow.c中使用,這看起來就像是GtkWindow的專屬私用函式。

在繼承上,GTK實際上使用結構鏈接(link)的方式,在
第一個 GTK 程式 中看過以下的繼承關係:
GObject
 +--GInitiallyUnowned
     +-- GtkObject
           +-- GtkWidget
                 +-- GtkContainer
                       +-- GtkBin
                             +-- GtkWindow

以GtkContainer為例,在gtkcontainer.h中有如下的定義:
typedef struct _GtkContainer       GtkContainer;
...

struct _GtkContainer
{
  GtkWidget widget;
 
  GtkWidget *focus_child;
 
  guint border_width : 16;

  /*< private >*/
  guint need_resize : 1;
  guint resize_mode : 2;
  guint reallocate_redraws : 1;
  guint has_focus_chain : 1;
};

GtkContainer的成員中有一個GtkWidget,而再來看到gtkwidget.h:
typedef struct _GtkWindow          GtkWindow;
...
struct _GtkWidget
{
  /* The object structure needs to be the first
   *  element in the widget structure in order for
   *  the object mechanism to work correctly. This
   *  allows a GtkWidget pointer to be cast to a
   *  GtkObject pointer.
   */
  GtkObject object;
    ...
};


GtkWidget中有個成員為GtkObject,以如此的鏈結關係來維持物件上的繼承關係架構,而在gtk_window_set_title()函式的使用例子中:
gtk_window_set_title(GTK_WINDOW(window), "哈囉!GTK+!");

GTK_WINDOW是一個巨集,用來進行指標型態轉型動作:
#define GTK_WINDOW(obj)
          (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_WINDOW, GtkWindow))


G_TYPE_CHECK_INSTANCE_CAST巨集定義在GLib的gtype.h(
/usr/include/glib-2.0/gobject/gtype.h)中:
#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type)   
            (_G_TYPE_CIC ((instance), (g_type), c_type))


G_TYPE_CHECK_INSTANCE_CAST巨集會檢查instance是否為g_type的一個實例,如果不是的話就發出警示訊息,若是的話就將指標轉型為c_type型態(參考 G_TYPE_CHECK_INSTANCE_CAST 線上文件說明)。

即便在熟悉C++、Java等支援物件導向程式語言的人來說,這樣的架構在物件導向的概念上並不完整,但確實在易讀與維護性上加強了不少。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章