注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

C++ 对象的内存布局(多重虚拟继承)  

2015-05-21 18:31:32|  分类: C和C++语言 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
原文:http://blog.csdn.net/haoel/article/details/3081328
下面,让我们来看看多重继承中C++对象的内存布局的情况,假设有下面这样一个类的继承关系。
注意:子类只overwrite了父类的f()函数,而还有一个是自己的函数(我们这样做的目的是为了用g1()作为一个标记来标明子类的虚函数表)。而且每个类中都有一个自己的成员变量:
 C++ 对象的内存布局(单一的一般继承) - hubingforever - 民主与科学
 
 
我们的类继承的源代码如下所示:父类的成员初始为10,20,30,子类的为100 

class Base1 {
public:
    int ibase1;
    Base1():ibase1(10) {}
    virtual void f() { cout << "Base1::f()" << endl; }
    virtual void g() { cout << "Base1::g()" << endl; }
    virtual void h() { cout << "Base1::h()" << endl; }
 
};
 
class Base2 {
public:
    int ibase2;
    Base2():ibase2(20) {}
    virtual void f() { cout << "Base2::f()" << endl; }
    virtual void g() { cout << "Base2::g()" << endl; }
    virtual void h() { cout << "Base2::h()" << endl; }
};
 
class Base3 {
public:
    int ibase3;
    Base3():ibase3(30) {}
    virtual void f() { cout << "Base3::f()" << endl; }
    virtual void g() { cout << "Base3::g()" << endl; }
    virtual void h() { cout << "Base3::h()" << endl; }
};
 
 
class Derive : public Base1, public Base2, public Base3 {
public:
    int iderive;
    Derive():iderive(100) {}
    virtual void f() { cout << "Derive::f()" << endl; }
    virtual void g1() { cout << "Derive::g1()" << endl; }
};
 

我们通过下面的程序来查看子类实例的内存布局:下面程序中,注意我使用了一个s变量,其中用到了sizof(Base)来找下一个类的偏移量。(因为我声明的是int成员,所以是4个字节,所以没有对齐问题。关于内存的对齐问题,大家可以自行试验,我在这里就不多说了) 

             typedef void(*Fun)(void);

               Derive d;
 
                int** pVtab = (int**)&d;
 
                cout << "[0] Base1::_vptr->" << endl;
                pFun = (Fun)pVtab[0][0];
                cout << "     [0] ";
                pFun();
 
                pFun = (Fun)pVtab[0][1];
                cout << "     [1] ";pFun();
 
                pFun = (Fun)pVtab[0][2];
                cout << "     [2] ";pFun();
 
                pFun = (Fun)pVtab[0][3];
                cout << "     [3] "; pFun();
 
                pFun = (Fun)pVtab[0][4];
                cout << "     [4] "; cout<<pFun<<endl;
 
                cout << "[1] Base1.ibase1 = " << (int)pVtab[1] << endl;
 
 
                int s = sizeof(Base1)/4;
 
                cout << "[" << s << "] Base2::_vptr->"<<endl;
                pFun = (Fun)pVtab[s][0];
                cout << "     [0] "; pFun();
 
                Fun = (Fun)pVtab[s][1];
                cout << "     [1] "; pFun();
 
                pFun = (Fun)pVtab[s][2];
                cout << "     [2] "; pFun();
 
                pFun = (Fun)pVtab[s][3];
                out << "     [3] ";
                cout<<pFun<<endl;
 
                cout << "["<< s+1 <<"] Base2.ibase2 = " << (int)pVtab[s+1] << endl;
 
                s = s + sizeof(Base2)/4;

                cout << "[" << s << "] Base3::_vptr->"<<endl;
                pFun = (Fun)pVtab[s][0];
                cout << "     [0] "; pFun();
 
                pFun = (Fun)pVtab[s][1];
                cout << "     [1] "; pFun();
 
                pFun = (Fun)pVtab[s][2];
                cout << "     [2] "; pFun();
 
                pFun = (Fun)pVtab[s][3];
                 cout << "     [3] ";
                cout<<pFun<<endl;
 
                s++;
                cout << "["<< s <<"] Base3.ibase3 = " << (int)pVtab[s] << endl;
                s++;
                cout << "["<< s <<"] Derive.iderive = " << (int)pVtab[s] << endl;
 

其运行结果如下所示:(在VC++ 2003和G++ 3.4.4下)
[0] Base1::_vptr->
     [0] Derive::f()
     [1] Base1::g()
     [2] Base1::h()
     [3] Driver::g1()
     [4] 00000000      // 注意:在GCC下,这里是1
[1] Base1.ibase1 = 10
[2] Base2::_vptr->
     [0] Derive::f()
     [1] Base2::g()
     [2] Base2::h()
     [3] 00000000      // 注意:在GCC下,这里是1
[3] Base2.ibase2 = 20
[4] Base3::_vptr->
     [0] Derive::f()
     [1] Base3::g()
     [2] Base3::h()
     [3] 00000000
[5] Base3.ibase3 = 30
[6] Derive.iderive = 100

使用图片表示是下面这个样子:
 C++ 对象的内存布局(单一的一般继承) - hubingforever - 民主与科学
  我们可以看到:
1)  每个父类都有自己的虚表。
2)  子类的成员函数被放到了第一个父类的表中。
3)  内存布局中,其父类布局依次按声明顺序排列。
4)  每个父类的虚表中的f()函数都被overwrite成了子类的f()。这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。
 
  评论这张
 
阅读(308)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017