How to get the typeid of a void* pointer?
Asked Answered
B

4

12

I have a list of pointers to objects. These objects have nothing in common (i.e. no common base class); for better understanding: It is a list of objects that lie under the mouse cursor in a GUI.

Now I would like to know what kind of object it is. A node, a node handle, a line segment, a tag, and so on. However I cannot use typeid(*ptr) since ptr is a const void*.

Any solution for this? Can I force the usage of typeid since I know that the pointers always point to objects and not to mere values? Or is there no way around adding some fake common base class?

(edit: Currently I'm doing it that way that I store a struct in the list which additionally stores the type of the object (as enum). Maybe I should change this to store a type_info object ...)

Brutish answered 4/7, 2011 at 13:30 Comment(8)
Give them a common base class, and use it. typeid is for polymorphic types, not void*.Godmother
why a fake common base class ? it isn't fake if every objects in the list "is a" ObjectLyingUnderTheMouse, then ObjectLyingUnderTheMouse make sense. if it doesn't, it's bad design, change design. Especially if you mix up the view and the model in your objects.Uam
@Tomalak: why didn't you post your comment as an answer? I think it covers everything the OP asked.Spiffing
@larsm: Wasn't convinced that it's an answer.Godmother
@larsm: perhaps because the question is "how to get the typeid of a void* pointer?", not "please advise me how to redesign my code" ;-)Galasyn
@simon: You are asking for reflection, something C++ does not have. However, your statement 'These objects have nothing in common' is not true. You said so yourself: they are 'objects that lie under the mouse cursor in a GUI'. That these objects have nothing in common in your design and that you need reflection to solve this lack of commonality is a reflection on your design.Amass
@all thanks for your tips. You are right -- I now slightly changed the design and added a common base class.Brutish
boost::variant<> ?Cramfull
S
11

For a technical solution, not considering design level, use a std::map or hash table (whatever) to associate the untyped pointers with type descriptors or typed pointers, of course before the user starts using the mouse.

At a higher level, the void* pointers are just ungood.

It would be best to fix the design instead of employing a kludge like the std::map.

Cheers & hth.

Schematic answered 4/7, 2011 at 13:35 Comment(0)
E
6

You definitely should introduce a polymorphic dummy base class or this purpose. Otherwise, you would need to do a reinterpret_cast/static_cast to another, possibly unrelated pointer type first in order to be able to call dynamic_cast. Since accessing an object with its wrong type is undefined in C++, such a use of dynamic_cast would trigger undefined behaviour.

Technically, RTTI information is typically stored in a field of an object's vtable, so hijacking the binary representation might just work and give you an per-type unique pointer. Please don't do that.

Eldridgeeldritch answered 4/7, 2011 at 13:36 Comment(3)
...ahh.. removed the section I was going to comment about.. :)Propylite
@Nim: Sorry, I was editing, I re-introduced the section after rephrasing it a bit.Eldridgeeldritch
After casting I always got the cast type back from typeid, no matter what object it was before. Strange ... However, I now decided to add a common base class.Brutish
C
2

You should consider using the boost::variant type to hold your raw pointers (before you convert them to void*), and store those in your list instead.

You can then either attempt to retrieve your pointers back directly using the Get member function, or better yet, if you have multiple possible types to deal with at the same point, using the visitor syntax.

Caceres answered 4/7, 2011 at 14:5 Comment(0)
Y
2

Declare and define a new class named "Object":

class Object
{
private: const void *pointer
         const char *type;
public: template <class T> Object(const T *t)
{
    this->pointer = t;
    this->type = typeid(*t).name();
    //NOTE that you must #include <typeinfo.h> in order to use the "typeid" keyword of course!
}
const void* GetPointer()
{
    return this->pointer;
}
const char* GetType()
{
    return this->type;
}
template <class T> const T* GetPointer()
{
    return (T*)this->pointer;
}
template <class T> T& GetReference()
{
    return *(T*)this->pointer;
}
template <class T> T GetValue()
{
    return *(T*)this->pointer;
}
//You also can add some explicit and/or implicit conversions operators if you want by using template class in each
};

Then replace your void* with Object in your list.

Each time you iterate this list, first call the GetType function of the Object class to know the type of the object that the void pointer of this Object points at. GetType returns the name of this type as const char* string.

You can use the strcmp function to help you compare const char* strings.

Then after that you called GetType function, now you know to which type to convert or cast the void pointer of the Object and then do whatever you want with the current iterated object!

Call one of the two overloads of the GetPointer function to retrieve the void pointer of the Object converted / casted or not.

If you just want the reference to the object that the void pointer of the Object points at, then just call the GetReference function instead GetPointer.

Hope if you like my answer!

Yearwood answered 4/5, 2015 at 19:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.