9

在 Raymond Chen 的一篇博文的回复中

一位提问者指出

Raymond,我认为 C++ 示例不正确,因为根据 ISO C++ 2003 标准(10-3,第 168 页)未指定派生类中基类子对象的位置,并且您假设基类子对象始终位于开始。C 示例在 C++ 中也可以,所以我会坚持使用它。

Raymond回复了

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

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

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

4

1 回答 1

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 知道要将 a 转换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

如您所见, astatic_cast是在之前尝试过reinterpret_cast的,因此在这种情况下,C 风格的演员表也会做正确的事情。


更多信息


1不保证。关于在reinterpret_cast. 我所知道的所有实现都会简单地给出相同的地址不变。

于 2012-02-04T05:56:03.770 回答