GObject

GObjectは、移植性の高いオブジェクトシステムと言語間の透過的相互運用性を提供するフリーなライブラリである。GObjectはC言語で実装されており、他の言語ではバインディングによって利用可能となっている。

1. 歴史
-----

GLibとlibcにのみ依存しており、GNOMEの基礎として GTK、Pango、Accessibility Toolkit、多くのGNOMEライブラリやアプリケーションなど広範囲に利用されている。GTK 2.0以前は、GObjectのコードはGTK+の一部だった。ただし、当時はGObjectとは呼ばれておらず、ベースクラスは GtkObject と呼ばれていた。

GTK 2.0リリースの際に、オブジェクトシステムを汎用ユーティリティとすべく、別ライブラリとして分離した。その際にGUI関係でない GtkObject クラスの大部分は新たなベースクラスである GObject に移された。GTK 2.0のリリースされた2002年3月11日以降、GObjectは独立したライブラリとして存在し続け、現在ではGUI以外のCUIアプリケーションやサーバアプリケーションにも広く使われている。

2. GLibとの関係
-----------

GObjectのマニュアル等はGLibとは別にあり、ライブラリファイルとしても別になっているが、ソースコードはGLibのソースツリー内にあって、GLibと共に配布されている。このため、GObjectのバージョン番号はGLibのものを使っており、GLibパッケージの一部とされることが多い。

3. 型システム
--------

GObjectフレームワークの基盤として、汎用の動的型システム GType がある。GTypeシステムは全オブジェクトの実行時記述を保持し、各種言語バインディングを実現するグルーコードからそれを使うことができる。型システムは任意の単一継承クラス階層を扱え、同時にクラスでないデータ型も扱える。

GTypeは登録されている型に属する値のコピー、代入、破棄の方法を知っている。整数などの型ではこれらは自明だが、複雑なオブジェクトには参照カウントがあるものもあれば、参照カウントのないものもある。型システムが参照カウントのあるオブジェクトを「コピー」するとき、一般に単に参照カウントをインクリメントするだけである。しかし、参照カウントのないオブジェクトのコピーでは、メモリを確保して実際にコピーを生成する。

この基本機能を使って GValue が実装されている。これは汎用コンテナ型であり、型システムが把握している任意の型の値を保持できる。このようなコンテナは、全てのネイティブ値をそのような型タグコンテナに格納する動的型付き言語とやりとりする際に特に便利である。

3.1. 基本型
--------

クラスと関連のない型を //non-classed// と称する。そのような型と何らかの rootクラスに対応した全ての型を総称して「基本型」と呼び、それ以外の型を「派生型」と呼ぶ。これらは比較的閉じた体系であり、一般ユーザーが独自の基本型を生成することはないものと想定されているが、生成は可能であり、GObject クラスに基づかないクラス階層を独自に作ることもできる。

GLib 2.9.2では、//non-classed// の基本型は以下の通りである。

空の型、C言語の void に対応。
C言語の char、int、long、64ビット整数に対応した型。
ブーリアン型。
列挙型とフラグ型。C言語の enum に対応するが、後者はビットフィールドにのみ使われる。
IEEE 754の単精度および倍精度の浮動小数点数。C言語の float と double に対応。
文字列型。C言語の char * に対応。
不透明ポインタ型。C言語の void * に対応。//classed// の基本型は以下の通りである。

標準クラス継承ツリーのrootである GObject のインスタンスの基底クラス型。
基底インタフェース型。標準インタフェース継承ツリーの rootを表している。
ボックス化用の型。単純な値オブジェクトや外部オブジェクトを参照カウント付きの「ボックス」で包むのに使われる。
「パラメータ記述オブジェクト」用の型。オブジェクトのプロパティのメタデータを記述するのに使われる。型システムによって自動的にインスタンス化できる型を //instantiable// と称する。そのような型の重要な特徴は、インスタンスの先頭数バイトに必ずその型に対応したクラス構造へのポインタが格納されている点である。このため、instantiableな型は必ずクラスと対応している。逆にnon-classedな型は instantiableではない。また、classedな型はインタフェース型などを除いてinstantiableである。

3.2. 派生型
--------

GObjectの組み込みの基本型から派生する型は4種類に分けられる。

列挙型とフラグ型 オブジェクトシステムとの関連で何らかの形で使われる列挙型や整数ベースのビットフィールド型。例えば、オブジェクトのプロパティの型など。一般にこれらの型の登録を行う初期化コードは glib-mkenumsというツールで自動生成され、別ファイルに格納される。 ボックス化型 完全なクラス型にするには単純すぎるデータ構造だが、型システムに登録する必要があるもの。例えば、あるクラスに background-color というプロパティを追加したいとする。その値は struct color { int r, g, b; } のようなデータ構造のインスタンスである。これを GObject のサブクラスにしたくない場合、ボックス化型で表し、コピーや解放といった機能を提供できる。GObjectにはGLibの単純なデータ型を包んだ各種ボックス化型が最初から備わっている。ボックス化型は、外部オブジェクトのタグ付きコンテナとしても使える。 不透明ポインタ型 場合によっては、コピーや解放といった機能も不要で、ボックス化型でも大げさすぎるというオブジェクトもある。そのようなオブジェクトは単に不透明ポインタ  として扱っても良いが、派生ポインタ型を生成することで、それがある特定用途のオブジェクトであることを示すことができる。 クラス型とインタフェース型 GObjectアプリケーションにおける大半の型はクラス型であり、通常のオブジェクト指向的な感覚で言えば、rootクラス GObject から直接または間接的に派生する。Java風のインタフェースもあるが、2006年現在ではあまり使用されていない。GIMPはGObjectのインタフェース型を使っている。

4. メッセージング・システム
---------------

GObjectのメッセージングシステムは、相補的な //closure// と //signal// から構成される。

Closure コールバックを一般化したもの。C言語とC++以外にもバインディングがある言語から使える。例えば、PythonやJavaのコードをClosureの機構で GObjectから呼び出すことができる。Signal Closureを呼び出す一次機構。オブジェクトは、あるSignalとClosureのマッピングを指定したSignalリスナーを登録する。登録されたSignalが発信されると、対応するClosureが呼び出される。GTKでは、全てのネイティブGUIイベントはGObjectのSignalを発信でき、対応するリスナーがそれに対して動作する。

5. クラス実装
--------

GObjectのクラスはクラス構造体とインスタンス構造体という少なくとも2つの構造体で実装される。

クラス構造体 C++におけるvtableに相当する。先頭にスーパークラスのクラス構造体がある。その後に関数ポインタ群があり、それぞれがクラスの仮想メソッドを指している。クラス固有変数を使って、クラス変数をエミュレートできる。 インスタンス構造体 オブジェクトのインスタンス毎に存在する。先頭にスーパークラスのインスタンス構造体がある。その後にインスタンス固有の変数群があり、C++のメンバ変数に対応する。C言語の構造体には“public”、“protected”、“private”といったアクセス修飾がないので、インスタンス構造体にプライベートデータへのポインタ _priv がある。プライベート構造体は共通ヘッダファイルに宣言することはできるが、定義は個々の実装ファイルでのみ行われ、外部から見えないようにしている。プライベート構造体をGTypeに登録すると、自動的にオブジェクトシステムで確保される。プライベートデータが必要なとき常に G_TYPE_INSTANCE_GET_PRIVATE を使うようにすれば、_priv ポインタを構造体に含める必要はない。

GObjectフレームワークの欠点は、冗長性である。新たなクラスを生成するとき、型登録や各種マクロを多量にコーディングする必要があり、その多くは決まりきった形式である。GObject BuilderやGOB2はこの問題に対処するツールであり、Java風の構文からコードを生成できる。GOB2で書かれたコードはコンパイル前にC言語のコードに展開される。他にもC#風の文法でコーディングできるValaがある。

6. 利用
-----

C言語とGObjectを使っているフリーソフトウェアプロジェクトとしては、GNOMEデスクトップ、GTKツールキット、GIMP画像編集プログラムなどがある。

GObjectを使ったアプリケーションはC言語で書かれていることが多いが、GObject自体はC++、Java、Ruby、Python、.NET/Monoなどのオブジェクトシステムともうまくマッピングできる。従って、GObjectフレームワークを使ったライブラリに言語バインディングを作るのは比較的簡単である。

しかし、C言語でGObjectのコードを書くのは若干大変である。特に高級オブジェクト指向言語に慣れたプログラマにとっては苦痛かもしれない。例えば、ちょっとしたサブクラスを書くだけで数百行のコードを必要とする。とはいうものの、GObjectを使うことでC言語でオブジェクト指向的なコーディングが可能となる。

一級オブジェクトは存在しないが、GObjectアプリケーションは実行時にクラスやインタフェースのようなメタオブジェクトを生成でき、イントロスペクションもサポートできる。この機能は言語バインディング以外にGladeなどのGUI設計アプリケーションで使われ、GObjectクラスを提供する共有ライブラリをロードし、そのクラスの全プロパティの一覧を獲得し、型情報とドキュメンテーション文字列を完成させるといったことが可能となる。

7. 他のオブジェクトシステムとの比較
-------------------

GObjectはC言語での完全なオブジェクトシステムであり、C言語から派生したC++やObjective-Cと同等のものと見ることもできる。C++とGObjectの明らかな違いは、GObjectが多重継承をサポートしていない点である。

もう1つの重要な違いは、C++やObjective-Cが独立した言語であるのに対して、GObjectは単なるライブラリであり、新たな構文やコンパイラ機能を追加しているわけではないという点である。例えば、GObjectベースのコードを書くとき、明示的な cast が頻繁に必要となる。従ってGObjectとC言語の組合せを通常のC言語とは別の言語と考えたとき、それはC++とは異なり、通常のC言語の厳密なスーパーセットとなっている。

C++コンパイラを対象とした標準ABIは存在しないので、あるC++コンパイラでコンパイルされたライブラリから、別のC++コンパイラでコンパイルされたライブラリを呼び出せないことがある。そのような互換性を必要とする場合、C++メソッドはC言語の関数としてエクスポートされる必要があり、C++のオブジェクトシステムが部分的に破綻する。原因の一部は、C++コンパイラがエクスポートするシンボルの一意性を保証するために、それぞれ独自に名前修飾しているためである。一方これとは対照的に、C言語にはオーバーロードも名前空間もないので、C言語ライブラリではエクスポートされるシンボルの一意性を保証するために明示的なプレフィックスを付けるのが一般的である。GObjectベースのライブラリはオブジェクト指向ではあるがC言語で書かれているので、コンパイラが何であっても明示的なシンボル名を使う。

おそらく最も意義のあるGObjectの特徴はSignalである。これは、GObjectがGUIツールキット向けに開発されたために必要になった機能である。他のオブジェクト指向言語にも同様の機能はあるが、GObjectではオブジェクトシステムそのものに組み込まれている。このため、GObjectアプリケーションはSignalを多用する傾向があり、GObjectのコンポーネントはC++やJavaよりもカプセル化とコードの再利用という面で優れている。

8. 出典
-----

9. 外部リンク
--------

[1]
[2]
[3]
[4]