Is it possible that void*
keep type-information?
I tried to make it forget the real types (B*
) by cast B* b
to void* v
, but it seems to know its origin.
It is good-luck for me, but I don't know why.
Here is a simplified code (full demo) :-
#include <iostream>
#include <memory>
using namespace std;
class B{public: int ib=1;};
class C:public B{public: int ic=2;};
int main() {
B* b=new C();
void* v=b; //<- now you forget it!
C* c=static_cast<C*>(v);
std::cout<<c->ib<<" "<<c->ic<<std::endl; //print 1 and 2 correct (it should not)
return 0;
}
I expected c
to point to the address of B*
(a wrong address), but it seems to know that v
is B*
and correctly cast.
Why it work? Does void*
really remember the type?
How far can it "remember"?
I am trying to create an void*
abstract class here, but surprised that it works.
I want to make sure that it is an expected standard behavior.
Edit: Sorry for the newbie question.
Now, I realize that I misunderstand about void*
.
Undefined behavior is undefined. That means you might, just might, get the "right answer" anyway.
In this particular case, it is entirely possible that your compiler's layout organizes C
such that C
and its base class B
have the same address. Therefore, if you pretend one is a pointer to the other in an undefined way, you get correct behavior.
Today. What happens tomorrow is a matter of speculation.
This is not something you can rely on. It's just a "fortunate" happenstance.
It's a pointer to C, then a pointer to B, then a pointer to void, then a pointer to C again. All perfectly legal conversions.
No, they're not.
It's a pointer to C
, then a pointer to B
. Then it becomes a void*
. But the standard is quite clear: if you convert a pointer to a void*
, the only legal conversion is one that converts it to a pointer to the exact type that was cast from. So if you convert from B*
to void*
, the only legal conversion is back to B*
.
Not to a type derived from B
.
C++17 makes "the exact type" into "a pointer interconvertible type". But base and derived classes are not pointer-interconvertible, so it's still UB.