设为首页 加入收藏

TOP

谈VC++对象模型(三十四)
2012-11-02 08:51:57 来源: 作者: 【 】 浏览:14131
Tags:对象 模型

    单继承。由于派生类实例与其基类实例之间的偏移量是常数0,所以,可以直接利用基类指针和基类成员之间的偏移量关系,如此计算得以简化。
   
    D* pd;
   
    pd->c1; // *(pd + dDC + dCc1); // *(pd + dDc1);
   
    pd->d1; // *(pd + dDd1);
   
    译者注:D从C单继承,pd为指向D的指针。
   
    当访问基类成员c1时,计算步骤本来应该为"pd+dDC+dCc1",即为先计算D对象和C对象之间的偏移,再在此基础上加上C对象指针与成员变量c1之间的偏移量。然而,由于dDC恒定为0,所以直接计算C对象地址与c1之间的偏移就可以了。
   
    当访问派生类成员d1时,直接计算偏移量。
   
    多重继承。虽然派生类与某个基类之间的偏移量可能不为0,然而,该偏移量总是一个常数。只要是个常数,访问成员变量,计算成员变量偏移时的计算就可以被简化。可见即使对于多重继承来说,访问成员变量开销仍然不大。
   
    F* pf;
   
    pf->c1; // *(pf + dFC + dCc1); // *(pf + dFc1);
   
    pf->e1; // *(pf + dFE + dEe1); // *(pf + dFe1);
   
    pf->f1; // *(pf + dFf1);
   
    译者注:F继承自C和E,pf是指向F对象的指针。
   
    访问C类成员c1时,F对象与内嵌C对象的相对偏移为0,可以直接计算F和c1的偏移;
   
    访问E类成员e1时,F对象与内嵌E对象的相对偏移是一个常数,F和e1之间的偏移计算也可以被简化;
   
    访问F自己的成员f1时,直接计算偏移量。
   
    虚继承。当类有虚基类时,访问非虚基类的成员仍然是计算固定偏移量的问题。然而,访问虚基类的成员变量,开销就增大了,因为必须经过如下步骤才能获得成员变量的地址:获取"虚基类表指针";获取虚基类表中某一表项的内容;把内容中指出的偏移量加到"虚基类表指针"的地址上。然而,事情并非永远如此。正如下面访问I对象的c1成员那样,如果不是通过指针访问,而是直接通过对象实例,则派生类的布局可以在编译期间静态获得,偏移量也可以在编译时计算,因此也就不必要根据虚基类表的表项来间接计算了。
   
    I* pi;
   
    pi->c1; // *(pi + dIGvbptr + (*(pi+dIGvbptr)) + dCc1);
   
    pi->g1; // *(pi + dIG + dGg1); // *(pi + dIg1);
   
    pi->h1; // *(pi + dIH + dHh1); // *(pi + dIh1);
   
    pi->i1; // *(pi + dIi1);
   
    I i;
   
    i.c1; // *(&i + IdIC + dCc1); // *(&i + IdIc1);
   
    译者注:I继承自G和H,G和H的虚基类是C,pi是指向I对象的指针。
   
    访问虚基类C的成员c1时,dIGvbptr是"在I中,I对象指针与G的"虚基类表指针"之间的偏移",*(pi + dIGvbptr)是虚基类表的开始地址,*(pi + dIGvbptr) 是虚基类表的第二项的内容(在I对象中,G对象的"虚基类表指针"与虚基类之间的偏移),dCc1是C对象指针与成员变量c1之间的偏移;
   
    访问非虚基类G的成员g1时,直接计算偏移量;
   
    访问非虚基类H的成员h1时,直接计算偏移量;
   
    访问自身成员i1时,直接使用偏移量;
   
    当声明了一个对象实例,用点"."操作符访问虚基类成员c1时,由于编译时就完全知道对象的布局情况,所以可以直接计算偏移量。
   
    当访问类继承层次中,多层虚基类的成员变量时,情况又如何呢?比如,访问虚基类的虚基类的成员变量时?一些实现方式为:保存一个指向直接虚基类的指针,然后就可以从直接虚基类找到它的虚基类,逐级上推。VC++(www.cppentry.com)优化了这个过程。VC++(www.cppentry.com)在虚基类表中增加了一些额外的项,这些项保存了从派生类到其各层虚基类的偏移量。
   
    4 强制转化
   
    如果没有虚基类的问题,将一个指针强制转化为另一个类型的指针代价并不高昂。如果在要求转化的两个指针之间有"基类-派生类"关系,编译器只需要简单地在两者之间加上或者减去一个偏移量即可(并且该量还往往为0)。
   
    F* pf;
   
    (C*)pf; // (C*)(pf pf + dFC : 0); // (C*)pf;
   
    (E*)pf; // (E*)(pf pf + dFE : 0);
   
    C和E是F的基类,将F的指针pf转化为C*或E*,只需要将pf加上一个相应的偏移量。转化为C类型指针C*时,不需要计算,因为F和C之间的偏移量为0.转化为E类型指针E*时,必须在指针上加一个非0的偏移常量dFE.C++(www.cppentry.com)规范要求NULL指针在强制转化后依然为NULL,因此在做强制转化需要的运算之前,VC++(www.cppentry.com)会检查指针是否为NULL.当然,这个检查只有当指针被显示或者隐式转化为相关类型指针时才进行;当在派生类对象中调用基类的方法,从而派生类指针被在后台转化为一个基类的Const "this" 指针时,这个检查就不需要进行了,因为在此时,该指针一定不为NULL.
   

                  

首页 上一页 31 32 33 34 35 36 37 下一页 尾页 34/47/47
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇用VC++制作DLL经验 下一篇VC++数据类型

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: