K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[2029] Re:『Java 謎』3.3 寄り道 - Cで継承を実現してみる
投稿者:(ぱ)こと管理人
2017/12/02 00:40:59

>『Java 謎+落とし穴 徹底解明』 3.3 寄り道 - Cで継承を実現してみる >p.177 - List 3.11 - 3.22 について、 たとえば ExtendedPolyline を追加す >るとしたらどうするのか、つたないながら考えてみました。 趣旨としては、複数階層の継承を実現するにはどうすればよいか、ということで よいでしょうか。 >まず、 Shape.c の MethodTableIndex を Shape.h に移動するのはまずいでしょ >うか。しかし、そうしたとして、あとは以下のファイルを改変または追加しました。 >(なお、 Shape は abstract 相当と理解しております。) Shape.hは利用者側(たとえばmain.c)でも#includeするヘッダファイルですが、 MethodTableIndexは利用者に晒す必要はないので、Shape.hに移動するのは よろしくないかと思います。 >/* このへんがとりわけリアリティにかけるのかも…… */ >void initExtendedPolyline(void) { > ClassDescriptor *cd = getPolylineClassDescriptor(); > void (**mt)() = cd->methodTable; > memcpy(methodTable, mt, sizeof(mt)); > methodTable[(int)DRAW_INDEX] = drawExtendedPolylineImpl; >} まず、このmemcpy()は、ExtendedPolyline独自のmethodTableについて、 いったんそのスーパークラスであるPolylineのmethodTableをコピーしておいて、 その中で特定のメソッドだけをオーバーライドするためのものかと思います。 ただ、上記mtの型は、宣言にあるとおり「voidを返す関数へのポインタへのポインタ」 なので、sizeof(mt)ではポインタのサイズしか取れません。 この形で複数階層の継承を実現するには、スーパークラスのメソッドテーブルに 何個のメソッドがあるのかを、できればコンパイル時に知りたい(メソッドテーブルを malloc()で確保するなら別ですが、静的に決まる数の要素をmalloc()で確保するのは 避けたい)わけで、そうなると、各クラスのヘッダファイルを、 アプリケーションに公開するもの、自分自身のサブクラスのみに公開するものに 分ける必要があるかと思います。実際、Xt Intrinsicsや http://kmaebashi.com/programmer/c_yota/inherit.html こちらのサンプルでは、Polyline.hとPolylineP.hを分けています。 また、クラスディスクリプタを初期化する関数を用意するのは良いとして、 それを、利用者側(main.c)から呼び出させるのは美しくないですよね。 この場合、Objectクラスのクラスディスクリプタに、 ・クラスディスクリプタが初期化されているかどうかのフラグ ・スーパークラスのクラスディスクリプタへのポインタ ・クラスディスクリプタを初期化する関数へのポインタ を持たせてやって、 PolylineやRectangleのような各クラスで、それぞれのクラスディスクリプタへの ポインタをグローバル変数として公開し、 /* PolylineClassがPolylineのクラスディスクリプタへのポインタ */ Polyline *polyline = new_instance(PolylineClass); このnew_instanceの中で、 渡されたポインタの指す先のクラスディスクリプタが初期化されていなければ、 そのクラスディスクリプタを初期化する関数を呼び出す。ただしそれを、 親クラスへ遡りながら親クラスから順に行う。 という処理を行えば、クラスディスクリプタの初期化処理を フレームワーク内で行えるのではないでしょうか。 また、new_instanceの中では、各クラスの「コンストラクタ」を 呼ぶこともできます。 こちらのサンプルでは、 http://kmaebashi.com/programmer/c_yota/inherit.html クラスディスクリプタを初期化する関数へのポインタclass_initializerを Coreのクラスディスクリプタに持たせているにもかかわらず、 それを呼び出す処理がどこにも書いてないですね…… orz
[この投稿を含むスレッドを表示] [この投稿を削除]