memo/20091208
created 2009-12-08 modified 2009-12-23
S.B.リップマン先生の「C++ オブジェクトモデル」
の
4.2 仮想メンバ関数
と、ほぼ同じ内容がWebで読めます。
リンク | 備考 |
---|---|
「C++:水面下の仕組み」 Jan Gray | Microsoft の技術文書 |
単一継承 ...
クラス継承階層の上から下まで全部が単一継承で、かつ仮想継承なしだと、
基底クラスのポインタと派生クラスのポインタは同じ値、として、ただしいマシン語を出力するコンパイラを実装できる(かつそれがデファクトスタンダードになってる)。
+--------------+ <- 基底のthis == 派生Aのthis |基底のメンバ | +--------------+ |派生Aのメンバ | +--------------+
+--------------+ <- 基底のthis == 派生Bのthis |基底のメンバ | +--------------+ |派生Bのメンバ | +--------------+
アップキャストしてもダウンキャストしても、thisの値は同じ。
多重継承 ...
多重継承では、継承クラスの記述で2番目以降に書いたクラスについては、
this の値が派生クラスや基底クラスと同じでは、
正しいマシン語を出力するコンパイラは実装できないので、
微妙にthisの値を修正するコードを割り込ませるようになってる。
基底1,基底2は継承のルートで、派生は基底1と基底2を多重継承している場合:
+--------------+ <- (1) 基底1のthis == 派生Aのthis |基底1のメンバ | +--------------+ <- (2) 基底2のthis |基底2のメンバ | +--------------+ |派生Aのメンバ | +--------------+
+--------------+ <- (1) 基底1のthis == 派生Bのthis |基底1のメンバ | +--------------+ <- (2) 基底2のthis |基底2のメンバ | +--------------+ |派生Bのメンバ | +--------------+
基底1のメンバ関数の暗黙の第一パラメータthisは、(1)。
基底2のメンバ関数の暗黙の第一パラメータthisは、(2)。
派生Aのメンバ関数の暗黙の第一パラメータthisは、(1)。
補足:
基底1や基底2のメンバ関数は、派生Aについて一切知らないから、 thisとして自分の先頭を受け取る。 派生Aのメンバ関数は、派生Aが基底1と基底2を継承しているクラスで あることを知っているから、thisとして基底1の先頭を受け取る。
派生Aのポインタを基底2のポインタに代入する(アップキャスト)とき、
コンパイラは値を調整するコードを挿入する(同じ値ではない)。
基底2のポインタから派生Aのポインタに代入する(ダウンキャスト)ときは
…C++ の使い方としては、基底2に仮想関数を1つ以上定義した上で、
dynamic_cast するのが正解なんだろうね。
もちろん、
単一継承で 基底1 ~ 基底2 ~ 派生A なら
+--------------+ <- 基底1のthis == 基底2のthis == 派生Aのthis |基底1のメンバ | +--------------+ |基底2のメンバ | +--------------+ |派生Aのメンバ | +--------------+
となる。
cfront がダウンロードできるらしい
なんと!cfront がダウンロードできるらしい。
リンク | 備考 |
---|---|
Cfront releases |
リップマン先生によると
余談ではあるが、EH(例外処理)が cfront を文字通り絶滅させてしまったということも言うに値することだろう。 コード生成(とリンカ)のサポートなしには、頑強な EH メカニズムは提供できない。 (中略) USL は最終的に cfront の Release 4.0 とそれ以降の開発をあきらめた。
(C++オブジェクトモデル 7.2 例外処理)
だそうです。