vtableはメモリのどこに保存されますか?
6 に答える
コンパイラによって異なります。
VC ++では、vtableポインターは、オブジェクト割り当ての先頭で、メンバーデータの前に格納されます。(クラスに少なくとも1つの仮想メンバー関数がある場合。)
クラスがvtablesを持つ他のクラスから複数継承する場合は、複数のvtableポインタが存在する可能性もあります。
vtable自体は、アドレス空間のどこかに静的に割り当てられます。
次に、オブジェクトのレイアウトは次のようになります(Cのインスタンスの場合)。
A's VTable ptr
A's member variables.
B's Vtable ptr
B's member variables.
C's member variables.
階層のために
class A {
virtual Ax() {}
int a, b;
};
class B {
virtual Bx() {}
int c, d;
};
class C : public A, public B {
int foo, bar;
};
Vtable?どのvtable?C ++標準では、vtableについては言及されていません。各コンパイラは、仮想関数を好きなように実装できます。これには、vtableを好きな場所に配置することも含まれます。
通常、オブジェクトの先頭にあるvptr(Imperfect C ++、Backyard Hotrodding C ++)ですが、標準では保証されていません。vptrsとvtablesの使用は、標準では保証されていません。
それがどこにあるかを本当に知る必要がある場合は、基本的にvptrのようなものが配置されている場所を設定し、それらの使用方法を設定することによって実装されるCOM、XPCOM、UNOなどのようなものを使用するのが一般的です。
仮想関数を含むすべてのインスタンスには、仮想関数テーブル(vbtl)を指す仮想関数ポインターがあります。インスタンスからvtblを見つけることしかできませんでした。または、objdumpを使用してELFファイルのシンボルを読み取ることができます。おそらく、答えを見つけることができます。次の例があなたを助けてくれることを願っています。
#include <iostream>
#include <stdio.h>
typedef void (*fun_pointer)(void);
using namespace std;
class Test
{
public:
Test()
{
cout<<"Test()."<<endl;
}
virtual void print()
{
cout<<"Test::Virtual void print()."<<endl;
}
virtual void print2()
{
cout<<"Test::virtual void print2()."<<endl;
}
};
class TestDrived:public Test
{
public:
TestDrived()
{
cout<<"TestDrived()."<<endl;
}
virtual void print()
{
cout<<"TestDrived::virtual void print()."<<endl;
}
virtual void print2()
{
cout<<"TestDrived::virtual void print2()."<<endl;
}
void GetVtblAddress()
{
cout<<"vtbl address:"<<(int*)this<<endl;
}
void GetFirstVtblFunctionAddress()
{
cout<<"First vbtl function address:"<<(int*)*(int*)this+0 << endl;
}
void GetSecondVtblFunctionAddress()
{
cout<<"Second vbtl function address:"<<(int*)*(int*)this+1 << endl;
}
void CallFirstVtblFunction()
{
fun = (fun_pointer)* ( (int*) *(int*)this+0 );
cout<<"CallFirstVbtlFunction:"<<endl;
fun();
}
void CallSecondVtblFunction()
{
fun = (fun_pointer)* ( (int*) *(int*)this+1 );
cout<<"CallSecondVbtlFunction:"<<endl;
fun();
}
private:
fun_pointer fun;
};
int main()
{
cout<<"sizeof(int):"<<sizeof(int)<<"sizeof(int*)"<<sizeof(int*)<<endl;
fun_pointer fun = NULL;
TestDrived a;
a.GetVtblAddress();
a.GetFirstVtblFunctionAddress();
a.GetSecondVtblFunctionAddress();
a.CallFirstVtblFunction();
a.CallSecondVtblFunction();
return 0;
}
VptrとVtableはデータセグメントに保存されます。
Vtableは、関数ポインタの配列のようなものです。
VtableとVptrはコンパイル時に作成され、実行時にメモリを取得します。vtableエントリは仮想関数アドレスです。
仮想関数を含むクラスのすべてのオブジェクトには、仮想テーブルを指す追加のポインターがあります。これは仮想ポインターと呼ばれます。
オブジェクトを使用して仮想関数を呼び出すときは常に、最初に対応するVptrが実行時にVtableから関数を読み取り、最後に関数が呼び出されます。