计算虚继承中对象占用的空间

请写出sizeof的运算结果

程序1

class Base{
   void f(){}   
};

class Derived1:public Base{
  void f1(){}
};

class Derived2:public virtual Base{
  void f2(){}
};

sizeof(Base);
sizeof(Derived1);
sizeof(Derived2); 

答案:1, 1, 4

问题分析:

Base类没有任何数据成员,但是Base类的对象占用的空间却不是0,由于对象存储在内存中,不占用空间的对象在内存中无法标识,因此Base类的对象在内存中会有一个占位符,占用空间为1个字节。

Derived1类继承Base类,没有任何数据成员,因此Derived1类的对象也只有一个占位符,占用空间为1个字节。

Derived2类虚继承Base类,没有任何数据成员,但是由于虚继承的关系,Derived2类的对象中会有一个指向虚基类Base的指针,指针占用的空间为4个字节,因此Derived2类的对象占用空间为4个字节。

程序2

class Base{
  virtual void f(){}
};

class Derived1:public Base{
  virtual void f1(){}
};

class Derived2:public Base{
  virtual void f2(){}
};

class Derived3:public virtual Base{
  virtual void f3(){}
};

sizeof(Base);
sizeof(Derived1);
sizeof(Derived2);
sizeof(Derived3);

答案:4, 4, 4, 8(GCC)或12(VC)

问题分析:

Base 类中没有任何数据成员,但是由于Base类中有虚函数,Base类的对象中会有一个指向虚函数表的指针,因此Base类的对象占用空间为4个字节。

Derived1类继承Base类,没有任何数据成员,但是Derived1类继承了Base类中的虚函数,使得Derived1类的对象中也含有一个指向虚函数表的指针,因此Derived1类的对象占用空间为4个字节。

Derived2类继承Base类,没有任何数据成员,但是Derived2类不但继承了Base类的虚函数,还有自己的虚函数,这两个虚函数关联同一个虚函数表,因此Derived2类的对象中只有一个指向虚函数表的指针,占用4个字节。

Derived3类虚继承Base类,这个情况比较复杂,不同编译器的实现不同。这里只分析一下主流的VC编译器和GCC编译器。

对于VC编译器来说,虚继承中父类和子类不共享指向虚函数表的指针,因此Derived3类的对象中有三个指针:指向Base类虚函数表的指针,指向Derived3类虚函数表的指针,指向虚基类Base的指针,总共占用空间为12个字节。

对于GCC编译器来说,无论普通继承还是虚继承,任何对象只有一个指向虚函数表的指针,因此Derived3类的对象中有两个指针:指向虚函数表的指针,指向虚基类Base的指针,总共占用空间为8个字节。