- Casting from a data pointer to
void *
is always guaranteed to work, and the pointer is guaranteed to survive the roundtripBase *
->void *
->Base *
(C++11 §5.2.9 ¶13); vp
is a valid pointer, so there shouldn't be any problem.a. albeit printing pointers is implementation-defined1, the printed values should be the same: in facts
operator<<
by default is overloaded only forconst void *
, so when you writecout<<&b
you are converting toconst void *
anyway, i.e. whatoperator<<
sees is in both cases&b
casted toconst void *
.b. yes, if we take the only sensible definition of "has the same value" - i.e. it compares equal with the
==
operator; in facts, if you comparevp
and&b
with==
, the result istrue
, both if you convertvp
toBase *
(due to what we said in 1), and if you convert&b
tovoid *
.Both these conclusions follow from §4.10 ¶2, where it's specified that any pointer can be converted to
void *
(modulo the usual cv-qualified stuff), and the result «points to the start of the storage location where the object [...] resides»1This is tricky; that C-style cast is equivalent to a
static_cast
, which will happily allow casting a «"pointer to cv1B
[...] to [...] "pointer to *cv2D
", whereD
is a class derived fromB
» (§5.2.9, ¶11; there are some additional constraints, but they are satisfied here); but:If the prvalue of type “pointer to cv1
B
” points to aB
that is actually a subobject of an object of typeD
, the resulting pointer points to the enclosing object of typeD
. Otherwise, the result of the cast is undefined.(emphasis added)
So, here your cast is allowed, but the result is undefined...
... which leads us to printing its value; since the result of the cast is undefined, you may get anything. Since pointers are probably allowed to have trap representations (at least in C99, I could find only sparse references to "traps" in the C++11 standard, but I think that probably this behavior should already be inherited from C89) you may even get a crash just by reading this pointer to print it via
operator<<
.
If follows that also 6, 8 and 9 aren't meaningful, because you are using an undefined result.
Also, even if the cast was valid, strict aliasing (§3.10, ¶10) would block you to do anything meaningful with the pointed objects, since aliasing a Base
object via a Derived
pointer is only allowed when the dynamic type of the Base
object is actually Derived
; anything that deviates from the exceptions specified at §3.10 ¶10 results in undefined behavior.
Notes:
operator>>
delegates tonum_put
which conceptually delegates toprintf
with%p
, whose description boils down to "implementation defined".This rules out my fear that an evil implementation could in theory return different but equivalent values when casting to
void *
.