继承关系下的成员布局

一.单个类带虚函数的成员布局

class A
{
public:
    int m_i;
    int m_j;
    virtual void func() {}
};
int main()
{
    cout<<sizeof(A)<<endl;  //12
    printf("m_i的偏移量=%d\n",&A::m_i); //4
    printf("m_j的偏移量=%d\n",&A::m_j);//8
}

图示说明:

因为类里面存在虚函数,所以会产生一个虚函数表,存在于类所有成员的上面;

二.单一继承 父类带虚函数 的成员布局

class Base1
{
public:
    int b_i;
    virtual void func() {}
};
class A:public Base1
{
public:
    int m_i;
    int m_j;
    virtual void func() {}
};
int main()
{
    cout << sizeof(Base1) << endl; //8
    cout << sizeof(A) << endl;     //16

    printf("b_i的偏移量=%d\n", &A::b_i);//4
    printf("m_i的偏移量=%d\n", &A::m_i); //8
    printf("m_j的偏移量=%d\n", &A::m_j); //12

    return 0;
}

图示理解:

基类和派生类都是带有虚函数的,但是最后派生类只有一个vptr(虚函数表指针),说明基类和派生类公用一个虚函数表指针。

三.单一继承 父类不带虚函数 的数据成员布局

class Base1
{
public:
    int b_i;
};
class A:public Base1
{
public:
    int m_i;
    int m_j;
    virtual void func() {}
};
int main()
{
    cout << sizeof(Base1) << endl; //4
    cout << sizeof(A) << endl;     //16

    printf("b_i的偏移量=%d\n", &A::b_i);//0
    printf("m_i的偏移量=%d\n", &A::m_i); //8
    printf("m_j的偏移量=%d\n", &A::m_j); //12

    return 0;
}

看到b_i的偏移量是0的时候,可能会以为内存布局是这样的:

其实,并不是这样的,偏移量为0是b_i对Base1的偏移量是0,并不是对A类的偏移量是0,真实的内存布局应该是这样的:

四.单一继承数据成员布局 this指针偏移知识补充

1.Base1中没有虚函数

class Base1
{
public:
    int b_i;
    Base1()
    {
        printf("Base1的this指针是%p\n",this);
    };
class A:public Base1
{
public:
    int m_i;
    int m_j;
    virtual void func() {}
    Base1()
    {
        printf("A的this指针是%p\n",this);
    }
};
int main()
{
    cout << sizeof(Base1) << endl; //4
    cout << sizeof(A) << endl;     //16

    printf("b_i的偏移量=%d\n", &A::b_i);//0
    printf("m_i的偏移量=%d\n", &A::m_i); //8
    printf("m_j的偏移量=%d\n", &A::m_j); //12

    return 0;
}

图示理解:

2.多重继承且父类都带虚函数的数据成员布局

class Base1
{
public:
    int b_i;
    Base1()
    {
        printf("Base1的this指针是:%p\n", this);
    }
    virtual void func() {}
};

class Base2
{
public:
    int b2_i;
    Base2()
    {
        printf("Base2的this指针是:%p\n", this);
    }
    virtual void func2() {}
};


class A:public Base1,public Base2
{
public:
    int m_i;
    int m_j;
    virtual void func() {}
    A()
    {
        printf("A的this指针是:%p\n", this);
    }
    ~A(){}
};

int main()
{
    cout << sizeof(Base1) << endl; //8
    cout << sizeof(Base2) << endl; //8
    cout << sizeof(A) << endl;     //24

    printf("b_i的偏移量=%d\n", &A::b_i);//4
    printf("b2_i的偏移量=%d\n", &A::b2_i);//4
    printf("m_i的偏移量=%d\n", &A::m_i); //16
    printf("m_j的偏移量=%d\n", &A::m_j); //20

图示理解:

结论:

我们要访问一个类对象中的成员,成员的定位是通过this指针,以及该成员的偏移值来确定的;

比如要访问b_i;this指针就会调整为Base1的this指针,然后再偏移4就得到了b_i的位置;

五.父类直至指向子类的多态分析:

int main()
{
    A a;
    a.b_i = 1;
    a.m_i = 2;
    a.m_j = 3;
    Base1* p1 = &a;
    Base2* p2 = &a;
    // a的地址:  a  = 0x0043fc0c 
    // p1的地址: p1 = 0x0043fc0c  // 没有进行调整;
    // p2的地址: p2 = 0x0043fc14  // 进行了调整,指向了Base2所指向的空间; 

    Base2* pa = new A(); // pa = 0x00f0e2c0 
    A* pb= (A*)pa;  // pb = 0x00f0e2b8 
    //delete pa; //  这里会报错; 因为pa里面存储的不是当时new的所有内容;
    delete pb; //得这样释放;
    

    return 0;
}

六.更复杂的继承

我的内容可能写的比较潦草,如果需要笔记内容相对应的课程,请关注并私信我。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值