Yes they are superfluous. cast and dereference have the same precidence and are applied right to left.
I'm not sure why you are using void you could do the following, then you don't need the cast
1 2 3 4 5 6 7 8 9 10
int main()
{
int i = 99;
int* vp = &i;
cout << vp << " " << &vp << endl;
*vp = 3;
cout << i << endl;
return 0;
}
Its an exercise to demonstrate that you can't dereference a void*. It produces a compile-time error so you have to cast back to int before dereferencing. The author says that doing this introduces a hole in the language's type system because you can cast a void* to any type. So avoid void* except on rare occasions which isn't covered until much later in the volume. In other words, I have much to learn.
You can cast any type to any type. How much damage you can do, how usable that pointer is and why you need affect whether or not it is a good idea. I recently had a case where I needed to return a bool and an int from a function and a pointer to void did everything.