含有虚函数多重继承派生类内存布局

来源:互联网 发布:javascript 严格模式 编辑:程序博客网 时间:2024/05/17 08:39

今天刚学关于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

 

此篇文章是本人参考书上和老师上课讲的知识总结出来的,如有错的地方,欢迎指出微笑

 

0 0
原创粉丝点击