在钻石等级中向下

Downcast in a diamond hierarchy

本文关键字:钻石      更新时间:2023-10-16

为什么static_cast不能从虚拟基地向下投射?

struct A {};
struct B : public virtual A {};
struct C : public virtual A {};
struct D : public B, public C {};
int main()
{
  D d;
  A& a = d;
  D* p = static_cast<D*>(&a); //error
}  

G++ 4.5 说:

 error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’

解决方案是使用dynamic_cast ? 但为什么。什么是理性?

--编辑--
下面很好的答案。不过,没有答案详细说明子对象和 vtables 最终是如何排序的。以下文章给出了一些关于 gcc 的好例子:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting

显而易见的答案是:因为标准是这么说的。 这标准中这背后的动机是static_cast应该接近微不足道——最多是一个简单的加法或将常量减去指针。 落魄在哪里到虚拟基地将需要更复杂的代码:也许即使在某处的 vtable 中有一个额外的条目。 (它需要的不仅仅是常量,因为位置 D相对于A如果有进一步的推导,可能会发生变化。转换显然是可行的,因为当您调用时一个A*上的虚函数,并且该函数被实现在D中,编译器必须这样做,但额外的开销是被认为不适合static_cast. (据推测,在这种情况下使用static_cast的唯一原因是优化,因为dynamic_cast通常是首选溶液。 因此,当static_cast可能与 dynamic_cast 无论如何,为什么要支持它。

因为如果对象实际上是 E 类型(派生自 D),则A子对象相对于D子对象的位置可能与对象实际D的位置不同。

如果您考虑从 A 转换为 C,它实际上已经发生了。当您分配 C 时,它必须包含 A 的实例,并且它位于某个特定的偏移量。但是当你分配 D 时,C 子对象引用了 B 附带的 A 实例,因此它的偏移量是不同的。