为什么在这里使用static_cast而不是reinterpret_cast很重要? [英] Why is it important to use static_cast instead of reinterpret_cast here?
问题描述
一位提问者指出
我相信C ++示例是不正确的,因为根据ISO C ++ 2003标准(10-3,第168页),派生类中的基类子对象的位置
是未指定的
,并且假设
基类的子对象总是在开始。 C
的例子在C ++中也很好,所以我坚持下去。
Raymond回应了
不做这个假设。这就是为什么重要的是
使用static_cast而不是reinterpret_cast。尝试它:添加一个虚拟
方法到OVERLAPPED(所以一个vtable在前面),并观察
编译器。 -Raymond]
我读过他的评论后可以猜到。使用static_cast在这个例子很好,但reinterpret_cast不是。因为reinterpret_cast不是转换vtable。我理解它是否正确?
虽然,如果我在那里使用C风格的演员(不reinterpret_cast),它也可能会出错?
我重读了更有效的C ++的演员解释,以了解。但是没有回答。
使用static_cast在这个例子中,但reinterpret_cast不。因为reinterpret_cast不是转换vtable。
不,问题是 reinterpret_cast
完全忽视了继承。它将简单地返回相同的地址不变 1 。但是 static_cast
知道您正在执行向下转换:即从基础类转换为派生类。
让我们假装我们的实现提出了假设的 OVERLAPPEDEX
具有如下虚拟函数的类:
+ --- + ------------ + ------------------ + ------------- +
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+ ------ + ------------ + ------------------ + ------ ------- +
^
|
ptr
我们给出的指针指向 OVERLAPPED
子对象。 reinterpret_cast
不会改变。它只会改变类型。显然,通过这个地址访问 OVERLAPPEDEX
类容易造成严重破坏,因为它的子对象的位置现在都错了!
我们相信当我们通过指针访问OVERLAPPEDEX时我们有什么
+ ------ + ------------ + - ----------------- + ------------- +
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+ ------ + ------ + ----- + ------ + ----------- + ------ + ------ + ------ +
| vptr | OVERLAPPED | AssociatedClient | ClientState | < - 我们实际有什么
+ ------ + ------------ + ------------------ + ------------- +
^
|
ptr
static_cast
知道将 OVERLAPPED *
转换为 OVERLAPPEDEX *
时必须调整地址,正确的事情:
+ ------ + ------------ + - ---------------- + ------------- +
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+ ------ + ------------ + ------------------ + ------ ------- +
^
|
ptr after static_cast
但是,如果我在那里使用C-Style转换(不是reinterpret_cast),它也可能会出错?
C风格的转换被定义为以下的第一个成功:
-
const_cast
-
static_cast
-
static_cast $ c $ c>
b
reinterpret_cast
,const_cast
可以看到,在 reinterpret_cast
之前尝试了 static_cast
,因此在这种情况下,一个C风格的演员也会做正确的事。
>不保证。对于
reinterpret_cast
上发生的事情几乎没有保证。我知道的所有实现将简单地给出相同的地址不变。 At a reply of a blog post of Raymond Chen,
A questioner pointed out
Raymond, I believe the C++ example is not correct since the position of the base class subobject in the derived class is unspecified according to ISO C++ 2003 Standard (10-3, page 168), and you assume that the base class subobject is always at the beginning. The C example would be fine in C++ too, so I'd stick with it.
Raymond replied
[The code does not make this assumption. That's why it's important to use static_cast instead of reinterpret_cast. Try it: Add a virtual method to OVERLAPPED (so a vtable goes in front) and observe what the compiler does. -Raymond]
I could guess after read his comments. Using static_cast is fine at the example but reinterpret_cast is not. Because reinterpret_cast is not convert vtable. Do I understand it rightly?
Though, if I use C-Style cast at there(not reinterpret_cast), could it also go wrong?
I re-read More Effective C++'s cast explanation to understand that. But there was no answer about that.
Using static_cast is fine at the example but reinterpret_cast is not. Because reinterpret_cast is not convert vtable.
No, the problem is that the reinterpret_cast
is completely oblivious about the inheritance. It will simply return the same address unchanged1. But static_cast
knows that you're performing a downcast: i.e. casting from a base class to a derived class. Since it knows both types involved it adjusts the address accordingly, i.e., does the right thing.
Let's pretend our implementation lays out the hypothetical OVERLAPPEDEX
class that has a virtual function like this:
+------+------------+------------------+-------------+
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------------+------------------+-------------+
^
|
ptr
The pointer we're given points to the OVERLAPPED
subobject. reinterpret_cast
would not change that. It would only change the type. Obviously, accessing the OVERLAPPEDEX
class through this address would easily wreak havoc, because the locations of its subobjects are all wrong now!
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
knows that to convert a OVERLAPPED*
to OVERLAPPEDEX*
it must adjust the address, and does the right thing:
+------+------------+------------------+-------------+
| vptr | OVERLAPPED | AssociatedClient | ClientState |
+------+------------+------------------+-------------+
^
|
ptr after static_cast
Though, if I use C-Style cast at there(not reinterpret_cast), could it also go wrong?
A C-style cast is defined as the first one of the following that succeeds:
const_cast
static_cast
static_cast
, thenconst_cast
reinterpret_cast
reinterpret_cast
, thenconst_cast
As you can see, a static_cast
is tried before reinterpret_cast
, so in this case, a C-style cast would also do the right thing.
1Not guaranteed. There are very little guarantees about what happens on a reinterpret_cast
. All implementations I know of will simply give out the same address unchanged.
这篇关于为什么在这里使用static_cast而不是reinterpret_cast很重要?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!