上文在C++對(duì)象模型中,提到了vptl和vptr。寫這篇文章即是在代碼驗(yàn)證這二者。Talk is cheap。
平臺(tái):Win7 x64,編譯:dev Cpp。
非繼承下的vptr和vptl
#include <iostream>
using namespace std;
class Base
{
public:
Base(int i) : baseInt(i) { }
~Base() { cout << "Base::~Base()" << endl; }
virtual void Base_virtual_func1() {
cout << "Base::Base_virtual_func1" << endl;
}
virtual void Base_virtual_func2() {
cout << "Base::Base_virtual_func2" << endl;
}
private:
int baseInt;
};
typedef void (*Fun)();
void test1()
{
Base base(1000);
cout << "對(duì)象起始地址:" << &base << endl;
cout << "虛函數(shù)表的首地址: " << (int*)*(int*)(&base) << endl;
cout << "虛函數(shù)1的地址: " << (int*)*(int*)(&base) << " ";
Fun ptr1 = (Fun)*(int*)*(int*)(&base);
ptr1();
cout << "虛函數(shù)2的地址: " << (int*)*(int*)(&base) + 2<< " ";
Fun ptr2 = (Fun)*((int*)*(int*)(&base) + 2);
ptr2();
cout << "---------------" << endl;
}
int main()
{
test1();
}
輸出結(jié)果:
1.jpg
從結(jié)果可以看出:Vptr 是放在對(duì)象起始地址。關(guān)系如圖:
1.jpg
單繼承下的vptr和vptl
#include <iostream>
using namespace std;
typedef void (*Fun)();
class Base
{
public:
Base(int i) : baseInt(i) { }
~Base() { cout << "Base::~Base()" << endl; }
virtual void virtual_func() {
cout << "Base::virtual_func" << endl;
}
virtual void Base_virtual_func() {
cout << "Base::Base_virtual_func" << endl;
}
private:
int baseInt;
};
class Derive : public Base
{
public:
Derive(int d): Base(1000), DeriveInt(d) { }
~Derive() { cout << "Derive::~Derive()" << endl; }
void virtual_func() override {
cout << "Drive::virtual_func()" << endl;
}
virtual void Drive_virtual_func() {
cout << "Drive::Drive_virtual_func" << endl;
}
private:
int DeriveInt;
};
void test2()
{
Derive derive(2000);
cout << "對(duì)象起始地址:" << &derive << endl;
cout << "虛函數(shù)表首地址:" << (int*)*(int*)(&derive) << endl;
cout << "虛函數(shù)1的地址:" << (int*)*(int*)(&derive) << " ";
Fun ptr1 = (Fun)*(int*)*(int*)(&derive);
ptr1();
cout << "虛函數(shù)2的地址:" << (int*)*(int*)(&derive) + 2 << " ";
Fun ptr2 = (Fun)*((int*)*(int*)(&derive) + 2);
ptr2();
cout << "虛函數(shù)3的地址:" << (int*)*(int*)(&derive) + 4 << " ";
Fun ptr3 = (Fun)*((int*)*(int*)(&derive) + 4);
ptr3();
cout << endl << "----------------------" << endl;
}
int main()
{
test2();
}
輸出結(jié)果:
2.jpg
從結(jié)果來看,virtual function一共有3種可能:
- 繼承base class的virtual function函數(shù)實(shí)例。
- 可以使用覆蓋掉base class的virtual function。
- 它可以加一個(gè)新的virtual fucntion。這時(shí)候virtual table的尺寸會(huì)增加一個(gè)新的slot,新的函數(shù)實(shí)例地址會(huì)放在其中。
如圖所示:
3.jpg
多繼承下的vptr和vptl
子類不覆蓋父類的虛函數(shù)
#include <iostream>
using namespace std;
typedef void(*Fun)();
class Base1{
public:
virtual void f() { cout << "Base1::f" << endl; }
virtual void g() { cout << "Base1::g" << endl; }
};
class Base2{
public:
virtual void f() { cout << "Base2::f" << endl; }
virtual void g() { cout << "Base2::g" << endl; }
};
class Base3{
public:
virtual void f() { cout << "Base3::f" << endl; }
virtual void g() { cout << "Base3::g" << endl; }
};
class Derive : public Base1, public Base2, Base3{
public:
virtual void a() { cout << "Derive::a" << endl; }
virtual void b() { cout << "Derive::b" << endl; }
};
void v_table_test4()
{
Derive d;
Fun func_ptr1 = nullptr;
Fun func_ptr2 = nullptr;
Fun func_ptr4 = nullptr;
Fun func_ptr5 = nullptr;
Fun func_ptr7 = nullptr;
Fun func_ptr8 = nullptr;
Fun func_ptr10 = nullptr;
Fun func_ptr11 = nullptr;
cout << "對(duì)象起始地址: " << (int*)(&d) << endl;
cout << "第1個(gè)vptr地址:" << (int*)(&d) << endl;
cout << "第1個(gè)虛函數(shù)表首地址: " << (int*)*(int*)(&d) << endl;
func_ptr1 = (Fun)*( (int*)*(int*)(&d));
func_ptr2 = (Fun)*( (int*)*(int*)(&d) + 2);
func_ptr4 = (Fun)*( (int*)*(int*)(&d) + 4);
func_ptr5 = (Fun)*( (int*)*(int*)(&d) + 6);
func_ptr1();
func_ptr2();
func_ptr4();
func_ptr5();
cout << "----------------" << endl;
cout << "第2個(gè)vptr地址:" << (int*)(&d) + 2 << endl;
cout << "第2個(gè)(vptr->vptl)虛函數(shù)表首地址: " << (int*)*( (int*)(&d) + 2) << endl;
func_ptr7 = (Fun)*( (int*)*( (int*)(&d) + 2));
func_ptr8 = (Fun)*( ((int*)*( (int*)(&d) + 2)) + 2);
func_ptr7();
func_ptr8();
cout << "----------------" << endl;
cout << "第3個(gè)vptr地址:" << (int*)(&d) + 4 << endl;
cout << "第3個(gè)(vptr->vptl)虛函數(shù)表首地址: " << (int*)*( (int*)(&d) + 4) << endl;
func_ptr10 = (Fun)*( (int*)*( (int*)(&d) + 4));;
func_ptr11 = (Fun)*( ((int*)*( (int*)(&d) + 4)) + 2);
func_ptr10();
func_ptr11();
}
int main()
{
v_table_test4();
}
輸出結(jié)果:
4.jpg
從結(jié)果看來,對(duì)于子類不覆蓋父類的虛函數(shù)的多繼承,子類有多個(gè)vptr和多個(gè)vptl,每一個(gè)vptr指向一個(gè)vptl,子類自己的虛函數(shù)在第一個(gè)vptl里面,
如圖所示:
5.jpg
子類覆蓋自己的虛函數(shù)
這個(gè)類似單繼承下的vptr和vptl的,只是替換相應(yīng)的函數(shù)地址。
多重繼承和虛繼承
比較復(fù)雜,暫時(shí)還不會(huì)。