美文网首页人生几何?
多重继承成员布局与this指针的调整

多重继承成员布局与this指针的调整

作者: 404Not_Found | 来源:发表于2021-09-01 22:54 被阅读0次
    • 作者: 雪山肥鱼
    • 时间:20210901 00:19
    • 目的: 多重继承成员布局与this指针的调整

    父类无虚函数,子类有虚函数

    class Base
    {
    public:
        int m_bi;
        Base() {
            printf("Base::Base()的this 指针是 %p\n", this);
        }
    };
    class Myclass : public Base
    {
    public:
        int m_i;
        int m_j;
        virtual void myvirfunc()
        {}
        Myclass()
        {
            int abc = 1;
            printf("Myclass::Myclass()的this 指针是 %p\n", this);
        }
        ~Myclass()
        {
            int def = 0;
        }
    };
    
    int main(int argc, char **argv)
    {
        printf("myclass:m_bi = %d\n", &Myclass::m_bi);
        printf("myclass:m_i = %d\n", &Myclass::m_i);
        printf("myclass:m_j = %d\n", &Myclass::m_j);
    
        Myclass myobj;
        printf("myobj的地址是:%p\n", &myobj);
        myobj.m_bi = 0;
        myobj.m_i = 1;
        myobj.m_i = 2;
    
        return 0;
    }
    
    this指针位置不同.png

    上述布局的输出结果很明显,如下图所示:


    布局.png
    • 访问父类的this 与 子类的 this 不同
    • 访问成员变量,this指针都需要进行调整, 才能访问父类的东东。

    子类有虚函数,父类也有虚函数

    class Base
    {
    public:
        int m_bi;
        virtual void voidfatherfun()
        {
    
        }
        Base() {
            printf("Base::Base()的this 指针是 %p\n", this);
        }
    };
    class Myclass : public Base
    {
    public:
        int m_i;
        int m_j;
        virtual void myvirfunc()
        {}
        Myclass()
        {
            int abc = 1;
            printf("Myclass::Myclass()的this 指针是 %p\n", this);
        }
        ~Myclass()
        {
            int def = 0;
        }
    };
    
    int main(int argc, char **argv)
    {
        printf("myclass:m_bi = %d\n", &Myclass::m_bi);
        printf("myclass:m_i = %d\n", &Myclass::m_i);
        printf("myclass:m_j = %d\n", &Myclass::m_j);
    
        Myclass myobj;
        printf("myobj的地址是:%p\n", &myobj);
        myobj.m_bi = 0;
        myobj.m_i = 1;
        myobj.m_i = 2;
    
        return 0;
    
    图片.png
    • this 指针相同,父类与子类即使虚函数不同也共用一个vptr
    • 访问父类的东东,this 指针不需要进行调整

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

    class Base1
    {
    public:
        int m_b1i;
        virtual void voidfatherfun()
        {
    
        }
        Base1() {
            printf("Base1::Base1()的this 指针是 %p\n", this);
        }
    };
    
    class Base2
    {
    public:
        int m_b2i;
        virtual void voidfatherfun2()
        {
    
        }
        Base2() {
            printf("Base2::Base2()的this 指针是 %p\n", this);
        }
    };
    class Myclass : public Base1, public Base2
    {
    public:
        int m_i;
        int m_j;
        virtual void myvirfunc()
        {}
        Myclass()
        {
            int abc = 1;
            printf("Myclass::Myclass()的this 指针是 %p\n", this);
        }
        ~Myclass()
        {
            int def = 0;
        }
    };
    
    int main(int argc, char **argv)
    {
        printf("sizeof Myclass:%d\n", sizeof(Myclass));
        printf("myclass:m_bi = %d\n", &Myclass::m_b1i);
        printf("myclass:m_bi = %d\n", &Myclass::m_b2i);
        printf("myclass:m_i = %d\n", &Myclass::m_i);
        printf("myclass:m_j = %d\n", &Myclass::m_j);
    
        Myclass myobj;
        printf("myobj的地址是:%p\n", &myobj);
    
        return 0;
    }
    
    运行结果.png

    B1 和 Myclass 共用一个 this 指针, 如果访问B2 则需要修改this 指针的值。

    内存布局如下:


    内存布局.png

    注意 this 指针的位置是不同的!

    结论:
    我们要访问一个类对象中的成员,成员定位是通过this指针的来的(编译器会自动调整,比如我们讨论的多重继承中Base1, Base2 就不用) 以及偏移值来定位的。
    this指针的调整需要编译器来介入。

    深解多重继承中的this偏移

    Myclass myobj;
    myobj.m_i = 1;
    myobj.m_j = 2;
    myobj.m_b1i = 3;
    myobj.m_b2i = 4;
    
    Base2 * pBase2 = &myobj;
    
    

    这里的现象很有意思
    &myobj 的地址 :
    0x00bdfe04 {m_i=1 m_j=2 },
    pbase2 的地址:
    pbase2 = 0x00bdfe0c

    两者并不相同,差了8个字节。
    实际编译器是这么操作的:

        Base2 * pbase2 = ( ( (char*)&myobj) + sizeof(Base1) );
    

    这里做的,个人认为是调整了this指针的位置。

    同理

    Base1 * pbase1 = &myobj 就不会进行调整
    
        Base2 *pBase3 = new Myclass(); //指向的是 Base2 的 this 指针位置 428
        Myclass *psubobj = (Myclass*)pBase3;// 420
    

    分配堆后,进行转化,发现this 指针 同样调整了8个字节。多继承完全阐述了 编译器堆this指针的调整。

        delete psubobj; // 正确的
        //delete pBase3;// 分配的有问题,说明pBase3 并不是 真个堆的首地址。而是调整了this指针后的地址
    

    下面的 delete pBase3 是绝对有问题的。因为delete不干净。会报错呢。

    再次举例:


    多重继承的举例.png

    学到: 多重继承中,this指针的调整

    相关文章

      网友评论

        本文标题:多重继承成员布局与this指针的调整

        本文链接:https://www.haomeiwen.com/subject/zmntwltx.html