g ++编译器如何通过虚函数实现多重继承?

时间:2015-07-01 12:51:11

标签: c++

在书中提到了#34;内部的C ++对象模型"派生类具有n - 1个额外虚拟表,n是基类的数量。我用g ++编译器进行了一些实验,我的机器是64位。 以下是我的代码。

class A{
    private:
        int a;
    public:
        virtual void print() const{
            cout << a << endl;
        }

};

class B : A{
    private:
        int b;
    public:
        virtual  void set(int num){
            b = num;
        }
};


class C : public A, public B{
    private:
        int c;
    public:
        void print() const{
            cout << c << endl;
        }
        void set(int num){
            c = num;
        }
};

我在gdb中检查每个类的内存布局:

(gdb) p a
$1 = (A) {
  _vptr.A = 0x400bb0 <vtable for A+16>, 
  a = 0
}
(gdb) p b
$2 = (B) {
  _vptr.B = 0x400b90 <vtable for B+16>, 
  b = 4196384
}
(gdb) p c
$3 = (C) {
  <A> = {
    _vptr.A = 0x400b50 <vtable for C+16>, 
    a = 4197101
  }, 
  <B> = {
    _vptr.B = 0x400b70 <vtable for C+48>, 
    b = 0
  }, 
  members of C: 
  c = 0
}

它表明C类中有两个vptrs。然后我用-fdump-class-hierarchy编译它获得了一些信息。

 Vtable for A
    A::_ZTV1A: 3u entries
    0     (int (*)(...))0
    8     (int (*)(...))(& _ZTI1A)
    16    (int (*)(...))A::print

    Class A
       size=16 align=8
       base size=12 base align=8
    A (0x0x7fe4654956c0) 0
        vptr=((& A::_ZTV1A) + 16u)

    Vtable for B
    B::_ZTV1B: 3u entries
    0     (int (*)(...))0
    8     (int (*)(...))(& _ZTI1B)
    16    (int (*)(...))B::set

    Class B
       size=16 align=8
       base size=12 base align=8
    B (0x0x7fe465495720) 0
        vptr=((& B::_ZTV1B) + 16u)

    Vtable for C
    C::_ZTV1C: 7u entries
    0     (int (*)(...))0
    8     (int (*)(...))(& _ZTI1C)
    16    (int (*)(...))C::print
    24    (int (*)(...))C::set
    32    (int (*)(...))-16
    40    (int (*)(...))(& _ZTI1C)
    48    (int (*)(...))C::_ZThn16_N1C3setEi

    Class C
       size=32 align=8
       base size=32 base align=8
    C (0x0x7fe46516e690) 0
        vptr=((& C::_ZTV1C) + 16u)
      A (0x0x7fe465495780) 0
          primary-for C (0x0x7fe46516e690)
      B (0x0x7fe4654957e0) 16
          vptr=((& C::_ZTV1C) + 48u)

然后我对以下问题感到困惑。

  1. Class A size=16 align=8 base size=12 base align=8 我不明白为什么A类的大小是16,基本大小和对齐是什么意思?我认为A类的大小应为12字节,vptr为8字节,int a为4字节。 B级也是如此。
  2. 我认为C级有2 vtables但结果显示只有一个有7个条目。这个vtable和C级的两个vptr之间的关系是什么?
  3. 最后一行显示vptr=((& C::_ZTV1C) + 48u),48是什么意思?并且C类vtable的最后一个条目表明了这一点 48 (int (*)(...))C::_ZThn16_N1C3setEi 这是什么意思?它不是虚函数的名称和顶部的偏移量。为什么第二个vptr指向此条目?

1 个答案:

答案 0 :(得分:0)

vtables有关。对于多重继承,一个对象可能有几个(对于每个包含虚拟成员函数的超类,可能只有一个)。

将一个对象指针转换为某些父类可能需要添加一些偏移量(以获得正确的vtable和成员函数)。