23

为什么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

4

2 回答 2

11

显而易见的答案是:因为标准是这样说的。标准中这背后的动机是static_cast 应该接近于微不足道的——至多是对指针的常量的简单加法或减法。where s downcast to a virtual base 将需要更复杂的代码:甚至可能在 vtable 的某处有一个额外的条目。(它需要的不仅仅是常量,因为如果有进一步的推导, D相对于的位置A可能会改变。)转换显然是可行的,因为当你在 an 上调用虚函数A*并且函数在 中实现时D,编译器必须这样做它,但额外的开销被认为不适合static_cast. (据推测,在这种情况下使用的唯一原因static_cast是优化,因为dynamic_cast通常是首选解决方案。所以什么时候static_cast可能会像 dynamic_cast反正一样贵,为什么要支持它。)

于 2011-05-18T12:42:50.387 回答
10

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

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

于 2011-05-18T12:22:51.033 回答