Search code examples
c++c++14void-pointersstatic-cast

Does void* reserve inheritance information?


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.

Question

Why it work? Does void* really remember the type?
How far can it "remember"?

Background

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*.


Solution

  • 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.