今天刚学关于c++多态,学了含有虚函数的类的内存情况。在多基类的派生类中,其中每个基类都含有虚函数,在这种情况下派生类的内存布局是怎么样的?
对于多重继承,有多少基类含有与派生类同名函数虚函数,派生类中就会存在多少个虚函数表和虚函数表指针,编译器会把第一个基类的虚函数表指针存放在派生类的起始地址,把第二个基类的虚函数表指针紧挨着第一个虚函数表指针存放,一次类推,直到存放完所有基类的虚函数表指针。
下面通过代码说明:
#include<iostream>
using namespace std;
typedef void (*Fun)(); //定义一个函数指针类型
class base
{
public:
virtual void fun()
{
cout<<"base fun"<<endl;
}
virtual char* fun2()
{
cout<<"base fun2"<<endl;
return NULL;
}
virtual ~base()
{
cout<<"base disconstructor"<<endl;
}
};
class base2
{
public:
virtual void fun()
{
cout<<"funbase2"<<endl;
}
virtual void funbase22()
{
cout<<"funbase22"<<endl;
}
};
class child :public base,public base2
{
public:
virtual void fun()
{
cout<<"fun child"<<endl;
}
};
int main(int argc, char const *argv[])
{
child b1;
int *p=NULL;
p=(int*)&b1;//将b1对象地址转换为int类型指针
//p是指向b1对象起始地址的,这个地址存放的是虚函数表地址
//(int*)把p转换成int类型指针
//((int *)p+0)是指向第0个基类的vfptr(虚函数表指针)存放地址
//同理((int *)p+1)是指向第1个基类的vfptr(虚函数表指针)存放地址
//*((int *)p+0)把地址中的值取出来,是个地址,但体现为整数。
//(int*)*((int *)p+0)把取出来的数值转换为一个地址(指针),此时的地址就是第0个虚函数表存放的地址
//同理(int*)*((int *)p+1)把取出来的数值转换为一个地址(指针)此时的地址就是第1个虚函数表存放的地址
//((int*)*((int *)p+0)+0)表示第0个虚函数表中第0个虚函数地址
//同理((int*)*((int *)p+0)+1)表示第0个虚函数表中第1个虚函数地址
//同理((int*)*((int *)p+1)+1)表示第1个虚函数表中第1个虚函数地址
//*((int*)*((int *)p+0)+0)就是把第0个虚函数表中第0个虚函数地址中的值取出来,这个数值是虚函数的地址
//(Fun)*((int*)*((int *)p+0)+0)就是把取出来的虚函数地址需要转换的指针转换成 void (*Fun)()类型的函数指针,赋值给f指针
Fun f=(Fun)*((int*)*((int*)p+0)+0);//指向第0个虚函数
(*f)();//通过函数指针调用虚函数
f=(Fun)*((int*)*((int*)p+0)+1);//指向第1个虚函数
(*f)(); //通过函数指针调用虚函数
f=(Fun)*((int*)*((int*)p+0)+2);//指向第2个虚函数
(*f)(); //通过函数指针调用虚函数
//以上是输出第一个基类(也就是第0个基类的虚函数表中的虚函数)
f=(Fun)*((int*)*((int*)p+1)+0);//指向第0个虚函数
(*f)();//通过函数指针调用虚函数
f=(Fun)*((int*)*((int*)p+1)+1);//指向第1个虚函数
(*f)(); //通过函数指针调用虚函数
//以上是输出第二个基类(也就是第1个基类的虚函数表中的虚函数)
return 0;
}
输出结果是:
fun child
base fun2
base disconstructor
fun child
funbase22
此篇文章是本人参考书上和老师上课讲的知识总结出来的,如有错的地方,欢迎指出