犬も猫も空想も扱っておりません。(旧・エト記)この広告は、90日以上更新していないブログに表示しています。C言語によるオブジェクト記述法「C~(シー・チルダ)」(原理編)C++id:xoinu:20090507,id:xoinu:20090509,id:xoinu:20090511,に続いて,いよいよオブジェクト指向の記述を実践してみようと思います。オブジェクト指向とは何かについては,Wikipediaを引いておきます。(多態性、多相性)カプセル化クラスの継承が挙げられていますが,このうち,カプセル化はC言語でも普通にサポートされ,実践されている機能なので,C~では,多態と継承を実現することに焦点を当てます。言い換えると,C~の目的はC++の記述能力をシンプルなCで実現することです。多くの人々が,C++をあたかもCの後継言語のように捉えられている背景には,言語そのものの機能ももさることながら,何より実行効率を意識した「実装」が優れているという点が大きいと思います。その思いから,C~では,通常はプログラマから隠蔽されているC++の仮想関数テーブルを,メソッドのディスパッチの一実装として採用しました。ここからは,私の思考経路に沿って,C++のコードと,それに対してCでどう記述するか,というスタンスでC~の説明を試みることにします。ありますが,C~の基本方針として以下の3つを挙げておきます。最後の1つは,仮想関数テーブルを採用する(C++からパクる)ことの正当化です。クラスの定義まずは単純に,メンバ変数が1つ,コンストラクタ,仮想デストラクタ,仮想関数がそれぞれ1つあるクラスを考えてみましょう。x;};C~では,これを2つの構造体で表します。1つは仮想関数テーブル,1つはデータ構造の定義です。仮想関数テーブルから。self);};C++のAtomに仮想関数が2つあるのと同様,C~のatomにも,関数ポインタが2つあります。定義であることを示唆しています。続いてデータ構造は以下のように表します。この構造体が「オブジェクト」としてインスタンス化されるわけですが,みそは,オブジェクトの最初のメンバは仮想関数へのポインタだということです。atomをインスタンス化*/a.self->su.vtbl->typename();となります。メンバ関数の中でメンバ変数にアクセスする場合には,仮想関数テーブルを介して呼び出された関数の第1引数にa自身を入れる必要があります。次に継承と多態をいっぺんに実現します。上で定義した2つの構造体を原理的に同じ方法で拡張するので,分かり易いと思います。foo_;};Atomが拡張され,仮想関数とメンバがそれぞれ1つずつ追加されました。これに相当する構造体を表す前に,ポインタを定義します。cnst;};と書きます。アクセスするわけです。次にやるべきことは「blobのポインタをatomだと思って利用」できるようにオブジェクトと,仮想関数のメモリイメージを揃えるだけです。これに相当するものはやはり2つの構造体で表現します。self);};ここで,blob_vtbl(仮想関数テーブル)の最初のメンバがatom_vtblであることに注目。atom_vtbl)バイトはatom_vtblと同じになっています。blob_vtblのatomを上書くことで,多態を実現しようという魂胆です。上書く前のオリジナルのメンバ関数にアクセスする時にはsuperを使います。b.atom;a.self->su.vtbl->typename();と書けるわけです。方が,遥かに安全なことには異論は無いでしょう。:a.self->su.vtbl->atom.typename();とかなって,ややこしいことになります。クラス階層が深くなるとなかなか興味深いことになりそうですが,書けるだけましだと言い聞かせましょう。使って,オブジェクト指向の肝である多態と継承をさらりと実現しました。(多態性、多相性)カプセル化クラスの継承が,Cでも実現できるようになりました。マクロも一切使用せず,言語の性質を生かした記述法であると思います。今回はオブジェクト指向の実現のためのエッセンスに留めて置きましたが,オブジェクトの生成,消滅,アクセス制御,デザインパターン,例外処理を統合する規約の整理など,記法としてのC~がカバーする領域はもう少し広くなる予定です。正確に言うと、insertが同種のset/mapに比べて圧倒的に遅い。