C++对象的内存布局下

原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://haoel.blog.51cto.com/313033/124561

重复继承

 
函数。
 

 
字节),而且还有自己的虚函数,自己overwrite覆盖了超类的函数,f1() 为自己的虚函数。
 
class  B
{
     public :
         int  ib;
         char  cb;
     public :
        B():ib( 0 ),cb( 'B' ) {}
 
         virtual   void  f() { cout <<  "B::f()"  << endl;}
         virtual   void  Bf() { cout <<  "B::Bf()"  << endl;}
};
class  B1 :   public  B
{
     public :
         int  ib1;
         char  cb1;
     public :
        B1():ib1( 11 ),cb1( '1' ) {}
 
         virtual   void  f() { cout <<  "B1::f()"  << endl;}
         virtual   void  f1() { cout <<  "B1::f1()"  << endl;}
         virtual   void  Bf1() { cout <<  "B1::Bf1()"  << endl;}
 
};
class  B2:   public  B
{
     public :
         int  ib2;
         char  cb2;
     public :
        B2():ib2( 12 ),cb2( '2' ) {}
 
         virtual   void  f() { cout <<  "B2::f()"  << endl;}
         virtual   void  f2() { cout <<  "B2::f2()"  << endl;}
         virtual   void  Bf2() { cout <<  "B2::Bf2()"  << endl;}
       
};
 
class  D :  public  B1,  public  B2
{
     public :
         int  id;
         char  cd;
     public :
        D():id( 100 ),cd( 'D' ) {}
 
         virtual   void  f() { cout <<  "D::f()"  << endl;}
         virtual   void  f1() { cout <<  "D::f1()"  << endl;}
         virtual   void  f2() { cout <<  "D::f2()"  << endl;}
         virtual   void  Df() { cout <<  "D::Df()"  << endl;}
       
};
下)
    typedef   void (*Fun)( void );
     int ** pVtab = NULL;
    Fun pFun = NULL;
 
    D d;
    pVtab = ( int **)&d;
    cout <<  "[0] D::B1::_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] " ;    pFun();
    pFun = (Fun)pVtab[ 0 ][ 5 ];
    cout <<  "     [5] 0x"  << pFun << endl;
   
    cout <<  "[1] B::ib = "  << ( int )pVtab[ 1 ] << endl;
    cout <<  "[2] B::cb = "  << ( char )pVtab[ 2 ] << endl;
    cout <<  "[3] B1::ib1 = "  << ( int )pVtab[ 3 ] << endl;
    cout <<  "[4] B1::cb1 = "  << ( char )pVtab[ 4 ] << endl;
 
    cout <<  "[5] D::B2::_vptr->"  << endl;
    pFun = (Fun)pVtab[ 5 ][ 0 ];
    cout <<  "     [0] " ;    pFun();
    pFun = (Fun)pVtab[ 5 ][ 1 ];
    cout <<  "     [1] " ;    pFun();
    pFun = (Fun)pVtab[ 5 ][ 2 ];
    cout <<  "     [2] " ;    pFun();
    pFun = (Fun)pVtab[ 5 ][ 3 ];
    cout <<  "     [3] " ;    pFun();
    pFun = (Fun)pVtab[ 5 ][ 4 ];
    cout <<  "     [4] 0x"  << pFun << endl;
 
    cout <<  "[6] B::ib = "  << ( int )pVtab[ 6 ] << endl;
    cout <<  "[7] B::cb = "  << ( char )pVtab[ 7 ] << endl;   
    cout <<  "[8] B2::ib2 = "  << ( int )pVtab[ 8 ] << endl;
    cout <<  "[9] B2::cb2 = "  << ( char )pVtab[ 9 ] << endl;
 
    cout <<  "[10] D::id = "  << ( int )pVtab[ 10 ] << endl;
    cout <<  "[11] D::cd = "  << ( char )pVtab[ 11 ] << endl;
 
下面是对于子类实例中的虚函数表的图:
 
 
 
 
B2中,其有B1的成员在D继承而来的。所以,如果我们使用以下语句,则会产生二义性编译错误:
 
D d;
d.ib = 0;                //二义性错误
d.B1::ib = 1;            //正确
d.B2::ib = 2;            //正确

中还是有两个实例,这种继承造成了数据的重复,我们叫这种继承为重复继承。重复的基类数据成员可能并不是我们想要的。所以,C++上述的“重复继承”只需要把B1的语法中加上virtual 在查看DGCC下的程序大家可以根据我给出的程序自己仿照着写一个去试一试):
 
     int ** pVtab = NULL;
    Fun pFun = NULL;
 
    B1 bb1;
 
    pVtab = ( int **)&bb1;
    cout <<  "[0] B1::_vptr->"  << endl;
    pFun = (Fun)pVtab[ 0 ][ 0 ];
    cout <<  "     [0] " ;
    pFun();  //B1::f1();
    cout <<  "     [1] " ;
    pFun = (Fun)pVtab[ 0 ][ 1 ];
    pFun();  //B1::bf1();
    cout <<  "     [2] " ;
    cout << pVtab[ 0 ][ 2 ] << endl;
 
    cout <<  "[1] = 0x" ;
    cout << ( int *)*(( int *)(&bb1)+ 1 ) <<endl;  //B1::ib1
    cout <<  "[2] B1::ib1 = " ;
    cout << ( int )*(( int *)(&bb1)+ 2 ) <<endl;  //B1::ib1
    cout <<  "[3] B1::cb1 = " ;
    cout << ( char )*(( int *)(&bb1)+ 3 ) << endl;  //B1::cb1
 
    cout <<  "[4] = 0x" ;
    cout << ( int *)*(( int *)(&bb1)+ 4 ) << endl;  //NULL
 
    cout <<  "[5] B::_vptr->"  << endl;
    pFun = (Fun)pVtab[ 5 ][ 0 ];
    cout <<  "     [0] " ;
    pFun();  //B1::f();
    pFun = (Fun)pVtab[ 5 ][ 1 ];
    cout <<  "     [1] " ;
    pFun();  //B::Bf();
    cout <<  "     [2] " ;
    cout <<  "0x"  << (Fun)pVtab[ 5 ][ 2 ] << endl;
 
    cout <<  "[6] B::ib = " ;
    cout << ( int )*(( int *)(&bb1)+ 6 ) <<endl;  //B::ib
    cout <<  "[7] B::cb = " ;
 
的对比):
 
GCC 3.4.4
VC++ 2003
    [1] : B1::f1()
[1] B1::ib1 : 11
    [0] : B1::f()
[4] B::ib : 0
[0] B1::_vptr->
     [2] 0
ç[2] B1::ib1 = 11
[5] B::_vptr->
     [2] 0x00000000
这里,大家可以自己对比一下。关于细节上,我会在后面一并再说。
 
的(因为VC++的相对要清楚很多,所以这里只给出VC++<span lang="ZH-CN" times="" new="" roman';="" mso-hansi-font-family:="" 'times="" roman'"="" style="padding: 0px; margin: 0px; font-family: 宋体;">的程序,GCCGCC    [0] : D::f()
    [3] : D::f2()
[1] B1::ib1 : 11
    [0] : D::f()
    [3] : 0
[6] D::id : 100
    [0] : D::f()
[9] B::ib : 0
[0] D::B1::_vptr->
     [2] D::Df()
ç-4
[4] D::B2::_vptr->
     [2] 00000000
该地址取值后是[7] B2::cb2 = 2
[10]  = 0x00000000
     [1] B::Bf()
[13] B::cb = B
 
 
1) ,除了一些细节上的不同,其大体上的对象布局是一样的。也就是说,先是B1 (灰色),而B 关于虚函数表,尤其是第一个虚表,GCC 的虚表比较清晰和有逻辑性。

都把B分隔符把B的布局分开。GCC中的内存布局有两个地址我有些不是很明白,在其中我用红色标出了。取其内容是-45)GCC中则没有指向Bsize这门语言是一门比较复杂的语言,对于程序员来说,我们似乎永远摸不清楚这门语言背着我们在干了什么。需要熟悉这门语言,我们就必需要了解C++这门最难的编程语言。
 
Ajax是: haoel@hotmail.com  

本文出自 “陈皓的个人专栏” 博客,请务必保留此出处http://haoel.blog.51cto.com/313033/124561

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值