【问题标题】:Why is it important to use static_cast instead of reinterpret_cast here?为什么在这里使用 static_cast 而不是 reinterpret_cast 很重要?
【发布时间】:2012-02-26 15:58:51
【问题描述】:

At a reply of a blog post of Raymond Chen,

提问者指出

Raymond,我认为 C++ 示例不正确,因为位置 派生类中的基类子对象的未指定 根据 ISO C++ 2003 标准(10-3,第 168 页),您假设 基类子对象总是在开头。 C 这个例子在 C++ 中也可以,所以我会坚持下去。

雷蒙德回复

[代码没有做这个假设。这就是为什么重要的是 使用 static_cast 而不是 reinterpret_cast。试试看:添加虚拟 方法重叠(所以一个 vtable 放在前面)并观察什么 编译器会。 -雷蒙德]

看过他的cmets后我就猜到了。在示例中使用 static_cast 很好,但 reinterpret_cast 不是。因为 reinterpret_cast 不是转换 vtable。我理解的对吗?
不过,如果我在那里使用 C-Style cast(不是 reinterpret_cast),它也会出错吗?

我重新阅读了更有效的 C++ 的演员解释来理解这一点。但没有任何答案。

【问题讨论】:

  • 我完全不精通 C++,但我的理解是“重新解释强制转换”的含义正是 *(destination_type *)& 在 C 中的含义。大概“静态强制转换”实际上考虑了类关系并允许编译器进行重要的转换工作。

标签: c++ pointers casting reinterpret-cast static-cast


【解决方案1】:

在示例中使用 static_cast 很好,但 reinterpret_cast 不是。因为 reinterpret_cast 不是转换 vtable。

不,问题在于reinterpret_cast 完全没有注意到继承。它只会返回相同的地址不变1。但是static_cast 知道您正在执行向下转换:即从基类转换为派生类。由于它知道涉及的两种类型,因此它会相应地调整地址,即做正确的事情。

让我们假装我们的实现展示了假设的OVERLAPPEDEX 类,它具有这样的虚函数:

+------+------------+------------------+-------------+
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------------+------------------+-------------+
       ^
       |
      ptr

我们得到的指针指向OVERLAPPED 子对象。 reinterpret_cast 不会改变这一点。它只会改变类型。显然,通过这个地址访问OVERLAPPEDEX类很容易造成破坏,因为它的子对象的位置现在都错了!

       what we believe we have when we access OVERLAPPEDEX through the pointer
       +------+------------+------------------+-------------+
       | vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------+-----+------+-----------+------+------+------+
| vptr | OVERLAPPED | AssociatedClient | ClientState | <- what we actually have
+------+------------+------------------+-------------+
       ^
       |
      ptr

static_cast 知道要将OVERLAPPED* 转换为OVERLAPPEDEX*,它必须调整地址,并且做正确的事:

 +------+------------+------------------+-------------+
 | vptr | OVERLAPPED | AssociatedClient | ClientState |
 +------+------------+------------------+-------------+
 ^
 |
ptr after static_cast

不过,如果我在那里使用 C-Style cast(不是 reinterpret_cast),它也会出错吗?

C 样式转换定义为以下第一个成功的转换:

  1. const_cast
  2. static_cast
  3. static_cast,然后是const_cast
  4. reinterpret_cast
  5. reinterpret_cast,然后是const_cast

如您所见,static_cast 在 reinterpret_cast 之前尝试,所以在这种情况下,C 风格的转换也可以做正确的事情。


More info


1不保证。对于reinterpret_cast 上发生的事情几乎没有保证。我知道的所有实现都会简单地给出相同的地址。

【讨论】:

  • 是的,我的convert vtable 是一个非常奇怪的句子。顺便说一句,C风格的施法者也知道继承关系吗?也许不是。但我一直使用 C 风格的演员表,即使我使用 C++。而且我认为它甚至在示例中也很有效。这很奇怪。
  • @Benjamin 我添加了关于 C 风格转换的解释,以及为什么它在这种情况下有效。不过,我建议不要使用它们,因为并不总是很清楚选择了哪些替代方案。 C 型表壳是一把非常钝的锤子。
  • 我当然会听从你的建议,因为我现在明白了。谢谢你。但是,您的 C 型脚轮的顺序是否标准化?
  • @Benjamin 是的,该顺序由标准指定。
  • 还要注意 C 风格转换的一个可能的陷阱:如果编译器无法确定存在继承结构(例如缺少头文件包含),它将回退到 reinterpret_cast,失败以同样的方式。这是 C-cast 危险的另一个原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 2021-11-10
  • 2013-10-14
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
  • 2017-12-31
相关资源
最近更新 更多