C++ メンバー関数ポインタの話
C++メンバー関数ポインタで仮想関数だとどうなるんだろ?と思って調べてみた。
このとき、fpはC::func関数のメモリアドレスと同じ値かと思っていたのですが、ぜんぜん違った。
実態はvtbl内のaddress offsetのような数値(実際はオフセット+1の数値)です。
vtblのオフセットなので、class Cを継承したDというクラスでfuncをoverrideするとメンバー関数ポインタfpを使った呼び出しはきちんと、overrideされたD::funcを呼び出します(コンストラクタの中ではvtblの関係でだめですけど)。
このソースコードで、C::func()が呼び出されないという不思議。
funcがvirtualではない場合、普通に関数アドレスが戻ってるので、呼び出し時にどちらか判断する必要があります。
ここに、なんらかの仕組みが必要なのでasmソース出して調べてみた。
この通り(?)、通常の関数アドレスやvtblオフセットが32bit alignなのを利用して、関数アドレスの場合はそのまま、vtblオフセットの場合は+1しておくことで1ビット目で判断してました。
メンバー関数ポインタの呼び出しがオブジェクト内部からでも(this->*fp)();とする必要がある理由は、この処理にあるんすね。
それにしても仮想関数テーブルのlookupコードが長いので-O2してみた。
こんなもんか。ふむ。