reinterpret cast and its affect on virtual functions

C

Christopher

If I have an abstract class A, and class B derives from A,
implementing A's pure virtual methods. What is supposed to happen when
somewhere in the code I reinterpret_cast a void * to a A *, then call
one of the pure virtual methods?

It seems to be aborting in my case. I want it to call the method
implemented in class B. Am I doomed to fail at that endevour?

I have don't think I have a choice but to reinterpret cast, because MS
loves passing around void pointers.
 
S

SG

If I have an abstract class A, and class B derives from A,
implementing A's pure virtual methods. What is supposed to happen when
somewhere in the code I reinterpret_cast a void * to a A *, then call
one of the pure virtual methods?

Of course such casting should be avoided if possible. A
reinterpret_cast is the last (worst) resort, really. Here your
programm will still be syntactically correct if you use a static_cast.

However, the standard only guarantees that

T* pointer;
static_cast<T*>(static_cast<void*>(pointer)) == pointer

In your case you probably have a situation like this:

B b; // 'b' is an A (public inheritance)
A pa1 = &b;
A pa2 = static_cast<A*>(static_cast<void*>(&b));

The question is: Is pa1==pa2 guaranteed?

I'm not 100% sure but I would say NO. The type "void*" simply doesn't
have enough information so the compiler can correctly adjust the
pointers if it has to.

B could be declared like this:

class B : public X, public A {...};

A compiler might lay out B im memory so that all members of X are at
the beginning and all members of A are at the end. A pointer to B is
likely to point to the beginning B (to the members of X). By using a
pointer conversion B* to A* the pointer is internally adjusted
accordingly. A static_cast is able to reverse this successfully (as
opposed to a reinterpret_cast IIRC). But if you have a void* as
intermediate pointer (which will point to the object's beginning -- in
this case the members of X) and convert it to A* you'll get undefined
behaviour when dereferencing.

Try to use "A*" instead of "void*" or at least make sure that the
source and target pointer type is exactly the same in a pointer
conversion with void* being an intermediate. Of course the latter
approach is error-prone.

Cheers!
SG
 
S

SG

If I have an abstract class A, and class B derives from A,
implementing A's pure virtual methods. What is supposed to happen when
somewhere in the code I reinterpret_cast a void * to a A *, then call
one of the pure virtual methods?
[...]
Try to use "A*" instead of "void*" or at least make sure that the
source and target pointer type is exactly the same in a pointer
conversion with void* being an intermediate.  Of course the latter
approach is error-prone.

....but it still should work w.r.t. to the virtual function call by
which I mean B::your_virtual_function() will be invoked -- assuming
the void* pointer is the result of static_cast<void*>(static_cast<A*>
(&your_b_object)).

Again: Try hard to avoid this.

Cheers!
SG
 
J

James Kanze

If I have an abstract class A, and class B derives from A,
implementing A's pure virtual methods. What is supposed to
happen when somewhere in the code I reinterpret_cast a void *
to a A *, then call one of the pure virtual methods?

First, you don't need (and probably don't want) reinterpret_cast
for this. static_cast is more appropriate. (But in practice,
both will do exactly the same thing.)

Second, it depends on where the void* came from. If it is the
result of converting a valid A* to void* (implicitly or with
static_cast), then there should be no problem. Anything else,
however, is undefined behavior.
It seems to be aborting in my case. I want it to call the
method implemented in class B. Am I doomed to fail at that
endevour?
I have don't think I have a choice but to reinterpret cast,
because MS loves passing around void pointers.

So do a lot of other systems: the operating system doesn't want
to know about your types.

The usual problem in such cases is that your void* comes from a
B*, and not an A*, but it is converted back into an A*. This
occurs a lot with C style call-backs, where the void* is used to
allow the user to pass some data, e.g.:

extern "C" void callback( void* p )
{
static_cast< Base* >( p )->someFunction() ;
}

// ...
Derived handler ;
registerCallback( &callback, &handler ) ;

Since &handler is what gets converted (directly) to void*, and
it is a Derived*, you get undefined behavior. To avoid this,
the last line must be:

registerCallback( &callback, static_cast< Base* >( &handler ) ) ;

Alternatively, if your base class is designed expressedly for
handling such events, you should provide a static function in it
to do the registration---this function will take a Base*, so
there will be an implicit conversion to Base* before the
conversion to void*, and everything will be OK.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

More reinterpret or static cast issues 1
Webview Javascript functions? 1
Virtual destructor 3
cast 1
Non virtual and inheritance 7
Virtual Functions And Inline Definition 13
Virtual functions 3
Virtual functions 0

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top