为什么在这里使用static_cast而不是reinterpret_cast很重要?

时间:2012-02-04 05:48:11

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

At a reply of a blog post of Raymond Chen

提问者指出

  雷蒙德,我相信自从这个位置以来C ++的例子是不正确的   未指定派生类中的基类子对象   根据ISO C ++ 2003标准(10-3,第168页),您可以假设   基类子对象始终在开头。 C   例子在C ++中也没问题,所以我坚持下去。

雷蒙德回答说

  

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

读完他的评论后我猜错了。在示例中使用static_cast很好,但是reinterpret_cast不是。因为reinterpret_cast不能转换为vtable。我理解得对吗? 但是,如果我在那里使用C-Style演员(不是reinterpret_cast),它也会出错吗?

我重新阅读了更有效的C ++演员解释,以了解这一点。但是没有答案。

1 个答案:

答案 0 :(得分:17)

  

在示例中使用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演员(不是reinterpret_cast),它也会出错吗?

C样式演员被定义为以下第一个成功:

  1. const_cast
  2. static_cast
  3. static_cast,然后是const_cast
  4. reinterpret_cast
  5. reinterpret_cast,然后是const_cast
  6. 正如您所看到的,在static_cast之前尝试reinterpret_cast,所以在这种情况下,C风格的演员也会做正确的事。


    More info


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