Run-Time Checking of a Cast from a void*

前端 未结 3 1443
不思量自难忘°
不思量自难忘° 2021-01-19 12:21

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 cl

相关标签:
3条回答
  • 2021-01-19 12:46

    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);
    }
    
    0 讨论(0)
  • 2021-01-19 13:04

    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

    0 讨论(0)
  • 2021-01-19 13:10

    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
        }
    }
    
    0 讨论(0)
提交回复
热议问题