GObject のクラスの継承について学んでいきます。
Gobject で新しくクラスを作る場合、既存のクラスまたは、基底クラスの GObject を継承して作ります。
その際に、新し作るクラス用の構造体とインスタンス用の構造体の 2 つの構造体を作成し、 それをプログラムに登録する必要があります。
他のオブジェクト指向言語に慣れている方にとっては少し変な感覚ですが、GObject はあくまでもオブジェクト指向風のプログラミングができるライブラリです。 違和感のあるところも多少あります。
GObject のオブジェクトは、名前空間と名前で命名される慣習になっています。GObjet は G という名前空間と Object という名前で構成されています。GtkWidget は、Gtk という名前空間と Widget という名前で構成 されています。
ここでは基底クラスである GObject を継承して、MyObj というオブジェクトを作っていきます。 My が名前空間で、Obj が名前です。
クラスを作るときは、便利なマクロが用意されています。
#include <glib-object.h>
typedef struct _MyObjClass MyObjClass;
struct _MyObjClass
{
GObjectClass parent_class;
};
typedef struct _MyObj MyObj;
struct _MyObj
{
GObject parent;
int num;
};
static void
my_obj_class_init (MyObjClass *class){}
static void
my_obj_init (MyObj *self) {}
G_DEFINE_TYPE (MyObj, my_obj, G_TYPE_OBJECT)
int
main (int argc, char **argv)
{
GType type;
MyObj *obj;
type = my_obj_get_type ();
if (type)
g_print ("Registration successed : %lx\n", type);
else
g_print ("Registration failed.\n");
obj = g_object_new (my_obj_get_type(), NULL);
if (obj)
g_print ("Instantiation successed : %p\n", obj);
else
g_print ("Instantiation failed.\n");
g_object_unref (obj);
return 0;
}
クラスの構造体では、スーパークラスのメンバーのみを定義します。
インスタンスの構造体では、最初にスーパークラスのメンバーを定義して、 そのあとに、他のメンバーを登録していきます。
以下のとおりです。Windows の場合は通常版でも ARM64版 でも mingw64 で行ってください。
// ビルド
cc define.c -o define `pkg-config --cflags --libs gtk4`
// 実行
./define
// 結果
Registration successed : 600003991620
Instantiation successed : 0x600001d93e40
ファイナルクラス (最終型クラス) を作るマクロです。ファイナルクラスとはサブクラスを持たないクラスのことです。
実際にプログラミングをしていて、サブクラスを持たないクラスを作ることは多いと思います。このマクロはそのようなときに使います。
このマクロを使う場合には次の 3 つの注意点があります。
なお、サブクラスを持てる、G_DECLARE_DERIVABLE_TYPE というマクロもあります。
#include <glib-object.h>
// G_DECLARE_FINAL_TYPE は #include や #define などが終わったこの位置に記述しなければなりません。
G_DECLARE_FINAL_TYPE (MyObj, my_obj, MY, OBJ, GObject)
struct _MyObj {
GObject parent;
int num;
};
static void
my_obj_class_init (MyObjClass *class) {}
static void
my_obj_init (MyObj *self) {}
// G_DEFINE_TYPE マクロの記述も必要です
G_DEFINE_TYPE (MyObj, my_obj, G_TYPE_OBJECT)
int
main (int argc, char **argv) {
GType type;
MyObj *obj;
type = my_obj_get_type ();
if (type)
g_print ("Registration successed. The type is %lx.\n", type);
else
g_print ("Registration failed.\n");
obj = g_object_new (my_obj_get_type (), NULL);
if (obj)
g_print ("Instantiation successed. The instance address is %p.\n", obj);
else
g_print ("Instantiation failed.\n");
if (MY_IS_OBJ (obj)) // G_DECLARE_FINAL_TYPE マクロを使った場合だけ使えるマクロです
g_print ("obj is MyObj instance.\n");
else
g_print ("obj is not MyObj instance.\n");
if (G_IS_OBJECT (obj)) // G_DEFINE_TYPE マクロだけで使った場合も使えるマクロです
g_print ("obj is GObject instance.\n");
else
g_print ("obj is not GObject instance.\n");
g_object_unref (obj);
return 0;
}
// ビルド
cc declare.c -o declare `pkg-config --cflags --libs gtk4`
// 実行
./declare
// 結果
Registration successed. The type is 6000037f5620.
Instantiation successed. The instance address is 0x6000013f0360.
obj is MyObj instance.
obj is GObject instance.
マクロを使わない例も一応揚げておきます。
#include <glib-object.h>
typedef struct _MyObjClass MyObjClass;
struct _MyObjClass
{
GObjectClass parent_class;
};
typedef struct _MyObj MyObj;
struct _MyObj
{
GObject parent;
int num;
};
static void
my_obj_class_init (MyObjClass *class){}
static void
my_obj_init (MyObj *self) {}
GType
my_obj_get_type (void)
{
static GType type = 0;
GTypeInfo info;
if (type == 0)
{
info.class_size = sizeof (MyObjClass);
info.base_init = NULL;
info.base_finalize = NULL;
info.class_init = (GClassInitFunc) my_obj_class_init;
info.class_finalize = NULL;
info.class_data = NULL;
info.instance_size = sizeof (MyObj);
info.n_preallocs = 0;
info.instance_init = (GInstanceInitFunc) my_obj_init;
info.value_table = NULL;
type = g_type_register_static (G_TYPE_OBJECT, "MyObj", &info, 0);
}
return type;
}
int
main (int argc, char **argv)
{
GType type;
MyObj *obj;
type = my_obj_get_type ();
if (type)
g_print ("Registration successed : %lx\n", type);
else
g_print ("Registration failed.\n");
obj = g_object_new (my_obj_get_type (), NULL);
if (obj)
g_print ("Instantiation successed : %p\n", obj);
else
g_print ("Instantiation failed.\n");
g_object_unref (obj);
return 0;
}
以下のとおりです。Windows の場合は通常版でも ARM64版 でも mingw64 で行ってください。
// コンパイル
cc nonmacro.c -o nonmacro `pkg-config --cflags --libs gtk4`
// 実行
./nonmacro
// 結果
Registration successed : 6000000e9440
Instantiation successed : 0x6000024e9e60