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してみた。

こんなもんか。ふむ。