上次说到了多态,可是多态在编译器里到底是如何实现的呢?
下面我们就来探索一下它深层的实现机制
class Base
{
public:
virtual void func1()
{}
virtual void func2()
{}
private:
int a1;
};
void Test()
{
Base a;
cout << sizeof(a) << endl;//8
}
这里为什么sizeof(a)
是8呢?
因为这里还存了一个指向虚函数表的指针
我们可以从监视窗口来看一下
_vfptr就是虚函数表指针(virtual function ptr)
虚函数表(虚表):用一块连续的内存来存储虚函数的地址。
这张表解决了继承、虚函数(重写)的问题;
有虚函数就有虚表(从父类继承就自动生成了),虚函数表就像一个路标,指明了实际应该调用哪个虚函数
还是用我最喜欢的图示来说明,下图
单继承
class Base
{
public:
virtual void func1()
{
cout << "Base::func1" << endl;
}
virtual void func2()
{
cout << "Base::func2" << endl;
}
private:
int a;
};
class Derive:public Base
{
public:
virtual void func1()
{
cout << "Base::func1" << endl;
}
virtual void func3()
{
cout << "Base::func2" << endl;
}
virtual void func4()
{
cout << "Base::func2" << endl;
}
private:
int b;
};
void Test()
{
Base a1;
Derive b1;
}
我们还是来看一下监视
这里我们可以看出子类Derive实例化出的b1,继承了父类的虚函数表指针,没有重新生成
但是这里看监视窗口是有一些问题的
并没有看到虚表里有func3、func4,这是为什么呢?难道他们没有在虚表里?
在是肯定在,只是在监视不能显示出来,所以这里我们可以自己写个函数将虚表打印出来
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 a1;
Derive b1;
int* VTable1 = (int*)(*(int*)&a1);
int* VTable2 = (int*)(*(int*)&b1);
PrintVTable(VTable1);
PrintVTable(VTable2);
}
可以看出func1在子类中重写了,func2继承来没有变动,func3、func4就在后面依次存放着
多继承
class Base1
{
public:
virtual void func1()
{
cout << "Base1::func1" << endl;
}
virtual void func2()
{
cout <<" Base1::func2" << endl;
}
private:
int a;
};
class Base2
{
public:
virtual void func1()
{
cout <<" Base2::func1" << endl;
}
virtual void func2()
{
cout << "Base2::func2 "<< endl;
}
private:
int b;
};
class Derive :public Base1, public Base2 //多继承,写的顺序,就是继承先后的顺序
{
public:
virtual void func2()
{
cout << "Derive::func2 "<< endl;
}
virtual void func3()
{
cout <<" Derive::func3 "<< endl;
}
private:
int c;
};
typedef void(*FUNC) ();
void PrintfVTable(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();
}
}
void Test()
{
Derive c1;
int* VTable = (int*)(*(int*)&c1);
PrintfVTable(VTable);
//Base2虚表
VTable = (int*)(*((int*)&c1 + sizeof(Base1) / 4));
PrintfVTable(VTable);
}