虚基表是通过一块连续的内存来存储虚函数的地址。这张表解决了继承、虚函数(重写)的问题。
在有虚函数的对象实例中都存在一张虚表,虚函数表就像是一张地图,指明了实际应该调用的虚函数
一、探索单继承对象模型
1、没有覆盖
#include<iostream>
using namespace std;
class Base
{
public:
virtual void fun1()
{cout << "Base::fun1" << endl;}
virtual void fun2()
{cout << "Base::fun2" << endl;}
private:
int _a = 1;
};
class Derive : public Base
{
public:
virtual void fun3()
{cout << "Derive::fun3" << endl;}
virtual void fun4()
{cout << "Derive::fun4" << endl;}
private:
int _b = 2;
};
typedef void(*FUNC)();
void PrintVTable(int * VTable)
{
cout << "虚表地址:" << VTable << endl;
for (int i = 0; VTable[i] != 0; i++)
{
printf("第%d个虚函数地址:0x%x,->", i, VTable[i]);
FUNC f = (FUNC)VTable[i];
f();
}
cout << endl;
}
void test()
{
Base b1;
Derive d1;
int* Vtable1 = (int*)(*(int*)&b1);
int* Vtable2 = (int*)(*(int*)&d1);
PrintVTable(Vtable1);
PrintVTable(Vtable2);
}
int main()
{
test();
return 0;
}
说明:
(1)虚函数按照其声明顺序存在于虚表中
(2)在派生类中,前面基类的虚函数,后面是派生类的虚函数
2、有覆盖
#include<iostream>
using namespace std;
class Base
{
public:
virtual void fun1()
{cout << "Base::fun1" << endl;}
virtual void fun2()
{cout << "Base::fun2" << endl;}
private:
int _a = 1;
};
class Derive : public Base
{
public:
virtual void fun1()
{cout << "Derive::fun1" << endl;}
virtual void fun3()
{cout << "Derive::fun3" << endl;}
virtual void fun4()
{cout << "Derive::fun4" << endl;}
private:
int _b = 2;
};
typedef void(*FUNC)();
void PrintVTable(int * VTable)
{
cout << "虚表地址:" << VTable << endl;
for (int i = 0; VTable[i] != 0; i++)
{
printf("第%d个虚函数地址:0x%x,->", i, VTable[i]);
FUNC f = (FUNC)VTable[i];
f();
}
cout << endl;
}
void test()
{
Base b1;
Derive d1;
int* Vtable1 = (int*)(*(int*)&b1);
int* Vtable2 = (int*)(*(int*)&d1);
PrintVTable(Vtable1);
PrintVTable(Vtable2);
}
int main()
{
test();
return 0;
}
通过基类的引用或指针调用虚函数时,调用基类还是派生类的虚函数,要根据运行时引用(指针)实际引用(指针)的类型确定调用非虚函数时,则无论基类指向的是何种类型,都调用的是基类的函数。
派生类的虚函数表生成:
(1)先拷贝基类的虚函数表
(2)如果派生类重写了基类的某个虚函数,就同位置的基类虚函数
(3)跟上派生类自己定义的虚函数
Base b1;
Derive d1;
pBase = &b1; 指向基类,获取到的是基类的虚表指针
PBase->Fun();
pBase = &d1;
PBase->fun(); 指向派生类,获取到的是派生类的虚表指针
二、探索多继承的内存分布
1、有覆盖的
#include<iostream>
using namespace std;
class Base1
{
public:
virtual void fun1()
{
cout << "Base1::fun1()" << endl;
}
virtual void fun2()
{
cout << "Base1::fun2()" << endl;
}
private:
int b1 = 1;
};
class Base2
{
public:
virtual void fun1()
{
cout << "Base2::fun1()" << endl;
}
virtual void fun2()
{
cout << "Base2::fun2()" << endl;
}
private:
int b2 = 2;
};
class Derive :public Base1, public Base2
{
public:
virtual void fun1()
{
cout << "Derive::fun1()" << endl;
}
virtual void fun2()
{
cout << "Derive::fun2()" << endl;
}
virtual void fun3()
{
cout << "Derive::fun3()" << endl;
}
private:
int d = 5;
};
typedef void(*FUNC)();
void PrintVTable(int * VTable)
{
cout << "虚表地址:" << VTable << endl;
for (int i = 0; VTable[i] != 0; i++)
{
printf("第%d个虚函数地址:0x%x,->", i, VTable[i]);
FUNC f = (FUNC)VTable[i];
f();
}
cout << endl;
}
void test()
{
Base1 b1;
Base2 b2;
Derive d;
int* Vtable1 = (int*)(*(int*)&b1);
int* Vtable2 = (int*)(*(int*)&b2);
int* Vtable3 = (int*)(*(int*)&d);
PrintVTable(Vtable1);
PrintVTable(Vtable2);
PrintVTable(Vtable3);
}
int main()
{
test();
return 0;
}
2、没有覆盖的
#include<iostream>
using namespace std;
class Base1
{
public:
virtual void fun1()
{
cout << "Base1::fun1()" << endl;
}
virtual void fun2()
{
cout << "Base1::fun2()" << endl;
}
private:
int b1 = 1;
};
class Base2
{
public:
virtual void fun1()
{
cout << "Base2::fun1()" << endl;
}
virtual void fun2()
{
cout << "Base2::fun2()" << endl;
}
private:
int b2 = 2;
};
class Derive :public Base1, public Base2
{
public:
virtual void fun3()
{
cout << "Derive::fun3()" << endl;
}
private:
int d = 5;
};
typedef void(*FUNC)();
void PrintVTable(int * VTable)
{
cout << "虚表地址:" << VTable << endl;
for (int i = 0; VTable[i] != 0; i++)
{
printf("第%d个虚函数地址:0x%x,->", i, VTable[i]);
FUNC f = (FUNC)VTable[i];
f();
}
cout << endl;
}
void test()
{
Base1 b1;
Base2 b2;
Derive d;
int* Vtable1 = (int*)(*(int*)&b1);
int* Vtable2 = (int*)(*(int*)&b2);
int* Vtable3 = (int*)(*(int*)&d);
PrintVTable(Vtable1);
PrintVTable(Vtable2);
PrintVTable(Vtable3);
}
int main()
{
test();
return 0;
}
三、菱形继承
#include<iostream>
using namespace std;
class A
{
public:
virtual void f()
{
cout << "A::f()" << endl;
}
private:
int _a = 1;
};
class B: public A
{
public:
virtual void f()
{
cout << "B::f()" << endl;
}
private:
int _b = 2;
};
class C : public A
{
public:
virtual void f()
{
cout << "C::f()" << endl;
}
private:
int _c = 3;
};
class D : public B,public C
{
public:
virtual void f()
{
cout << "D::f()" << endl;
}
private:
int _d = 4;
};
int main()
{
D d;
return 0;
}
