単一継承クラスの虚関数テーブル
42618 ワード
ダミー関数テーブルの印刷
実行結果:
質問:ClassB.vtbl[2]=0とClassC.vtbl[2]=0は、虚関数テーブルの終端が0であるべきであることを示しているが、なぜClassAの虚関数テーブルには現れないのだろうか.次に、関数ポインタで虚関数テーブルの値を指し、メンバー関数を呼び出して虚関数テーブルに何が入っているかを見ます.
実行結果:
#include
#include
using namespace std;
class ClassA
{
public:
ClassA(){m_data1 = 1; m_data2 = 2;}
int m_data1;
int m_data2;
void func1(){cout << "ClassA::func1" << endl;}
void func2(){cout << "ClassA::func2" << endl;}
virtual void vfunc1(){cout << "ClassA::vfunc1" << endl;}
virtual void vfunc2(){cout << "ClassA::vfunc2" << endl;}
};
class ClassB : public ClassA
{
public:
ClassB(){m_data3 = 3;}
int m_data3;
void func2(){cout << "ClassB::func2" << endl;}
virtual void vfunc1(){cout << "ClassB::vfunc1" << endl;}
};
class ClassC : public ClassB
{
public:
ClassC(){m_data4= 5; m_data1 = 4;}
int m_data1;
int m_data4;
void func2(){cout << "ClassC::func2" << endl;}
virtual void vfunc1(){cout << "ClassC::vfunc1" << endl;}
};
int main()
{
ClassA a;
ClassB b;
ClassC c;
long *v; // v is the address of vptr
long *vtbl0; // vtbl0 is the address of vtbl[0]
Fun pFun = nullptr;
v = (long*)&a;
vtbl0 = (long*)(*v);
cout << "ClassA.vptr=" << v << " ClassA.vtbl[0]=" << vtbl0 << endl;
for (int i = 0; i < 6; ++i)
printf("ClassA vtbl[%d]=%#x // %#x
", i, *(vtbl0 + i), (vtbl0 + i));
cout << endl;
v = (long*)&b;
vtbl0 = (long*)(*v);
cout << "ClassB.vptr=" << v << " ClassB.vtbl[0]=" << vtbl0 << endl;
for (int i = 0; i< 6; ++i)
printf("ClassB vtbl[%d]=%#x // %#x
", i, *(vtbl0 + i), (vtbl0+i));
cout << endl;
v = (long*)&c;
vtbl0 = (long*)(*v);
cout << "ClassC.vptr=" << v << " ClassC.vtbl[0]=" << vtbl0 << endl;
for (int i = 0; i < 6; ++i)
printf("ClassC vtbl[%d]=%#x // %#x
", i, *(vtbl0 + i), (vtbl0+i));
cout << endl;
return 0;
}
実行結果:
ClassA.vptr=0xfff656e8 ClassA.vtbl[0]=0x5664ae88
ClassA vtbl[0]=0x566491d0 // 0x5664ae88
ClassA vtbl[1]=0x56649216 // 0x5664ae8c
ClassA vtbl[2]=0xf7f6e0ec // 0x5664ae90 :
ClassA vtbl[3]=0x566496a8 // 0x5664ae94
ClassA vtbl[4]=0x5664ae9c // 0x5664ae98
ClassA vtbl[5]=0xf7f6e0ec // 0x5664ae9c
ClassB.vptr=0xfff656f4 ClassB.vtbl[0]=0x5664ae78
ClassB vtbl[0]=0x566492de // 0x5664ae78
ClassB vtbl[1]=0x56649216 // 0x5664ae7c
ClassB vtbl[2]=0 // 0x5664ae80
ClassB vtbl[3]=0x5664aea8 // 0x5664ae84
ClassB vtbl[4]=0x566491d0 // 0x5664ae88
ClassB vtbl[5]=0x56649216 // 0x5664ae8c
ClassC.vptr=0xfff65704 ClassC.vtbl[0]=0x5664ae68
ClassC vtbl[0]=0x566493b0 // 0x5664ae68
ClassC vtbl[1]=0x56649216 // 0x5664ae6c
ClassC vtbl[2]=0 // 0x5664ae70
ClassC vtbl[3]=0x5664ae9c // 0x5664ae74
ClassC vtbl[4]=0x566492de // 0x5664ae78
ClassC vtbl[5]=0x56649216 // 0x5664ae7c
質問:ClassB.vtbl[2]=0とClassC.vtbl[2]=0は、虚関数テーブルの終端が0であるべきであることを示しているが、なぜClassAの虚関数テーブルには現れないのだろうか.次に、関数ポインタで虚関数テーブルの値を指し、メンバー関数を呼び出して虚関数テーブルに何が入っているかを見ます.
#include
#include
using namespace std;
class ClassA
{
public:
ClassA(){m_data1 = 1; m_data2 = 2;}
int m_data1;
int m_data2;
void func1(){cout << "ClassA::func1" << endl;}
void func2(){cout << "ClassA::func2" << endl;}
virtual void vfunc1(){cout << "ClassA::vfunc1" << endl;}
virtual void vfunc2(){cout << "ClassA::vfunc2" << endl;}
};
class ClassB : public ClassA
{
public:
ClassB(){m_data3 = 3;}
int m_data3;
void func2(){cout << "ClassB::func2" << endl;}
virtual void vfunc1(){cout << "ClassB::vfunc1" << endl;}
};
class ClassC : public ClassB
{
public:
ClassC(){m_data4= 5; m_data1 = 4;}
int m_data1;
int m_data4;
void func2(){cout << "ClassC::func2" << endl;}
virtual void vfunc1(){cout << "ClassC::vfunc1" << endl;}
};
int main()
{
ClassA a;
ClassB b;
ClassC c;
long *v; // v is the address of vptr
long *vtbl0; // vtbl0 is the address of vtbl[0]
Fun pFun = nullptr;
v = (long*)&a;
vtbl0 = (long*)(*v);
cout << "ClassA.vptr=" << v << " ClassA.vtbl[0]=" << vtbl0 << endl;
for (int i = 0; i < 2; ++i)
{
printf("ClassA vtbl[%d]=%#x %#x
", i, *(vtbl0 + i), (vtbl0 + i));
pFun = (Fun)*(vtbl0+i);
if ( *(vtbl0 + i) == 0) {cout << endl; break;}
pFun();
}
cout << endl;
v = (long*)&b;
vtbl0 = (long*)(*v);
cout << "ClassB.vptr=" << v << " ClassB.vtbl[0]=" << vtbl0 << endl;
for (int i = 0; i< 6; ++i)
{
printf("ClassB vtbl[%d]=%#x %#x
", i, *(vtbl0 + i), (vtbl0+i));
pFun = (Fun)*(vtbl0+i);
if ( *(vtbl0 + i) == 0) {cout << endl; break;}
pFun();
}
cout << endl;
v = (long*)&c;
vtbl0 = (long*)(*v);
cout << "ClassC.vptr=" << v << " ClassC.vtbl[0]=" << vtbl0 << endl;
for (int i = 0; i < 6; ++i)
{
printf("ClassC vtbl[%d]=%#x %#x
", i, *(vtbl0 + i), (vtbl0+i));
pFun = (Fun)*(vtbl0+i);
if ( *(vtbl0 + i) == 0) {cout << endl; break;}
pFun();
}
cout << endl;
return 0;
}
実行結果:
ClassA.vptr=0xff804738 ClassA.vtbl[0]=0x565c0e88
ClassA vtbl[0]=0x565bf2c0 0x565c0e88 ClassA::vfunc1
ClassA vtbl[1]=0x565bf306 0x565c0e8c ClassA::vfunc2
ClassB.vptr=0xff804744 ClassB.vtbl[0]=0x565c0e78
ClassB vtbl[0]=0x565bf3ce 0x565c0e78 ClassB::vfunc1 // override ,
ClassB vtbl[1]=0x565bf306 0x565c0e7c ClassA::vfunc2
ClassB vtbl[2]=0 0x565c0e80
ClassC.vptr=0xff804754 ClassC.vtbl[0]=0x565c0e68
ClassC vtbl[0]=0x565bf4a0 0x565c0e68 ClassC::vfunc1 // override ,
ClassC vtbl[1]=0x565bf306 0x565c0e6c ClassA::vfunc2
ClassC vtbl[2]=0 0x565c0e70