C ++无法通过虚拟基数A从基数A转换为派生类型B

问题描述 投票:51回答:7

我有三堂课:

class A {};

class B : virtual public A {};
class C : virtual public A {};

class D: public B, public C {};

尝试从A *到B *的静态转换时出现以下错误:

cannot convert from base A to derived type B via virtual base A
c++ casting downcast virtual-inheritance static-cast
7个回答
90
投票

为了了解转换系统,您需要深入研究对象模型。

简单分层模型的经典表示是包含:如果B源自A,则B对象实际上将在其自己的属性旁边包含一个A子对象。

对于这种模型,向下转换是通过编译时已知的偏移量进行的简单指针操作,该偏移量取决于B的内存布局。

这是static_cast的作用:将静态类型转换称为静态类型,因为对于类型转换所需的计算是在编译时完成的,无论是指针算术还是转换(*)。

但是,当virtual继承开始时,事情就会变得更加困难。主要问题是,在继承virtual的情况下,所有子类都共享该子对象的相同实例。为此,B将具有指向A的指针,而不是A适当的指针,并且A基类对象将在B之外实例化。

因此,在编译时无法推断出必要的指针算法:这取决于对象的运行时类型。

[只要有运行时类型依赖项,就需要RTTI(运行时类型信息),并且使用RTTI进行强制转换是dynamic_cast

的工作。

摘要:

  • 编译时向下转换:static_cast
  • 运行时下注:dynamic_cast
  • [另外两个也是编译时强制转换,但是它们是如此具体,以至于很容易记住它们的用途...而且它们很臭,因此最好不要使用它们。

(*)正如@curiousguy在评论中指出的那样,这仅适用于向下转换。 static_cast允许上载,而不考虑虚拟继承或简单继承,尽管这样也不必进行强制转换。


12
投票

据我所知,您需要使用dynamic_cast,因为继承是virtual,您正在向下转换。


6
投票

在这种情况下,您不能使用static_cast,因为编译器在编译时不知道B相对于A的偏移量。必须在运行时根据最派生对象的确切类型来计算偏移量。因此,您必须使用dynamic_cast


4
投票

是,您必须使用dynamic_cast,但是必须使基类A具有多态性,例如通过添加虚拟dtor。


4
投票

根据标准文档,


1
投票

$ 5.2.9 / 2-“表达式e可以是使用显式转换为类型T形式的static_caststatic_cast(e)如果声明对于某些人来说,“ T t(e);”的格式正确发明了临时变量t(8.5)。“


1
投票

我不知道这是否“安全”,但是。

© www.soinside.com 2019 - 2024. All rights reserved.