Re: distinguishing wheter void* ptr points to class A or class B?
On Sep 22, 1:57 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
jacek.dzied...@gmail.com wrote:
I have some legacy C code which expects a pointer to a function to
be evaluated at one point.
Because of the pointer-to-function vs. pointer-to-member
incompatibility, this needs to be a
global function. To aid the passing of some extra data to the
function, it takes an extra
parameter of type void* which is passed uninterpreted to it.
I am in a situation where this void* pointer can point either to
class A or to a class B,
which are not related. Is there a way to perform a reliable cast in
the function or otherwise
distinguish which the void* pointer actually points to? This is
compiled as C++.
I can static_cast<> to whatever, but, obviously, if I get the class
wrong, this segfaults
at the first dereference of a member. dynamic_cast<> does not work on
void*.
Is there a way out? I can modify classes A and B at will and the
function in question, but its signature must remain intact.
As far as I know, once the pointer is converted to void*, type
information is lost. Thus, the classes must take care of the
problem. Unfortunately, you cannot call member function of A
and B without knowing their type first.
Correct. You can, however, pass a pointer to something like:
enum Type { typeA, typeB } ;
struct TypedPtr
{
Type type ;
void* ptr ;
} ;
and go on from there. But...
I wonder (and I am not sure whether it will work) if you could embed a ty=
pe
tag field at the beginning of classes A and B. Like so:
struct A {
int type_tag;
...
};
struct B {
int type_tag;
...
};
The constructors of A and B would set the type_tag to the
right values, and you would cast the void* to int* first in
order to tell whether it is A or B.
One complication is that the standard does not guarantee that
the type_tag comes first unless (a) the classes A and B do not
derive from somewhere and (b) there are no interfering access
specifiers. Probably, there are many more.
Actually, it only guarantees that the address of the type_tag is
the same as the address of the class if the class is a POD. On
the other hand, if you can modify the classes, you can easily
make them both derive from a common base class, which consists
of nothing but a virtual destructor, and pass a pointer to the
common base. After which, dynamic_cast will work. If you can't
modify the classes in question, you can do something similar by
deriving a new class from the original class and the common
base, and passing a pointer to the common base.
Note that if the void* is forced, e.g. because the data is being
passed through a C API, you'll have to be very careful with the
casting. For example:
class ForRTTI
{
public:
virtual ~ForRTTI() {}
} ;
template< typename T >
class DynamicallyTyped : public T, public ForRTTI
{
// ...
} ;
void
handleCallback( void* p )
{
ForRTTI* obj = static_cast< ForRTTI* >( p ) ;
// further code using dynamic_cast, etc...
}
// ...
DynamicallyTyped< C > myC ;
registerCallback( handleCallback, &myC ) ;
will result in undefined behavior; the last line must be:
registerCallback( handleCallback,
static_cast< ForRTTI* >( &myC ) ) ;
(Basically, the void* must be converted back to the exact type
it was created from, or you have undefined behavior.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34