[C++基础]对象内存分布--虚继承

virtual在C++中最大的功能就是声明虚函数和虚基类。虚拟继承是为了解决多重继承下公共基类的多份拷贝问题。
虚继承

虚继承解决了菱形继承中对派生类拥有多个间接父类实例的情况。虚继承的派生类的内存布局与普通继承很多不同,主要体现在:

    虚继承的子类,如果本身定义了新的虚函数,则编译器为其生成一个虚函数指针(vptr)以及一张虚函数表。该vptr位于对象内存最前面。vs非虚继承:直接扩展父类虚函数表。
    虚继承的子类也单独保留了父类的vprt与虚函数表。这部分内容接与子类内容以一个四字节的0来分界。
    虚继承的子类对象中,含有四字节的虚表指针偏移值。

虚基类表解析

在C++对象模型中,虚继承而来的子类会生成一个隐藏的虚基类指针(vbptr),在MicrosoftVisualC++中,虚基类表指针总是在虚函数表指针之后,因而,对某个类实例来说,如果它有虚基类指针,那么虚基类指针可能在实例的0字节偏移处(该类没有vptr时,vbptr就处于类实例内存布局的最前面,否则vptr处于类实例内存布局的最前面),也可能在类实例的4字节偏移处。
一个类的虚基类指针指向的虚基类表,与虚函数表一样,虚基类表也由多个条目组成,条目中存放的是偏移值。第一个条目存放虚基类表指针(vbptr)所在地址到该类内存首地址的偏移值,由第一段的分析我们知道,这个偏移值为0(类没有vptr)或者-4(类有虚函数,此时有vptr)。我们通过一张图来更好地理解。


虚基类表的第二、第三...个条目依次为该类的最左虚继承父类、次左虚继承父类...的内存地址相对于虚基类表指针的偏移值,这点我们在下面会验证。
单虚拟继承

    class Base
    {
    public:
        virtual void fun1()
        {
            cout << "Base::func1()" << endl;
        }
        virtual void fun2()
        {
            cout << "Base::func2()" << endl;
        }
    private:
        int b;
    };
    class Derive : virtual public Base
    {
    public:
        virtual void fun1()
        {
            cout << "Derive::func1()" << endl;
        }
        virtual void fun3()
        {
            cout << "Derive::func3()" << endl;
        }
        void fun4()
        {
            cout << "Derive::func4()" << endl;
        }
    private:
        int d;
    };
    //1 > class Derive    size(20) :
    //1 > +-- -
    //1 > 0 | {vfptr}
    //1 > 4 | {vbptr}
    //1 > 8 | d
    //1 > +-- -
    //1 > +-- - (virtual base Base)
    //1 > 12 | {vfptr}
    //1 > 16 | b
    //1 > +-- -
    //1 >
    //1 > Derive::$vftable@Derive@:
    //1 > | &Derive_meta
    //1 > | 0
    //1 > 0 | &Derive::fun3
    //1 >
    //1 > Derive::$vbtable@:
    //1 > 0 | -4
    //1 > 1 | 8 (Derived(Derive + 4)Base)
    //1 >
    //1 > Derive::$vftable@Base@:
    //1 > | -12
    //1 > 0 | &Derive::fun1
    //1 > 1 | &Base::fun2
    //1 >
    //1 > Derive::fun1 this adjustor: 12
    //1 > Derive::fun3 this adjustor: 0
    //1 > vbi: class  offset o.vbptr  o.vbte fVtorDisp
    //1 >       Base      12       4       4 0
    //1 >

多虚拟继承

    class Base1
    {
    public:
        virtual void fun1()
        {
            cout << "Base1::fun1" << endl;
        }
        virtual void fun2()
        {
            cout << "Base1::fun2" << endl;
        }
    private:
        int b1;
    };
    class Base2
    {
    public:
        virtual void fun1()
        {
            cout << "Base2::fun1" << endl;
        }
        virtual void fun2()
        {
            cout << "Base2::fun2" << endl;
        }
    private:
        int b2;
    };
    class DeriveA : virtual public Base1, virtual public Base2
    {
    public:
        virtual void fun1()
        {
            cout << "DeriveA::fun1" << endl;
        }
        virtual void fun3()
        {
            cout << "DeriveA::fun3" << endl;
        }
    private:
        int d1;
    };
    //1 > class DeriveA    size(28) :
    //1 > +-- -
    //1 > 0 | {vfptr}
    //1 > 4 | {vbptr}
    //1 > 8 | d1
    //1 > +-- -
    //1 > +-- - (virtual base Base1)
    //1 > 12 | {vfptr}
    //1 > 16 | b1
    //1 > +-- -
    //1 > +-- - (virtual base Base2)
    //1 > 20 | {vfptr}
    //1 > 24 | b2
    //1 > +-- -
    //1 >
    //1 > DeriveA::$vftable@DeriveA@:
    //1 > | &DeriveA_meta
    //1 > | 0
    //1 > 0 | &DeriveA::fun3
    //1 >
    //1 > DeriveA::$vbtable@:
    //1 > 0 | -4
    //1 > 1 | 8 (DeriveAd(DeriveA + 4)Base1)
    //1 > 2 | 16 (DeriveAd(DeriveA + 4)Base2)
    //1 >
    //1 > DeriveA::$vftable@Base1@:
    //1 > | -12
    //1 > 0 | &DeriveA::fun1
    //1 > 1 | &Base1::fun2
    //1 >
    //1 > DeriveA::$vftable@Base2@:
    //1 > | -20
    //1 > 0 | &thunk: this -= 8; goto DeriveA::fun1
    //1 > 1 | &Base2::fun2
    //1 >
    //1 > DeriveA::fun1 this adjustor: 12
    //1 > DeriveA::fun3 this adjustor: 0
    //1 > vbi:  class  offset o.vbptr  o.vbte fVtorDisp
    //1 >       Base1      12       4       4 0
    //1 >       Base2      20       4       8 0
    //1 >

菱形虚拟继承

    class Base
    {
    public:
        virtual void func1()
        {
            cout << "Base::func1()" << endl;
        }
        virtual void func2()
        {
            cout << "Base::func2()" << endl;
        }
    private:
        int b;
    };
    class Base1 : virtual public Base
    {
    public:
        virtual void func1()
        {
            cout << "Base1::func1()" << endl;
        }
        virtual void func3()
        {
            cout << "Base1::func3()" << endl;
        }
    private:
        int b1;
    };
    class Base2 :virtual public Base
    {
    public:
        virtual void func1()
        {
            cout << "Base2::func2()" << endl;
        }
        virtual void func4()
        {
            cout << "Base2::func4()" << endl;
        }
    private:
        int b2;
    };
    class Derive : virtual public Base1, virtual public Base2
    {
    public:
        virtual void func1()
        {
            cout << "Derive::func1()" << endl;
        }
        virtual void func5()
        {
            cout << "Derive::func5()" << endl;
        }
    private:
        int d;
    };
    //1 > class Derive    size(44) :
    //1 > +-- -
    //1 > 0 | {vfptr}
    //1 > 4 | {vbptr}
    //1 > 8 | d
    //1 > +-- -
    //1 > +-- - (virtual base Base)
    //1 > 12 | {vfptr}
    //1 > 16 | b
    //1 > +-- -
    //1 > +-- - (virtual base Base1)
    //1 > 20 | {vfptr}
    //1 > 24 | {vbptr}
    //1 > 28 | b1
    //1 > +-- -
    //1 > +-- - (virtual base Base2)
    //1 > 32 | {vfptr}
    //1 > 36 | {vbptr}
    //1 > 40 | b2
    //1 > +-- -
    //1 >
    //1 > Derive::$vftable@:
    //1 > | &Derive_meta
    //1 > | 0
    //1 > 0 | &Derive::func5
    //1 >
    //1 > Derive::$vbtable@Derive@:
    //1 > 0 | -4
    //1 > 1 | 8 (Derived(Derive + 4)Base)
    //1 > 2 | 16 (Derived(Derive + 4)Base1)
    //1 > 3 | 28 (Derived(Derive + 4)Base2)
    //1 >
    //1 > Derive::$vftable@Base@:
    //1 > | -12
    //1 > 0 | &Derive::func1
    //1 > 1 | &Base::func2
    //1 >
    //1 > Derive::$vftable@Base1@:
    //1 > | -20
    //1 > 0 | &Base1::func3
    //1 >
    //1 > Derive::$vbtable@Base1@:
    //1 > 0 | -4
    //1 > 1 | -12 (Derived(Base1 + 4)Base)
    //1 >
    //1 > Derive::$vftable@Base2@:
    //1 > | -32
    //1 > 0 | &Base2::func4
    //1 >
    //1 > Derive::$vbtable@Base2@:
    //1 > 0 | -4
    //1 > 1 | -24 (Derived(Base2 + 4)Base)
    //1 >
    //1 > Derive::func1 this adjustor: 12
    //1 > Derive::func5 this adjustor: 0
    //1 > vbi:  class  offset o.vbptr  o.vbte fVtorDisp
    //1 >        Base      12       4       4 0
    //1 >       Base1      20       4       8 0
    //1 >       Base2      32       4      12 0
    //1 >

 
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值