虚继承和虚基类

参考

  • 在C++中,在定义公共基类A的派生类B、C…的时候,如果在继承方式前使用关键字virtual对继承方式限定,这样的继承方式就是虚拟继承,公共基类A成为虚基类。这样,在具有公共基类的、使用了虚拟继承方式的多个派生类B、C…的公共派生类D中,该基类A的成员就只有一份拷贝
  • 一个类有多个基类,这样的继承关系称为多继承。在多继承的情况下,如果不同基类的成员名称相同,匹配度相同, 则会造成二义性。为了避免多继承产生的二义性,在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。
  • 会在虚继承的类中生成一个指向虚基类的指针 {vbptr}
  • 会在内存中生成一个虚基类表 D::$vbtable@B@

微软的Visual Studio提供给用户显示C++对象在内存中的布局的选项
cl [filename].cpp /d1 reportSingleClassLayout[className]

一般继承:

class A
{
public:
    int dataA;
};
class B:public A
{
public:
    int dataB;
};
class C:public A
{
public:
    int dataC;
};
class D : public B, public C
{
public:
    int dataD;
};

输出:

class D size(20):
        +---
 0      | +--- (base class B)
 0      | | +--- (base class A)
 0      | | | dataA
        | | +---
 4      | | dataB
        | +---
 8      | +--- (base class C)
 8      | | +--- (base class A)
 8      | | | dataA
        | | +---
12      | | dataC
        | +---
16      | dataD
        +---

调用:

int main( )
{
    D d;
    cout << d.dataA << endl;
    return 0;
}

调用输出:

Start
prog.cc:29:15: error: non-static member 'dataA' found in multiple base-class subobjects of type 'A':
    class D -> class B -> class A
    class D -> class C -> class A
    cout << d.dataA << endl;
              ^
prog.cc:9:9: note: member found by ambiguous name lookup
    int dataA;
        ^
1 error generated.
1
Finish

虚继承:

class A
{
public:
    int dataA;
};
class B:virtual public A
{
public:
    int dataB;
};
class C:virtual public A
{
public:
    int dataC;
};
class D : public B, public C
{
public:
    int dataD;
};

B 类输出:

class B size(12):
        +---
 0      | {vbptr}
 4      | dataB
        +---
        +--- (virtual base A)
 8      | dataA
        +---

B::$vbtable@:
 0      | 0
 1      | 8 (Bd(B+0)A)
vbi:       class  offset o.vbptr  o.vbte fVtorDisp
               A       8       0       4 0

C 类输出:

class C size(12):
        +---
 0      | {vbptr}
 4      | dataC
        +---
        +--- (virtual base A)
 8      | dataA
        +---

C::$vbtable@:
 0      | 0
 1      | 8 (Cd(C+0)A)
vbi:       class  offset o.vbptr  o.vbte fVtorDisp
               A       8       0       4 0

D 类输出:

class D size(24):
        +---
 0      | +--- (base class B)
 0      | | {vbptr}
 4      | | dataB
        | +---
 8      | +--- (base class C)
 8      | | {vbptr}
12      | | dataC
        | +---
16      | dataD
        +---
        +--- (virtual base A)
20      | dataA
        +---

D::$vbtable@B@:
 0      | 0
 1      | 20 (Dd(B+0)A)

D::$vbtable@C@:
 0      | 0
 1      | 12 (Dd(C+0)A)
vbi:       class  offset o.vbptr  o.vbte fVtorDisp
               A      20       0       4 0