aravis解析 その5 [aravis]
aravisを読めるようにするためにGObjectをさらっとみている。前回はGObjectの大まかな構造を確認した。インスタンス構造体とクラス構造体があって、Objective-Cのisaポインタみたいなのがインスタンス構造体の先頭にあるということを見た。今日はクラス構造体のほうと、マクロ展開するための名前の規則なんかについて....
これは何かと言うと、仮想メソッド、つまりサブクラスで上書き(Override)されるべき関数である。
C言語では同じ名前の関数をふたつ作ることはできないので、サブクラスで上書きするメカニズムがない。そこでGObjectではクラス構造体の中に仮想メソッドの関数ポインタを置いておき、サブクラスがその実体の関数を実装してポインタを設定する。
C言語では自動的にはできないのでサブクラスの初期化関数の中で親クラスを呼んで設定させる(GObjectでは親クラスのクラス構造体へのポインタをもらってサブクラスが自分で設定する)作業を明示的に行う必要がある。こうやって完全に関数ポインタを書き換えることでメソッドのoverrideを実現しているようである。いつ仮想メソッドが呼ばれるかはわからないので、当然overrideはstaticな動作になるだろう。
オブジェクト指向の機能を持った言語で書けばほとんど何もすることはないのに、Cで書こうとすると非常にめんどくさい。仕方ない。
また、クラスの名前、つまりtypedefされた構造体の名前はキャメルケースにする。つまり
このふたつの規則は非常に重要で、G_DEFINE_TYPE()というマクロがこれに従って文字列からクラスシステムを登録する関数などを作り出すようである。
まず、オブジェクトの型に対応する GType を返すマクロのPREFIX_TYPE_OBJECT。マクロ名のイタリックの部分はそれぞれのprefix(libraryの名前など)とobjectで置き換える。例えば、aravisのカメラオブジェクトの場合
オブジェクトの型をキャストするマクロ、PREFIX_OBJECT(obj)。 GTypeかどうかをチェックしてポインタをキャストする。
例えばArvCameraでは実装ファイルの最後のほうに
4.2.3 クラス構造体の関数ポインタは何か?
インスタンス構造体のGTypeInstanceのあとのメンバはインスタンス変数だということはすぐわかる。クラス構造体の方にもGTypeClassのあとにメンバがあるけど、関数ポインタだけが並んでいる。これは何かと言うと、仮想メソッド、つまりサブクラスで上書き(Override)されるべき関数である。
C言語では同じ名前の関数をふたつ作ることはできないので、サブクラスで上書きするメカニズムがない。そこでGObjectではクラス構造体の中に仮想メソッドの関数ポインタを置いておき、サブクラスがその実体の関数を実装してポインタを設定する。
C言語では自動的にはできないのでサブクラスの初期化関数の中で親クラスを呼んで設定させる(GObjectでは親クラスのクラス構造体へのポインタをもらってサブクラスが自分で設定する)作業を明示的に行う必要がある。こうやって完全に関数ポインタを書き換えることでメソッドのoverrideを実現しているようである。いつ仮想メソッドが呼ばれるかはわからないので、当然overrideはstaticな動作になるだろう。
オブジェクト指向の機能を持った言語で書けばほとんど何もすることはないのに、Cで書こうとすると非常にめんどくさい。仕方ない。
4.2.4 名前の付け方
関数名は、ライブラリ名_型名_関数名の形にする。aravisのカメラオブジェクトの場合ArvCamera * arv_camera_new (const char *name); ArvDevice * arv_camera_get_device (ArvCamera *camera);などとなっている。
また、クラスの名前、つまりtypedefされた構造体の名前はキャメルケースにする。つまり
typedef struct _ArvCameraPrivate ArvCameraPrivate; typedef struct _ArvCameraClass ArvCameraClass; struct _ArvCamera { GObject object; ArvCameraPrivate *priv; }; struct _ArvCameraClass { GObjectClass parent_class; };のようにする。
このふたつの規則は非常に重要で、G_DEFINE_TYPE()というマクロがこれに従って文字列からクラスシステムを登録する関数などを作り出すようである。
4.2.5 定義すべきマクロ
クラス定義のヘッダの中に定義しておくマクロというのが決められている。GObjectのサブクラスなら6つのマクロを定義する。まず、オブジェクトの型に対応する GType を返すマクロのPREFIX_TYPE_OBJECT。マクロ名のイタリックの部分はそれぞれのprefix(libraryの名前など)とobjectで置き換える。例えば、aravisのカメラオブジェクトの場合
#define ARV_TYPE_CAMERA (arv_camera_get_type ())となっている。
オブジェクトの型をキャストするマクロ、PREFIX_OBJECT(obj)。 GTypeかどうかをチェックしてポインタをキャストする。
#define ARV_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),\ ARV_TYPE_CAMERA, ArvCamera))クラス構造体にキャストするPREFIX_OBJECT_CLASS (klass)。
#define ARV_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ ARV_TYPE_CAMERA, ArvCameraClass))引数がそのクラスのインスタンスかどうか(論理値gboolean)を返すPREFIX_IS_OBJECT (obj)。
#define ARV_IS_CAMERA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ ARV_TYPE_CAMERA))引数がそのクラスのクラス構造体かどうかを返すPREFIX_IS_OBJECT_CLASS(klass)。
#define ARV_IS_CAMERA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ ARV_TYPE_CAMERA))引数のオブジェクトのクラス構造体へのポインタを返すPREFIX_OBJECT_GET_CLASS (obj)。
#define ARV_CAMERA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), \ ARV_TYPE_CAMERA, ArvCameraClass))これらのマクロの置き換え後の文字列もマクロで生成してもいいぐらいの決まり切ったもののようである。
4.2.6 PREFIX_TYPE_OBJECTマクロの展開
ひとつめのマクロは決まった関数prefix_object_get_type()に展開される。この関数はGTypeの値を返すけど、その値はGObjectシステムが勝手に割り振るので自分で書くことはできない。この関数は別のマクロG_DEFINE_TYPE (PrefixObject, prefix_object, G_TYPE_OBJECT)を実装ファイルの中に書いておくと自動的に作られる。1つ目の引数はキャメルケースの名前、2つ目はアンダスコア「_」を使った名前、最後の引数はG_TYPE_OBJECTを指定する。ただし、当然のことながら文字列として展開するので、名前のつけ方が上の「名前のつけ方」で指定した通りでないといけない。
例えばArvCameraでは実装ファイルの最後のほうに
G_DEFINE_TYPE (ArvCamera, arv_camera, G_TYPE_OBJECT)と書いてある。
2019-06-30 21:34
nice!(0)
コメント(0)
コメント 0