GNOME3用アプリケーション開発に入門してみる その2

GObject

GObject Reference Manual: GObject Reference Manual

C言語オブジェクト指向を実現する仕組み。 他言語用にAPIを提供する仕組みも備えているので、 Cで書けばC++はもちろんPythonPHPとかからも使えるようになる。 たぶん逆もしかり。

ざっと見ではC++のvtableとかマングル名とかをCの構造体や命名規則、 マクロで実装している感じで合っていると思う。 加えて参照カウンタやObserverパターンのためのsignalの規則もあるっぽい。

チュートリアルから開始。

ヘッダファイルはハイフンかアンダースコアで区切るのが一般的っぽい。 privateを末尾につけた場合はインストールしない。

とりあえず maman-bar.h をコピペして、Object Construction, Object Destruction あたりまで進めてみる。

/*
 * Copyright/Licensing information.
 */

/* inclusion guard */
#ifndef __MAMAN_BAR_H__
#define __MAMAN_BAR_H__

#include <glib-object.h>
/*
 * Potentially, include other headers on which this header depends.
 */

/*
 * Type macros.
 */
#define MAMAN_TYPE_BAR                  (maman_bar_get_type ())
#define MAMAN_BAR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
#define MAMAN_IS_BAR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
#define MAMAN_BAR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
#define MAMAN_IS_BAR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
#define MAMAN_BAR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))

typedef struct _MamanBar        MamanBar;
typedef struct _MamanBarClass   MamanBarClass;
typedef struct _MamanBarPrivate MamanBarPrivate;

struct _MamanBar
{
  /* Parent instance structure */
  GObject parent_instance;

  /** Private data pointer */
  MamanBarPrivate* priv;

  /* instance members */
};

struct _MamanBarClass
{
  /* Parent class structure */
  GObjectClass parent_class;

  /* class members */
};

/* used by MAMAN_TYPE_BAR */
GType maman_bar_get_type (void);

/*
 * Method definitions.
 */

#endif /* __MAMAN_BAR_H__ */
/*
 * Copyright information
 */

#include "maman-bar.h"
#include <glib.h>
#include <glib/gprintf.h>

/* If you use Pimpls, include the private structure 
 * definition here. Some people create a maman-bar-private.h header
 * which is included by the maman-bar.c file and which contains the
 * definition for this private structure.
 */
struct _MamanBarPrivate
{
  GObject *an_object;

  gchar *a_string;
};

G_DEFINE_TYPE_WITH_PRIVATE (MamanBar, maman_bar, G_TYPE_OBJECT)

static void
maman_bar_dispose (GObject *gobject)
{
  MamanBar *self = MAMAN_BAR (gobject);
  g_printf("maman_bar_dispose\n");

  /* In dispose(), you are supposed to free all types referenced from this
   * object which might themselves hold a reference to self. Generally,
   * the most simple solution is to unref all members on which you own a 
   * reference.
   */

  /* dispose() might be called multiple times, so we must guard against
   * calling g_object_unref() on an invalid GObject by setting the member
   * NULL; g_clear_object() does this for us.
   */
  // g_clear_object (&self->priv->an_object);

  /* Always chain up to the parent class; there is no need to check if
   * the parent class implements the dispose() virtual function: it is
   * always guaranteed to do so
   */
  G_OBJECT_CLASS (maman_bar_parent_class)->dispose (gobject);
}

static void
maman_bar_finalize (GObject *gobject)
{
  MamanBar *self = MAMAN_BAR (gobject);
  g_printf("maman_bar_finalize\n");

  g_free (self->priv->a_string);

  /* Always chain up to the parent class; as with dispose(), finalize()
   * is guaranteed to exist on the parent's class virtual function table
   */
  G_OBJECT_CLASS (maman_bar_parent_class)->finalize (gobject);
}

static void
maman_bar_class_init (MamanBarClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  g_printf("maman_bar_class_init\n");

  gobject_class->dispose = maman_bar_dispose;
  gobject_class->finalize = maman_bar_finalize;
}

static void
maman_bar_init (MamanBar *self)
{
  self->priv = maman_bar_get_instance_private (self); 
  g_printf("maman_bar_init\n");

  self->priv->an_object = NULL; // g_object_new (MAMAN_TYPE_BAZ, NULL);
  self->priv->a_string = g_strdup ("Maman");
}

生成と破棄はたぶんこんな感じ。

#include "maman-bar.h"

int main(int argc, char const* argv[]) {
    GObject* bar = g_object_new (MAMAN_TYPE_BAR, NULL);
    g_object_unref(bar);
    return 0;
}

破棄がdisposeとfinalizeで分かれているのは参照カウンタがループしている時のためっぽい。