void* pn = static_cast<void*>(&n);
is an implicit conversion; you can also write
void *pn = &n;
It means that pn
stores a pointer to some object type; the programmer is responsible for knowing what that object type is. To cast back you need a static_cast
:
int *pi = static_cast<int*>(pn);
Note that using static_cast
to cast to any type significantly different than the original (float
is significantly different, const int
isn't) is a way of doing a reinterpretation. You should spell that reinterpret_cast
not implicit conversion (or static_cast
) followed by static_cast
.
This is the whole purpose of void*
, an concept tracing back to C, where casts are spelled with C-style casts obviously (not static_cast
...) but have otherwise identical meanings.
Going back to the syntax of declarations in C and C++:
The declaration of a pointer to int
is int (*pi);
(parentheses are useless but help illustrate the point), you can read it like: I declare that expression (*pi)
has type int
. You can read a function declaration that way: in int f(int i);
I declare that if i
has type int
then f(i)
has type int
.
The declaration void (*pi);
looks like a pointer to a void
but there is no such thing as an object of type void
, the expression *pi
isn't even well formed, it doesn't make sense. It's a special case in the type system: the syntax says "pointer to void", semantic says "pointer to something".
In C and C++, a pointer object is a first class object and you can take its address and have a pointer to a pointer, etc. (Contrast with Java where references like other fundamental types aren't class objects.)
So you can have a int**
, int***
... pointers to (pointers ... to int
); you can have for the same reason void**
: declared like a pointer to (pointer to void), semantically a pointer to (pointer to something).
Just like a pointer to int
can't be assigned to a pointer to float
without a cast:
float *f = &i; // ill-formed
because of the type mismatch, a type different from void**
can't be assigned to a void**
: the result of dereferencing a void**
must be a void*
object.