第一:没有虚函数,很可能在类中根本没有 vptr
。您看到的8个字节是虚拟继承实施方式的工件 。
层次结构中的几个类通常可能共享相同的 vptr
。发生这种情况时, 最终等级中的偏移量必须相同,并且 基类中的vtable条目列表必须是 派生类中vtable条目的列表的初始顺序。
这两个条件在几乎所有的实现中都能满足单一的 继承。无论遗产多么深,通常都会有 只有一个vptr
,在所有的类之间共享。
在多重继承的情况下,总会有至少一个 类这些要求得不到满足,因为这两个基地 类不能有一个共同的起始地址,并且除非他们有确切 相同的虚拟功能,只有一个的虚拟表可能是另一个的初始序列 。
虚拟继承增加了另一个怪癖,因为 虚拟基地相对于从其继承的类的位置将根据层次结构的其余部分而变化 。我见过的大多数实现 都使用了一个单独的指针,尽管应该可以将 这个信息放在vtable中。
如果我们把你的层次结构,增加虚拟功能,使我们 一定有vptr
,我们注意到B
和D
仍然可以共享一个 vtable
,但两者A
和C
需要单独vtables
。这意味着,如果您的课程具有虚拟功能,您至少需要三个 vptr
。 (从这个我认为你的实现是使用 单独的指针指向虚拟基地。随着B
和D
共享 相同的指针,并C
有自己的指针。当然,A
不 有一个虚拟基地,不需要指向自己的指针)
如果你想分析到底发生了什么,我建议在每个类中添加一个新的虚拟函数,并添加一个指针大小为 的整型类型你最初为每个 类别使用不同的已知值。 (使用构造函数设置值。)然后创建一个类的实例,取其地址,然后输出每个基类的地址为 类。然后转储该类:已知的固定值将帮助在 中识别不同元素所在的位置。喜欢的东西:
struct VB
{
int vb;
VB() : vb(1) {}
virtual ~VB() {}
virtual void fvb() {}
};
struct Left : virtual VB
{
int left;
Left() : left(2) {}
virtual ~Left() {}
virtual void fvb() {}
virtual void fleft() {}
};
struct Right : virtual VB
{
int right;
Right() : right(3) {}
virtual ~Right() {}
virtual void fvb() {}
virtual void fright() {}
};
struct Derived : Left, Right
{
int derived;
Derived() : derived(5) {}
virtual ~Derived() {}
virtual void fvb() {}
virtual void fleft() {}
virtual void fright() {}
virtual void fderived() {}
};
您可能要添加一个Derived2
,从Derived
派生看看 发生了什么例如之间的相对地址Left
和VB
取决于对象是否具有类型Derived
或Derived2
。
你需要说明你的编译器和体系结构。 – 2012-03-16 13:25:28
标准中没有任何内容谈论虚拟指针,它们确实存在。所以大小是8,因为编译器需要它是8.它是一个实现细节,没有什么值得推测的,因为它可能在另一个编译器上不同。 – 2012-03-16 14:11:54