最初:仮想関数のメカニズムが未定義であることをどこかで読みました。つまり、すべてのコンパイラが異なる方法で実装できることを意味します。しかし、仮想機能メカニズムについて私が見つけたすべてのテキストは、VTBL と VPTR について語っています。
別の仮想機能メカニズムの実装はありますか? いくつか例を挙げていただけますか?
2 番目: 異なる言語での VTBL 実装の違いは何ですか?
最初:仮想関数のメカニズムが未定義であることをどこかで読みました。つまり、すべてのコンパイラが異なる方法で実装できることを意味します。しかし、仮想機能メカニズムについて私が見つけたすべてのテキストは、VTBL と VPTR について語っています。
別の仮想機能メカニズムの実装はありますか? いくつか例を挙げていただけますか?
2 番目: 異なる言語での VTBL 実装の違いは何ですか?
人気のある代替手段の 1 つは、インライン キャッシングです。これは、Smalltalk システムに由来すると思います。
もう 1 つの方法は、型ごとにポリモーフィック メソッド テーブル (VMT) を用意する代わりに、ポリモーフィック メソッドごとに型テーブルを用意することです。プログラム全体の分析が必要ですが、効率的な多重継承が可能になります。一部の Eiffel コンパイラは、このような方法を使用します (詳細については、「多重継承を効率的に実装するにはどうすればよいですか?」を参照してください)。
最後の 1 つは、switch ステートメント ベースのアプローチ (Eiffel での検査 ~ C での switch) という別の方法についても言及しています。SmartEiffel はその変形を使用し、クラス ID に基づいてバイナリ検索を行います。また、プログラム全体の分析も必要ですが、命令キャッシュの動作が改善されているため、現在のシステムでは VMT よりも効率的な場合があります。(詳細は、「仮想関数テーブルを使用しない効率的な動的ディスパッチ」を参照してください)。
例を示します。
class B
{
private:
int m_i;
public:
void foo() { puts("B::foo"); }
virtual void bar() { puts("B::bar"); }
};
class D : public B
{
private:
int m_j;
public:
virtual void bar() { puts("D::bar"); }
virtual void asdf() { puts("D::asdf"); }
};
int main()
{
D d;
B *pb = &d;
pb->bar();
}
ほとんどのコンパイラは、そのコードを次のように実装します。
struct B;
struct __vtbl_B_t
{
void (*bar)(B * const this);
};
struct B
{
const __vtbl_B_t *__vptr;
int m_i;
};
void B__foo(B * const this) { puts("B::foo"); }
void B__bar(B * const this) { puts("B::bar"); }
const __vtbl_B_t __vtbl_B = { B__bar };
void B__ctor(B * const this)
{
this->__vptr = &__vtbl_B;
}
struct D;
struct __vtbl_D_t
{
__vtbl_B_t __base;
void (*asdf)(D * const this);
};
struct D
{
B __base;
int m_j;
};
void D__bar(D * const this) { puts("D::bar"); }
void D__asdf(D * const this) { puts("D::asdf"); }
__vtbl_D_t __vtbl_D = { { (void (*)(B * const))D__bar }, D__asdf };
void D__ctor(D * const this)
{
B__ctor((B * const)this);
this->__base.__vptr = (const __vtbl_B_t *)&__vtbl_D;
}
int main()
{
D d;
D__ctor(&d);
B *pb = (B *)&d;
(*pb->__vptr->bar)(pb);
}
出力:
D::bar
言語が C++ でなくても、コンパイラの動作は似ています。
これはあなたを助けるかもしれません:
異なるコンパイラ ベンダーは異なる方法を選択する可能性があります... しかし、最終的な実装は標準に準拠する必要があります。これは何ですか...
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf (セクション 10.3)