Search code examples
c++arrayspointerstype-safetydynamic-cast

dynamic_cast to the same type does not check type of object


I am trying to determine whether an object pointed by a T* pointer is truly a T object, or some other, unrelated type. I tried dynamic_cast, however it is less than useless, it returns the pointer itself instead of null even when it is obvious it does not point to a valid T object:

Object* garbage = reinterpret_cast<Object*>(0x12345678);
if( dynamic_cast<Object*>(garbage) == NULL ){
    cout << "Expected behaviour (by me)" << endl;
}else{
    cout << "You've got to be kidding me" << endl;
}

Is there any workaround for this, or some other solution? I've tried casting to void* and char* before the dynamic_cast to no avail, typeid is not enough either since I want to accept subclasses as well.

Some context: I'm writing a custom Array class implementing shallow conversion between different kinds of Arrays, like Array<Object*> and Array<String*>, and I would like to guarantee a minimal type safety by doing a dynamic type check at every element access, for example:

#define DEBUG
Array<String*> v(10);
Array<Object*> o = v;
o[0] = new Integer(1);      //  this is technically illegal but no idea how to check
//Array<String*> w = o;     //  this fails with an exception
String* str = v[0];         //  but this should fail horribly as well
cout << str << endl;

Casting to Object*, then doing the type check on the Object* works in a lot of cases, but it fails in the case of Array<Object*>, though I am not sure whether it is possible to insert something non-Object into an Array<Object*> without the use of reinterpret_cast.


Solution

  • Base on your example, it sounds like you've got shallow copy Arrays which someone could trick into containing different types than they are supposed to contain. I think the "normal" solution to this problem would be to make that difficult for users to do (i.e. don't provide conversions between Array<T> and Array<U>). But, if you're set in your ideas I think this will work:

    template<typename Subclass>
    class Array {
    public:
        // ...
        Subclass *operator [] (size_t index) {
            assert( index < size_ );
            assert( dynamic_cast<Subclass*>(static_cast<Object*>(internal_[index])) != NULL );
            // ...
        }
        // ...
    private:
        size_t size_;
        Subclass **internal_;
    };
    

    You can do some template meta-magic and a static assert to make sure that Subclass is really a Subclass of Object (exactly how is a completely different topic). Once that is out of the way, casting down to an Object* and then back up to Subclass with a dynamic_cast should accomplish your goal.