在钻石层次结构中向下倾斜

时间:2011-05-18 12:18:21

标签: c++ casting virtual-inheritance static-cast diamond-problem

为什么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?但为什么。什么是理性?

- 编辑 -
下面非常好的答案。没有答案详细说明子对象和vtable最终如何订购。以下文章给出了gcc的一些很好的例子:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting

2 个答案:

答案 0 :(得分:11)

显而易见的答案是:因为标准是这样说的。该 标准背后的动机是static_cast 应该接近琐碎 - 最多,一个简单的添加或 将常量减去指针。垂头丧气的地方 到虚拟基础需要更复杂的代码:也许 即使在vtable的某个地方有额外的条目。 (它 需要的东西不仅仅是常数,因为它的位置 如果有进一步的推导,相对于D的{​​{1}}可能会发生变化。) 当你打电话时,转换显然是可行的 A上的虚函数,该函数已实现 在A*中,编译器必须这样做,但额外的开销是 被认为不适合D。 (据推测, 在这种情况下使用static_cast的唯一原因是 优化,因为static_cast通常是首选 解。因此dynamic_cast可能会像static_cast一样昂贵 dynamic_cast无论如何,为什么支持它。)

答案 1 :(得分:10)

因为如果对象实际上是E类型(从D派生),A子对象相对于D子对象的位置可能与对象实际为{{ 1}}。

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