log*_*og0 23 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
}
Run Code Online (Sandbox Code Playgroud)
g ++ 4.5说:
error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’
Run Code Online (Sandbox Code Playgroud)
解决方案是使用dynamic_cast?但为什么.什么是理性?
- 编辑 -
下面非常好的答案.没有答案详细说明子对象和vtable最终如何订购.以下文章为gcc提供了一些很好的例子:http:
//www.phpcompiler.org/articles/virtualinheritance.html#Downcasting
Jam*_*nze 11
显而易见的答案是:因为标准是这样说的.标准中背后的动机是static_cast
应该接近于微不足道的 - 最多只是向指针添加或减去常量.对于虚拟基础的向下转换需要更复杂的代码:甚至可能在某个地方的vtable中有一个额外的条目.(它需要的不仅仅是常量,因为如果有进一步的推导,D相对的位置
A可能会改变.)转换显然是可行的,因为当你在一个虚拟函数上调用A*,并且函数被实现时D,编译器必须这样做它,但额外的开销被认为是不合适的static_cast.(据推测,static_cast在这种情况下使用的唯一原因是优化,因为dynamic_cast通常是首选的解决方案.因此static_cast,无论何时可能都是昂贵
dynamic_cast的,为什么要支持它.)
Jan*_*dec 10
因为如果对象实际上是类型E(从D派生),则A子对象相对于D子对象的位置可能与对象实际不同D.
如果你考虑从A转换为C,它实际上已经发生了.当你分配C时,它必须包含A的实例并且它存在于某个特定的偏移处.但是当你分配D时,C子对象引用了B附带的A实例,所以它的偏移是不同的.