C++对象的内存布局下

来源:互联网 发布:直销软件制作xazxrj 编辑:程序博客网 时间:2024/06/07 01:18
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。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

0 0
原创粉丝点击