关于C++虚拟继承的问题

9
以下代码摘自《深度探索C++对象模型》一书。
#include <iostream>  
using namespace std;
class X{};
class Y: public virtual X{};
class Z: public virtual X{};
class A: public Y, public Z{};

int main()
{
     cout<<sizeof(X)<<" "<<sizeof(Y)<<" "<<sizeof(Z)<<" "<<sizeof(A)<<endl;
     return 0;
}

在我的电脑上(Windows,VS2010),输出结果为:
1 4 4 8
以下是我的问题:
1、sizeof(X)=1
书中说当X类型生成两个实例xa和xb时,编译器会在A中插入一个字节,以便xa和xb可以具有不同的地址。我不太理解原因。
2、sizeof(Y)=4
通过使用虚拟继承,我们会有一个额外的虚拟指针吗?我猜这可能不同于多态性中的虚拟指针。有人能给出Y的内存布局吗?
谢谢!

每个问题请只提出一个问题: - Lightness Races in Orbit
请翻译以下与编程有关的内容,从英文到中文。只返回翻译后的文本:对于第一个问题,请查看:http://stackoverflow.com/questions/621616/c-what-is-the-size-of-an-object-of-an-empty-class?rq=1 - mots_g
1
我认为你的主要问题是,因为Y使用虚拟继承从非多态类X派生而来,而Y本身也是非多态的,那么虚拟继承本身会导致Y有一个虚函数表,从而使其大小为4吗? - CashCow
4个回答

6
  1. 当类为空时,编译器会创建一个新的字符,以便生成不同的对象。
  2. 由于使用了虚继承,因此sizeof(Y)=4,构造函数将生成vptr表,在32位系统上占用4个字节。
  3. 如果您使用的是Visual Studio,请在属性->C/C++/命令中使用/d1reportAllClassLayout来生成对象布局。在Visual Studio上,class Y对象布局如下:
  4. Stanley B. Lippman的书《Inside C++ object model》对此进行了非常好的解释。

 
        class Y size(4):
            +---
            0     | {vbptr}
            +---
            +--- (virtual base X)
            +---<br>
      Y::$vbtable@:
       0    | 0
       1    | 4 (Yd(Y+0)X)    


1

一个空类的sizeof始终返回1。这是一个空类的单个虚拟字节。

A在虚拟表中有两个条目,一个是Y,另一个是Z。

因此,两个指针的sizeof为8。

Y和Z都有一个X的虚拟表条目,因此大小为4。


我在这里看不到名为B和C的类。 - CashCow

1
一个A对象将包含一个Y对象,一个Z对象(按这个顺序),以及仅有的一个X对象(由Y和Z中的指针引用),因为Y和Z都是虚拟继承自X,这就意味着当多重继承发挥作用时,只会在子类中实例化一个X对象。A仍然有两个对象(一个Y,一个Z),因此它的sizeof = 8(因为它们的sizeof都为4)。但是Y和Z中对X对象的指针将指向相同的地址。

继承树将如下所示:

  X
 / \
 Y Z
 \ /
  A

0

类必须至少为1字节的原因是,假设我们有一个X的数组。如果它们为0字节,则&array [1]将具有与&array [3]相同的地址,这将令人意外地破坏代码,如果您不得不编写代码来检查它,并且通常没有任何意义。

Y将简单地是

static void* virtual_ptr1 //note this is in virtual table and cannot be edited  

你可以将vtable(指向类和虚函数的虚拟指针)视为静态变量,不能手动/编码编辑(或者至少不应该这样做)。把它看作编译器保留的静态变量。

1
我喜欢这个解释,因为sizeof(X)=1的原因。 - Junjie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接