在示例中使用 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 样式转换定义为以下第一个成功的转换:
const_cast
static_cast
-
static_cast,然后是const_cast
reinterpret_cast
-
reinterpret_cast,然后是const_cast
如您所见,static_cast 在 reinterpret_cast 之前尝试,所以在这种情况下,C 风格的转换也可以做正确的事情。
More info
1不保证。对于reinterpret_cast 上发生的事情几乎没有保证。我知道的所有实现都会简单地给出相同的地址。