c ++中虚拟继承的对象布局

时间:2015-03-23 13:58:38

标签: c++ object inheritance layout virtual

  • c ++中虚拟继承的对象布局?
  • 如何解释     结果如下?

环境是vs 2008

  #include <iostream>
  using namespace std;

    class A {
    public:
    virtual ~A();
    virtual void foo();
    };
    class B : public virtual A {
    public:
    virtual ~B();
    virtual void foo();
    };

    class C : public virtual A {
    public:
    virtual ~C();
    virtual void foo();
    virtual void foobar();
    };
    class D : public B, public C {
    public:
    virtual ~D();
    virtual void foo();
    virtual void foobar();
    };
    int main()
    {
    cout<<"size of A "<<sizeof(A)<<endl;
    cout<<"size of B "<<sizeof(B)<<endl;
    cout<<"size of D "<<sizeof(D)<<endl;
    cout<<"size of C "<<sizeof(C)<<endl;
    }

结果是:

size of A 4
size of B 12
size of D 20
size of C 16

1 个答案:

答案 0 :(得分:0)

标准中只定义了很少的关于对象内存布局的内容,如this SO question中所示。大多数布局都是实现定义的。在您参考MSVC实现时,为了好奇,让我们看一下这些(非便携式)实现细节。

简单继承:

我建议你从没有虚函数的简单非虚拟继承开始:

class X {  };                     //    size of X 1 
class Y : public X { };           //    size of Y 1 

所有对象必须具有非空大小(仍然是标准的)。这就是为什么我们看到1尽管X完全是空的。注意Y与X具有相同的大小,因为Y中没有添加任何内容(因此Y已经具有非空大小)。

简单继承,虚函数:

当您开始使用虚拟功能时,MSVC会在对象的开头添加指向vtable的指针。 This SO question在简单继承的情况下显示vtable的原理。

class XF                              // size of XF 4
{ public: virtual void foo(){} };
class YF : public XF                  // size of YF 4
{ public: virtual void bar(){} };
class YX : public X                   // size of YX 4
{ public: virtual void bar(){} };       

你在这里看到vtable指针大小为4.你可以立即扣除我在32位模式下编译,因为在x64模式下你有8个。

顺便说一句,出于多态的目的,合并了单个继承类的vtable(在派生对象的开头只有一个vtable指针)。有关vtable的更多信息,请在 this very interesting DDJ article 中注明多重继承。

没有虚拟继承的多重继承:

多重继承组合了所有继承的类,因此它的大小至少与添加继承类的大小一样大。

但是由于对象要求它可能更大,并且在虚函数的情况下,还有一个额外的vtable指针(在单继承中不再可能合并)。这也在DDJ文章中有所解释。

虚拟继承:

让我们看看虚拟继承的效果(与虚函数无关):

class ZX : public virtual X {   };     // size of ZX 4     
class ZF : public virtual XF {   };    // size of ZF 8 
class ZZF: public virtual ZF {   };    // size of ZZF 12

因此,我们看到无论何时进行虚拟继承,都会添加一个指针。这是什么目的?

没有虚拟的不间断,从派生对象向其基础的向上转换是直截了当的。

但是对于虚拟继承,这种向上转换是一场噩梦,因为几个类共享相同的基类。因此基类可能不再与派生类相邻。这就是虚拟继承需要指向虚拟基表的原因的原因。对于每个虚拟继承。