侧边栏壁纸
博主头像
Billy 的技术空间博主等级

君子生非异也,善假于物也。

  • 累计撰写 17 篇文章
  • 累计创建 1 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录
C++

C++ 虚继承与菱形继承

billy
2021-09-10 / 0 评论 / 0 点赞 / 91 阅读 / 10872 字

1、普通类继承

g++ -fdump-lang-class -c main.cpp # 通过此命令将类的内存布局打印到 main.cpp.001l.class 文件内
#include <cstdio>

class Base {
public:
    int base_var = 1;
    void fun() {
        std::puts("Base::fun");
    }
};

class Derived : public Base {
public:
    int derived_var = 2;
    void fun() {
        std::puts("Base::fun");
    }
};
 
int main() {
    printf("%d\n", sizeof(Base));
    printf("%d\n", sizeof(Derived));
}

上面代码类的内存布局如下:

Class Base
   size=4 align=4
   base size=4 base align=4
Base (0x0x7f71742dec60) 0

Class Derived
   size=8 align=4
   base size=8 base align=4
Derived (0x0x7f717418a1a0) 0
  Base (0x0x7f71742ded20) 0

2、虚函数类继承

#include <cstdio>

class Base {
public:
    int base_var = 1;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Derived : public Base {
public:
    int derived_var = 2;
    void fun() {
        std::puts("Base::fun");
    }
};
 
int main() {
    printf("%d\n", sizeof(Base));
    printf("%d\n", sizeof(Derived));
}

上面代码类的内存布局如下:

Vtable for Base
Base::_ZTV4Base: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4Base)
16    (int (*)(...))Base::fun

Class Base
   size=16 align=8
   base size=12 base align=8
Base (0x0x7f1ed6f6cc60) 0
    vptr=((& Base::_ZTV4Base) + 16)

Vtable for Derived
Derived::_ZTV7Derived: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI7Derived)
16    (int (*)(...))Derived::fun

Class Derived
   size=16 align=8
   base size=16 base align=8
Derived (0x0x7f1ed6e181a0) 0
    vptr=((& Derived::_ZTV7Derived) + 16)
  Base (0x0x7f1ed6f6cd20) 0
      primary-for Derived (0x0x7f1ed6e181a0)

3、两个虚函数类继承

#include <cstdio>

class Base1 {
public:
    int base1_var = 1;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Base2 {
public:
    int base2_var = 2;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Derived : public Base1, public Base2 {
public:
    int derived_var = 2;
    void fun() {
        std::puts("Base::fun");
    }
};
 
int main() {
    printf("%d\n", sizeof(Base1));
    printf("%d\n", sizeof(Base2));
    printf("%d\n", sizeof(Derived));
}

上面代码类的内存布局如下:

Vtable for Base1
Base1::_ZTV5Base1: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI5Base1)
16    (int (*)(...))Base1::fun

Class Base1
   size=16 align=8
   base size=12 base align=8
Base1 (0x0x7f8d14563c60) 0
    vptr=((& Base1::_ZTV5Base1) + 16)

Vtable for Base2
Base2::_ZTV5Base2: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI5Base2)
16    (int (*)(...))Base2::fun

Class Base2
   size=16 align=8
   base size=12 base align=8
Base2 (0x0x7f8d14563d20) 0
    vptr=((& Base2::_ZTV5Base2) + 16)

Vtable for Derived
Derived::_ZTV7Derived: 6 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI7Derived)
16    (int (*)(...))Derived::fun
24    (int (*)(...))-16
32    (int (*)(...))(& _ZTI7Derived)
40    (int (*)(...))Derived::_ZThn16_N7Derived3funEv

Class Derived
   size=32 align=8
   base size=32 base align=8
Derived (0x0x7f8d145cf000) 0
    vptr=((& Derived::_ZTV7Derived) + 16)
  Base1 (0x0x7f8d14563de0) 0
      primary-for Derived (0x0x7f8d145cf000)
  Base2 (0x0x7f8d14563e40) 16
      vptr=((& Derived::_ZTV7Derived) + 40)

4、菱形继承

#include <cstdio>

class Base {
public:
    int base_var = 1;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Base1 : public Base {
public:
    int base1_var = 1;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Base2 : public Base {
public:
    int base2_var = 2;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Derived : public Base1, public Base2 {
public:
    int derived_var = 2;
    void fun() {
        std::puts("Base::fun");
    }
};
 
int main() {
    printf("%d\n", sizeof(Base));
    printf("%d\n", sizeof(Base1));
    printf("%d\n", sizeof(Base2));
    printf("%d\n", sizeof(Derived));
}

上面代码类的内存布局如下:


Vtable for Base
Base::_ZTV4Base: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4Base)
16    (int (*)(...))Base::fun

Class Base
   size=16 align=8
   base size=12 base align=8
Base (0x0x7f329622fc60) 0
    vptr=((& Base::_ZTV4Base) + 16)

Vtable for Base1
Base1::_ZTV5Base1: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI5Base1)
16    (int (*)(...))Base1::fun

Class Base1
   size=16 align=8
   base size=16 base align=8
Base1 (0x0x7f32960db1a0) 0
    vptr=((& Base1::_ZTV5Base1) + 16)
  Base (0x0x7f329622fd20) 0
      primary-for Base1 (0x0x7f32960db1a0)

Vtable for Base2
Base2::_ZTV5Base2: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI5Base2)
16    (int (*)(...))Base2::fun

Class Base2
   size=16 align=8
   base size=16 base align=8
Base2 (0x0x7f32960db208) 0
    vptr=((& Base2::_ZTV5Base2) + 16)
  Base (0x0x7f329622fde0) 0
      primary-for Base2 (0x0x7f32960db208)

Vtable for Derived
Derived::_ZTV7Derived: 6 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI7Derived)
16    (int (*)(...))Derived::fun
24    (int (*)(...))-16
32    (int (*)(...))(& _ZTI7Derived)
40    (int (*)(...))Derived::_ZThn16_N7Derived3funEv

Class Derived
   size=40 align=8
   base size=36 base align=8
Derived (0x0x7f329629c000) 0
    vptr=((& Derived::_ZTV7Derived) + 16)
  Base1 (0x0x7f32960db270) 0
      primary-for Derived (0x0x7f329629c000)
    Base (0x0x7f329622fea0) 0
        primary-for Base1 (0x0x7f32960db270)
  Base2 (0x0x7f32960db2d8) 16
      vptr=((& Derived::_ZTV7Derived) + 40)
    Base (0x0x7f329622ff00) 16
        primary-for Base2 (0x0x7f32960db2d8)

5、菱形虚继承

#include <cstdio>

class Base {
public:
    int base_var = 1;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Base1 : public virtual Base {
public:
    int base1_var = 1;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Base2 : public virtual Base {
public:
    int base2_var = 2;
    virtual void fun() {
        std::puts("Base::fun");
    }
};

class Derived : public Base1, public Base2 {
public:
    int derived_var = 2;
    void fun() {
        std::puts("Base::fun");
    }
};
 
int main() {
    printf("%d\n", sizeof(Base));
    printf("%d\n", sizeof(Base1));
    printf("%d\n", sizeof(Base2));
    printf("%d\n", sizeof(Derived));
}

上面代码类的内存布局如下:

Vtable for Base
Base::_ZTV4Base: 3 entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4Base)
16    (int (*)(...))Base::fun

Class Base
   size=16 align=8
   base size=12 base align=8
Base (0x0x7f1d3955fc60) 0
    vptr=((& Base::_ZTV4Base) + 16)

Vtable for Base1
Base1::_ZTV5Base1: 8 entries
0     16
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI5Base1)
24    (int (*)(...))Base1::fun
32    18446744073709551600
40    (int (*)(...))-16
48    (int (*)(...))(& _ZTI5Base1)
56    (int (*)(...))Base1::_ZTv0_n24_N5Base13funEv

VTT for Base1
Base1::_ZTT5Base1: 2 entries
0     ((& Base1::_ZTV5Base1) + 24)
8     ((& Base1::_ZTV5Base1) + 56)

Class Base1
   size=32 align=8
   base size=12 base align=8
Base1 (0x0x7f1d3940b1a0) 0
    vptridx=0 vptr=((& Base1::_ZTV5Base1) + 24)
  Base (0x0x7f1d3955fd20) 16 virtual
      vptridx=8 vbaseoffset=-24 vptr=((& Base1::_ZTV5Base1) + 56)

Vtable for Base2
Base2::_ZTV5Base2: 8 entries
0     16
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI5Base2)
24    (int (*)(...))Base2::fun
32    18446744073709551600
40    (int (*)(...))-16
48    (int (*)(...))(& _ZTI5Base2)
56    (int (*)(...))Base2::_ZTv0_n24_N5Base23funEv

VTT for Base2
Base2::_ZTT5Base2: 2 entries
0     ((& Base2::_ZTV5Base2) + 24)
8     ((& Base2::_ZTV5Base2) + 56)

Class Base2
   size=32 align=8
   base size=12 base align=8
Base2 (0x0x7f1d3940b2d8) 0
    vptridx=0 vptr=((& Base2::_ZTV5Base2) + 24)
  Base (0x0x7f1d3955fde0) 16 virtual
      vptridx=8 vbaseoffset=-24 vptr=((& Base2::_ZTV5Base2) + 56)

Vtable for Derived
Derived::_ZTV7Derived: 12 entries
0     32
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI7Derived)
24    (int (*)(...))Derived::fun
32    16
40    (int (*)(...))-16
48    (int (*)(...))(& _ZTI7Derived)
56    (int (*)(...))Derived::_ZThn16_N7Derived3funEv
64    18446744073709551584
72    (int (*)(...))-32
80    (int (*)(...))(& _ZTI7Derived)
88    (int (*)(...))Derived::_ZTv0_n24_N7Derived3funEv

Construction vtable for Base1 (0x0x7f1d3940b3a8 instance) in Derived
Derived::_ZTC7Derived0_5Base1: 8 entries
0     32
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI5Base1)
24    (int (*)(...))Base1::fun
32    18446744073709551584
40    (int (*)(...))-32
48    (int (*)(...))(& _ZTI5Base1)
56    (int (*)(...))Base1::_ZTv0_n24_N5Base13funEv

Construction vtable for Base2 (0x0x7f1d3940b410 instance) in Derived
Derived::_ZTC7Derived16_5Base2: 8 entries
0     16
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI5Base2)
24    (int (*)(...))Base2::fun
32    18446744073709551600
40    (int (*)(...))-16
48    (int (*)(...))(& _ZTI5Base2)
56    (int (*)(...))Base2::_ZTv0_n24_N5Base23funEv

VTT for Derived
Derived::_ZTT7Derived: 7 entries
0     ((& Derived::_ZTV7Derived) + 24)
8     ((& Derived::_ZTC7Derived0_5Base1) + 24)
16    ((& Derived::_ZTC7Derived0_5Base1) + 56)
24    ((& Derived::_ZTC7Derived16_5Base2) + 24)
32    ((& Derived::_ZTC7Derived16_5Base2) + 56)
40    ((& Derived::_ZTV7Derived) + 88)
48    ((& Derived::_ZTV7Derived) + 56)

Class Derived
   size=48 align=8
   base size=32 base align=8
Derived (0x0x7f1d395cf000) 0
    vptridx=0 vptr=((& Derived::_ZTV7Derived) + 24)
  Base1 (0x0x7f1d3940b3a8) 0
      primary-for Derived (0x0x7f1d395cf000)
      subvttidx=8
    Base (0x0x7f1d3955fea0) 32 virtual
        vptridx=40 vbaseoffset=-24 vptr=((& Derived::_ZTV7Derived) + 88)
  Base2 (0x0x7f1d3940b410) 16
      subvttidx=24 vptridx=48 vptr=((& Derived::_ZTV7Derived) + 56)
    Base (0x0x7f1d3955fea0) alternative-path

0

评论区