ポインタが他のクラスにキャスト可能か調べる

なんか dynamic_cast<> のソースを見つけたので、それを改造して作ってみた。

#include <typeinfo.h>

typedef void (*v_table_ptr)();

typedef struct _cpp_object
{
    v_table_ptr*    vtable;
} cpp_object;

typedef struct _rtti_base_descriptor
{
    type_info*      type_descriptor;
    int             num_base_classes;
    int             base_class_offset;
    unsigned int    flags;
    int             unknown1;
    int             unknown2;
} rtti_base_descriptor;

typedef struct _rtti_base_array
{
    const rtti_base_descriptor* bases[3];
} rtti_base_array;

typedef struct _rtti_object_hierachy
{
    int                     unknown1;
    int                     unknown2;
    int                     array_len;
    const rtti_base_array*  base_classes;
} rtti_object_hierachy;

typedef struct _rtti_object_locator
{
    int                         unknown1;
    int                         base_class_offset;
    unsigned int                flags;
    type_info*                  type_descriptor;
    const rtti_object_hierachy* type_hierachy;
} rtti_object_locator;


bool IsCast(void* ptr, const type_info& targetType)
{
    cpp_object* cppobj = (cpp_object*) ptr;
    type_info* dst = (type_info*)&targetType;
    const rtti_object_locator* obj_locator;

    obj_locator = (rtti_object_locator*)cppobj->vtable[-1];

    if (obj_locator)
    {
        int count = 0;
        const rtti_object_hierachy* obj_bases =
            obj_locator->type_hierachy;
        const rtti_base_descriptor* const * base_desc =
            obj_bases->base_classes->bases;
        bool found = false;

        while (count < obj_bases->array_len)
        {
            const type_info* typ = (*base_desc)->type_descriptor;

            if (typ == dst)
            {
                found = true;
                break;
            }
            base_desc++;
            count++;
        }
        return found;
    }

    return false;
}
struct A
{
    virtual ~A() { }
};
struct B : public A { };

int main(int argc, char* argv[])
{
    B b;
    A* pa = &b;
    if (IsCast(pa, typeid(B)))
    {
        B* pb = static_cast<B*>(pb);
        ...
    }
    return 0;
}

何というコンパイラ依存コードw


あ、もちろん仮想テーブルとか RTTI とか無いポインタを渡すとアウトですよ。


そういえば、これだとオフセット値が分かんないから、キャスト可能って返されてキャストするとおかしなことになってしまうっぽい。
ということでちゃんと dynamic_cast<> のコードの通りやって NULL が返されるかどうかを見た方がよさげ。