问题 为什么我要使用dynamic_cast来转换为void *?


所以我正在阅读答案 来自“void *”的dynamic_cast 虽然你不能从一个演员 void * 到了 T * 一些回应指出有可能施展一个 T * 到了 void *,但不要给出任何指示 为什么 你想要那样做。

这只是一个琐事,它是可能的,还是有一个合理的案例?我想到可能是为了可读性或者说清楚我们正在转换为 void *但是考虑到了目的 dynamic_cast,它不适合我。

就此而言,除了让我们做任何其他事情是否有任何理由 T * 成为 void * 含蓄?我见过C风格的演员阵容 void * 为了这个目的不时使用,我认为只是明确(假设我们没有像铸造那样做一些不寻常的事情 int 指针或某事)。


5830
2018-02-28 01:52


起源

据我所知,如果源类型是多态的,使用dynamic_cast <void *>()并使用隐式转换为void *的结果总是返回相同的结果。我想你可以像使用static_assert(is_polymophic(x))一样使用它,但我真的不能想到这样做的好理由。 - Vaughn Cato


答案:


首先,使用时 dynamic_cast<void*>(x) 你得到一个指向第一个字节的指针 最衍生的 目的。只要静态类型 x 是多态的。

这在少数场景中很有用,其中地址用作对象标识:

  • 现在,您可以完全区分指向同一对象的子对象的指针,从指向不相关的子对象的指针。
  • 你现在可以走一些扭曲的图形而不需要多次访问同一个对象......这可以用来 系列化

当然,这当然不是一个 日常使用但是在C ++中,内存地址是对象的事实上的标识符,因此从继承层次结构的任何部分访问它的机制当然对那些少数边缘情况很有用。


9
2018-02-28 07:43



那么,如果我使用基类指针并将其强制转换为派生类,实际的地址值可能会有所不同?对不起,如果这是一个愚蠢的问题,我只是让它在大多数情况下对我来说是神奇的;)。 - FatalError
@FatalError :(注意:实用讨论)在单继承的情况下,基类是多态的,地址实际上应该是相同的。但是,只要您开始考虑多重继承,或者如果基类不是多态的,但派生类是,则地址可能会有所不同。您可以将基类视为第一个(隐藏)属性 - >它们首先出现在构造函数的初始化列表中;因此,当有多个类时,第二个基数的开始和当前导出的不再重合(baring例外)。 - Matthieu M.
我试了一下你是完全正确的,当我尝试使用多重继承时,我发现地址通过动态强制转换而不是静态强制转换或C样式强制转换。谢谢! - FatalError
请注意,这也有助于调用您可能没有派生足够指针的对象的(虚拟)成员函数(在多重继承的情况下尤其有用)。 - rubenvb
@rubenvb:对不起,请不要在这里关注你...你如何调用(虚拟或非虚拟)成员函数 void*?你表演了吗? reinterpret_cast 跟随 dynamic_cast? - Matthieu M.


有一个目的,有点。它在规范中允许它的部分暗示。从N3337,第5.2.7节,第7段:

如果T是“指向cv void的指针”,则结果是指向v指向的最派生对象的指针。

那么一个 dynamic_cast<void*>(...) 真的是简写 static_cast<void*>(dynamic_cast<MostDerivedType*>(...))。那将是有用的......有点儿。

使它有用的困难在于你不一定知道什么 MostDerivedType 是。毕竟,每个表达式可能不同。所以一旦你拥有它 void*,你不一定有办法把它丢回来 安然。如果你猜一下 MostDerivedType 只是 static_cast 它,你 错误那么你在未定义的行为领域。而如果你做了 dynamic_cast 那种类型(然后 static_cast 至 void*),如果它不是那种类型,它至少会返回NULL。

所以不,我会说这不是很有用。如果您希望生活在C ++的边界内并且不依赖于潜在的未定义行为,那就不是了。


5
2018-02-28 02:05



如果你有两个对象指针,你不一定知道它们是否指向同一个对象 - 通过多重继承,它们可以指向同一个对象的不同子对象。要查看它们是否属于同一个对象,请将它们都转换为 void*,并比较结果。 Windows COM有类似的规则: QueryInterface 对于 IUnknown,无论你开始使用哪个对象的接口,你都会得到相同对象的相同结果。 - Rob Kennedy
这并不能解释原因 dynamic_cast 需要这样做。 static_cast 已经说过以同样的方式工作了。 - Nicol Bolas
@NicolBolas: static_cast 不适用于虚拟继承。 - Matthieu M.
@MatthieuM。:不符合第4.10节第2段。 A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The result of converting a “pointer to cv T” to a “pointer to cv void” points to the start of the storage location where the object of type T resides, as if the object is a most derived object (1.8) of type T (that is, not a base class subobject). 请注意,这与用于的语言完全相同 dynamic_cast。 - Nicol Bolas
@NicolBolas:这是简单的转换, static_cast 更有限。见5.2.9 [expr.static.cast](n3337)。 static_cast 特别限制(指针)转换需要固定偏移(因此名称, static,表示在编译时计算偏移量。例如 static_cast<D&>(b) 如果允许的话 B既不是D的虚基类,也不是D的虚基类的基类。 - Matthieu M.