• C++类的内存结构


    摘自Jerry19880126

    简单类

    class Base
    {
        int a;
        int b;
    public:
        void CommonFunction();
    };
    

    简单类继承

    class DerivedClass: public Base
    {
        int c;
    public:
        void DerivedCommonFunction();
    };
    

    带有虚函数的类

    class Base
    {
        int a;
        int b;
    public:
        void CommonFunction();
        void virtual VirtualFunction();
    };
    

    虚函数类继承

    没有复写的继承

     class DerivedClass: public Base
    {
        int c;
    public:
        void DerivedCommonFunction();
        void virtual VirtualFunction();
    };
    

    复写的继承

    class DerivedClass1 : public Base
    {
        int c;
    public:
        void DerivedCommonFunction();
        void virtual VirtualFunction();
        void virtual VirtualFunction2();
    };
    

    多重继承

    class Base
    {
        int a;
        int b;
    public:
        void CommonFunction();
        void virtual VirtualFunction();
    };
    
    
    class DerivedClass1: public Base
    {
        int c;
    public:
        void DerivedCommonFunction();
        void virtual VirtualFunction();
    };
    
    class DerivedClass2 : public Base
    {
        int d;
    public:
        void DerivedCommonFunction();
        void virtual VirtualFunction();
    };
    
    class DerivedDerivedClass : public DerivedClass1, public DerivedClass2
    {
        int e;
    public:
        void DerivedDerivedCommonFunction();
        void virtual VirtualFunction();
    };
    

    内存分布从父类到子类,依次如下:
    Base中有一个虚表指针

    DerivedClass1继承了Base,内存排布是先父类后子类。

    DerivedClass2的情况是类似于DerivedClass1的。

    DerivedDerivedClass,由外向内看,它并列地排布着继承而来的两个父类DerivedClass1与DerivedClass2,还有自身的成员变量e。DerivedClass1包含了它的成员变量c,以及Base,Base有一个0地址偏移的虚表指针,然后是成员变量a和b;DerivedClass2的内存排布类似于DerivedClass1,注意到DerivedClass2里面竟然也有一份Base。

    这里有两份虚表了,分别针对DerivedClass1与DerivedClass2,在&DerivedDericedClass_meta下方的数字是首地址偏移量,靠下面的虚表的那个-16表示指向这个虚表的虚指针的内存偏移,这正是DerivedClass2中的{vfptr}在DerivedDerivedClass的内存偏移。

    虚继承

    class DerivedClass1: virtual public Base
    {
        int c;
    public:
        void DerivedCommonFunction();
        void virtual VirtualFunction();
    };
    
    class DerivedClass2 : virtual public Base
    {
        int d;
    public:
        void DerivedCommonFunction();
        void virtual VirtualFunction();
    };
    
    class DerivedDerivedClass :  public DerivedClass1, public DerivedClass2
    {
        int e;
    public:
        void DerivedDerivedCommonFunction();
        void virtual VirtualFunction();
    };
    

    Base类没有变化

    DerivedClass1就已经有变化了,原来是先排虚表指针与Base成员变量,vfptr位于0地址偏移处;但现在有两个虚表指针了,一个是vbptr,另一个是vfptr。vbptr是这个DerivedClass1对应的虚表指针,它指向DerivedClass1的虚表vbtable,另一个vfptr是虚基类表对应的虚指针,它指向vftable。

    下面列出了两张虚表,第一张表是vbptr指向的表,8表示{vbptr}与{vfptr}的偏移;第二张表是vfptr指向的表,-8指明了这张表所对应的虚指针位于内存的偏移量。

    DerivedClass2的内存分布类似于DerivedClass1,同样会有两个虚指针,分别指向两张虚表(第二张是虚基类表)。

    下面来仔细看一下DerivedDerivedClass的内存分布,这里面有三个虚指针了,但base却只有一份。第一张虚表是内含DerivedClass1的,20表示它的虚指针{vbptr}离虚基表指针{vfptr}的距离,第二张虚表是内含DerivedClass2的,12表示它的虚指针{vbptr}离虚基表指针{vfptr}的距离,最后一张表是虚基表,-20指明了它对应的虚指针{vfptr}在内存中的偏移。


    虚继承的作用是减少了对基类的重复,代价是增加了虚表指针的负担(更多的虚表指针)。

    下面总结一下(当基类有虚函数时):

    1. 每个类都有虚指针(vptr, virtual table pointer)和虚函数表(vtbl, virtual table); 2. 如果不是虚继承,那么子类将父类的虚指针继承下来,并指向自身的虚函数表(发生在对象构造时)。有多少个虚函数,虚函数表里面的项就会有多少。多重继承时,可能存在多个的基类虚函数表与虚指针; 3. 如果是虚继承,那么子类会有两份虚指针,一份指向自己的虚函数表,另一份指向基类虚函数表,多重继承时基类虚函数表与基类虚指针有且只有一份。
  • 相关阅读:
    MyBatis的分页插件PageHelper
    Mybatis的插件 PageHelper 分页查询使用方法
    textarea还剩余字数统计,支持复制粘贴的时候统计字数
    Mybatis——oracle——sql语句结尾不加;
    window.location.href和window.open的几种用法和区别
    window.location.href的用法(动态输出跳转)
    mybatis rownum Oracle 随机
    java 回车替换换行
    session 取
    socket编程浅知识
  • 原文地址:https://www.cnblogs.com/narjaja/p/10067996.html
Copyright © 2020-2023  润新知