4

Say that I have a void* containing a pointer to an unknown class. I want to use dynamic_cast to do run-time checking on the type of class I actually have. For example:

class Foo {};

void* bar = new Foo;

If I attempt to do dynamic_cast<Foo*>(bar) I get:

'void *': invalid expression type for dynamic_cast

However I need dynamic_cast because in my actual situation I'm not sure that bar is in fact a Foo*.

I've read here that one solution to this is to create a base class for all objects that bar could contain, reinterpret_cast to a pointer to that base class, and then try to dynamic_cast from that object pointer to Foo.

This is difficult for me because the objects that may be stored in bar are not all under my control. (And cause trying to recreate Java gives me heartburn.) Is there another way to do this?

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    Then you're going to need some additional state to tell you what type it is. – James Adkison Oct 27 '15 at 14:13
  • 2
    Design an interface/abstract class and declare bar of that type. – Richard Dally Oct 27 '15 at 14:14
  • @LeFlou Ewww... I don't like the idea of wrappers, but frankly that may be the best answer. If no one has a better suggestion you might want to write that up, cause it's probably the right answer. – Jonathan Mee Oct 27 '15 at 14:16
  • @JamesAdkison A valid suggestion but in my case I believe that it would prove more difficult than [LeFlou's wrappers](http://stackoverflow.com/questions/33370296/run-time-checking-of-a-cast-from-a-void?noredirect=1#comment54535135_33370296) – Jonathan Mee Oct 27 '15 at 14:17
  • 2
    related: http://stackoverflow.com/questions/9099384/how-to-check-if-a-void-pointer-can-be-safely-cast-to-something-else – NathanOliver Oct 27 '15 at 14:17
  • @KarolyHorvath Yeah, [`java.lang.Object`](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html) is the base class for *everything* in Java. – Jonathan Mee Oct 27 '15 at 14:22
  • 1
    Even with adding a base class, I believe `dynamic_cast` solution only works if the pointer is truly pointing something deriving from that base; if you want to insist on that much, you should make your interface take pointers to the base, rather than void pointers! –  Oct 27 '15 at 14:27
  • @JonathanMee If you don't control the objects stored in `bar` how can you guarantee they derive from a particular base class? – James Adkison Oct 27 '15 at 14:29
  • @Hurkyl Right, of course. – Jonathan Mee Oct 27 '15 at 14:32
  • @JamesAdkison I don't control the definitions of the objects stored in `bar`. And I cannot guarantee anything about them, that's why I need `dynamic_cast` to do run-time type checking for me. – Jonathan Mee Oct 27 '15 at 14:34
  • @NathanOliver That was [James Adkison's suggestion](http://stackoverflow.com/questions/33370296/run-time-checking-of-a-cast-from-a-void?noredirect=1#comment54535104_33370296). I don't feel it's as good as the wrapper solution in my case. – Jonathan Mee Oct 27 '15 at 14:45
  • Yes, I know you don't control them that's my point about the suggestion to create an interface suggested by LeFlou (i.e., you cannot guarantee the types derive the interface). – James Adkison Oct 27 '15 at 14:46
  • @JamesAdkison As mentioned [here](http://stackoverflow.com/questions/33370296/run-time-checking-of-a-cast-from-a-void?noredirect=1#comment54535866_33370539) the right way to handle this is to make wrappers for the objects who's implementations I do not control and use those wrappers in my code. (Obviously the wrappers will inherit from the base class.) – Jonathan Mee Oct 27 '15 at 14:58
  • 1
    Okay, that's the disconnect. I thought "the objects that may be stored in bar are not all under my control" meant you didn't even control it at the point of the call (i.e., not only is the class not under your control but the calling point which casts to `void*` was not under your control). If you control the calling point then yes you can guarantee you use the wrapper. – James Adkison Oct 27 '15 at 15:03
  • @JamesAdkison Yeah, unfortunately [LeFlou's answer](http://stackoverflow.com/a/33370539/2642059) does not reflect that. I've asked him to update... we'll see what happens... – Jonathan Mee Oct 27 '15 at 15:53

3 Answers3

1

dynamic_cast is use to cast down a polymorphic object to a class that has the type of the object you're trying to cast as it's parent.

void* is completely different from that. with a pointer to void, you are literally stripping every type information away.

dynamic_cast know that there's a base class and can do type checking through RTTI.

When you cast down a void pointer, you're saying to the compiler: "yeah you know this place in the memory? well, use it as this type" and if the memory is invalid, UB is invoked.

you have three choices here.

Option 1 Use an interface. Well, a polymorphic base class is the only way to do a dynamic_cast. There is no other way, no hacks, it's the only way. Simple as that.

struct Base { virtual ~Base() = default; };

struct Derived : Base {};

// ...

void test (Base* base) {
    auto derived = dynamic_cast<Derived*>(base);

    if (derived) {
        // derived is valid here.
    }
}

Option 2 Identify the type with the pointer I use a method to have a unique identifier per type and use the identifier to validate the cast. Done without any RTTI

using type_id_t = void(*)();
template <typename T> void type_id() {}

// now we can use a map or a vector.
std::vector<std::pair<type_id_t, void*>> vec;

template<typename T>
void insertToMyVector(T* obj) {
    vec.emplace_back(type_id<T>, obj);
}

template<typename T>
T* getObj(int index) {
    auto item = vec[index];

    return static_cast<T*>(item.first == &type_id<T> ? item.second : nullptr);
}

// ...

int main () {
    auto foo = new Foo;

    insertToMyVector(foo);

    auto maybeFoo = getObj<Foo>(0);

    if (maybeFoo) {
        // you have a valid Foo here
    }
}

Option 3 Generate derived class for any type This one is quite useful as it can hold any type while keeping type safety. I look like solution 1 but offer more flexibility. The trick it to generate a derived class for any type using templates. The advantage is you can hold any type, but may complexify you cade a bit.

struct Base { virtual ~Base() = default; };

template<typename T>
struct Derived : Base {
    Derived(T&& obj) : _obj{std::move(obj)} {}
    Derived(const T& obj) : _obj{obj} {}

    T& get() {
        return _obj;
    }

    const T& get() const {
        return _obj;
    }

private:
    T _obj;
};

// ...

void test (Base* base) {
    auto derived = dynamic_cast<Derived<int>*>(base);

    if (derived) {
        int i = derived->get();
        // derived is valid here, and we can safely access the int
    }
}
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • **1** Was suggested in the link in the question, and is not a desirable solution. **2** Was first suggested [here](http://stackoverflow.com/questions/33370296/run-time-checking-of-a-cast-from-a-void?noredirect=1#comment54535104_33370296) but is not a good solution for my problem. **3** Is the solution described [here](http://stackoverflow.com/questions/33370296/run-time-checking-of-a-cast-from-a-void?noredirect=1#comment54537066_33370296) and is the most promising so far. – Jonathan Mee Oct 27 '15 at 16:43
  • **2** Could be improved by using [`type_index`](http://en.cppreference.com/w/cpp/types/type_index) and **3** Could be improved by adding a casting operator instead of `get`: `operator T() { return _obj; }` – Jonathan Mee Oct 27 '15 at 16:52
  • I would rather add `operator*` and `operator->` than conversion operator. Or making the conversion operator explicit – Guillaume Racicot Oct 27 '15 at 17:19
  • Can you help me understand why making the wrapper invisible using a cast operator wouldn't be a good idea? – Jonathan Mee Oct 27 '15 at 17:25
  • 1
    Well, conversion operator would copy the underlying object, and sometimes it is not desirable, especially when dealing with heavy objects. If it were implicit, I would be really easy to create performance/memory issue or unwanted copies. As for `operator*` and `operator->` it does not. If you really want a conversion operator, then making it explicit would reduce the number of mistake and make then easily trackable. – Guillaume Racicot Oct 27 '15 at 17:32
0

To ensure dynamic_cast compiles and works, you should create an abstract or interface class with a virtual method.

#include <cassert>

class Bar
{
public:
    Bar() = default;
     virtual ~Bar() = default;
};

class Foo : public Bar
{
public:
    Foo() = default;
    virtual ~Foo() = default;
};

int main()
{
    Bar* bar = new Foo;
    Foo* foo = dynamic_cast<Foo*>(bar);
    assert(foo != nullptr);
}
Richard Dally
  • 1,432
  • 2
  • 21
  • 38
  • But I think your comment is more than this right? Specifically a `Bar` child needs to be a wrapper for another object. – Jonathan Mee Oct 27 '15 at 14:31
  • This works here but does nothing to solve the problem that the OP has as the OP does not have control of some of the objects passed to his function. So he cannot make them derive from a common object. – NathanOliver Oct 27 '15 at 14:39
0

As I understand it you want a polymorphic object but no common base class.

There is already a fairly standard idiom for this - it's called boost::any.

A boost::any carries your object plus some type information. The interface allows you to query the type and to attempt to cast the any to the type you're looking for.

http://www.boost.org/doc/libs/1_59_0/doc/html/any.html

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • I hate giving +1s to boost answers, but this is the best version so far of: http://stackoverflow.com/questions/33370296/run-time-checking-of-a-cast-from-a-void?noredirect=1#comment54535104_33370296 – Jonathan Mee Oct 27 '15 at 16:54
  • 1
    I hate giving boost answers but why re-invent a perfectly circular wheel? – Richard Hodges Oct 27 '15 at 17:00
  • :) So I can't find any implementation for this but I am very curious how this was accomplished. Is there somewhere I can look over the source for this? – Jonathan Mee Oct 27 '15 at 17:03
  • of course. download the boost source and have a look! Essentially it's accomplished with an inner polymorphic concept who's implementations are templated on the object type passed into the constructor (or assignment operator). The concept supports retrieving the typeid and a pointer to the address of the stored object. – Richard Hodges Oct 27 '15 at 17:26
  • I believer that [`any`](https://en.cppreference.com/w/cpp/utility/any) is now a thing. I believe that accomplishes the portion of `boost::any` that you were referencing. If you could replace this with the standard `any` and give an example, I'd like to accept. – Jonathan Mee Jan 07 '19 at 13:15