試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

Vala言語におけるクラス継承時の親クラスのコンストラクタの呼び出しに関する追加メモ

Vala言語向けのバインディングを用いることでGTK+などの外部パッケージを用いたプログラムが作成できるが、そのようなパッケージの言語バインディングに用意されているクラスを継承するときに、クラスに元々あるコンストラクタをValaのbase()で呼ぼうとしても失敗することがある。
例えば、GTK+のウィンドウ(Gtk.Window)のクラスを継承して

  class MainWindow : Gtk.Window
  {
    public MainWindow (Gtk.WindowType type)
    {
      base (type);
      (処理...)
    }
  }

のようにすると、コンパイルしようとしても「undefined reference to `gtk_window_construct'」のようになって、中間ファイルのC言語のコードからネイティブコードにリンクするところで失敗する。
Vala向けのバインディングでは、このようなコンストラクタ引数から設定されるメンバ変数は、親クラスのコンストラクタを呼ぶことによってではなく、子クラスのコンストラクタ内で個別に直接値を設定する形をとるものが多い。

  class MainWindow : Gtk.Window
  {
    public MainWindow (Gtk.WindowType type)
    {
      this.type = type;  // トップレベルかポップアップかを引数から設定
      (処理...)
    }
  }

メンバの名前は.vapiファイルやリファレンスなどからそれらしいものを探して見つける。ここでは型が「Gtk.WindowType」でウィンドウタイプを指定するのに使われそうなものとして「type」があったのでこれに代入した。
下は例。

using Gtk;

/*
 * valac --pkg gtk+-2.0 -o gtkhello gtkhello.vala
 */

namespace GtkHello
{
  class MainWindow : Gtk.Window
  {
    public MainWindow (Gtk.WindowType type)
    {
      //base (type);  // undefined reference to `gtk_window_construct'
      this.type = type;  // 実際はウィンドウタイプの場合トップレベルなら指定しなくてもOK
      Gtk.Button btn = new Gtk.Button.with_mnemonic ("_Good bye");
      btn.clicked += Gtk.main_quit;
      this.add (btn);
      this.set_default_size (200, 150);
     }
  }
  class MainClass
  {
    public static void main (string[] args)
    {
      Gtk.init (ref args);
      MainWindow win = new MainWindow (Gtk.WindowType.TOPLEVEL);
//      MainWindow win = new MainWindow (Gtk.WindowType.POPUP);  // ポップアップにする場合
      win.show_all ();
      win.destroy += Gtk.main_quit;
      Gtk.main ();
    }
  }
}

上のコードをコンパイルして実行すると「Good bye」と書かれたボタンだけを含んだウィンドウが表示され、このボタンもしくはウィンドウマネージャの「閉じる」ボタンを押すと終了する。

関連記事:

使用したバージョン:

  • Vala 0.7.3